260 lines
8.2 KiB
Go
260 lines
8.2 KiB
Go
package web
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"gardomatic.kleiax.de/lib/client"
|
|
)
|
|
|
|
type gardenForm struct {
|
|
CSRFToken string `form:"csrf_token"`
|
|
Name string `form:"name"`
|
|
Description string `form:"description"`
|
|
ImageData string `form:"image_data"`
|
|
ImageID int `form:"image_id"`
|
|
Errors map[string]string
|
|
}
|
|
|
|
type gardenEditForms struct {
|
|
Garden gardenForm
|
|
Invite inviteForm
|
|
}
|
|
|
|
type gardenRoleSettingsForm struct {
|
|
Name string `form:"name"`
|
|
Permissions []string `form:"permissions"`
|
|
}
|
|
|
|
func (app *application) gardens(w http.ResponseWriter, r *http.Request) {
|
|
apiClient := client.FromContext(r.Context())
|
|
gardens, _, err := apiClient.Gardens(r.Context())
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
if r.URL.Query().Get("auto") == "1" && len(gardens) == 1 {
|
|
http.Redirect(w, r, webPath("garden.dashboard", gardens[0].ID), http.StatusSeeOther)
|
|
return
|
|
}
|
|
data := app.newTemplateData(r)
|
|
data.Filters = collectionFilters(r, "q", "role", "sort")
|
|
data.Gardens = filterAndSortGardens(gardens, data.Filters)
|
|
data.Gardens, data.Pagination = paginateCollection(r, data.Gardens)
|
|
app.render(w, http.StatusOK, "gardens.tmpl", data)
|
|
}
|
|
|
|
func (app *application) gardenCreate(w http.ResponseWriter, r *http.Request) {
|
|
data := app.newTemplateData(r)
|
|
data.Form = gardenForm{Errors: make(map[string]string)}
|
|
app.render(w, http.StatusOK, "garden_new.tmpl", data)
|
|
}
|
|
|
|
func (app *application) gardenCreatePost(w http.ResponseWriter, r *http.Request) {
|
|
var form gardenForm
|
|
if err := app.decodePostForm(r, &form); err != nil {
|
|
app.clientError(w, http.StatusBadRequest)
|
|
return
|
|
}
|
|
form.Name = strings.TrimSpace(form.Name)
|
|
form.Description = strings.TrimSpace(form.Description)
|
|
form.Errors = make(map[string]string)
|
|
if form.Name == "" {
|
|
form.Errors["name"] = "Ein Name ist erforderlich."
|
|
}
|
|
apiClient := client.FromContext(r.Context())
|
|
if len(form.Errors) == 0 {
|
|
input := client.CreateGardenInput{Name: form.Name, Description: form.Description, ImageData: form.ImageData}
|
|
if form.ImageID > 0 {
|
|
imageID := form.ImageID
|
|
input.ImageID = &imageID
|
|
}
|
|
garden, _, err := apiClient.CreateGarden(r.Context(), input)
|
|
if err == nil {
|
|
http.Redirect(w, r, webPath("plants", garden.ID), http.StatusSeeOther)
|
|
return
|
|
}
|
|
var apiError *client.APIError
|
|
if errors.As(err, &apiError) && apiError.StatusCode == http.StatusUnprocessableEntity {
|
|
form.Errors = apiError.Validation
|
|
} else {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
}
|
|
data := app.newTemplateData(r)
|
|
data.Form = form
|
|
app.render(w, http.StatusUnprocessableEntity, "garden_new.tmpl", data)
|
|
}
|
|
|
|
func (app *application) gardenEdit(w http.ResponseWriter, r *http.Request) {
|
|
gardenID, err := app.readPathID(r, "gardenID")
|
|
if err != nil {
|
|
app.notFound(w)
|
|
return
|
|
}
|
|
app.renderGardenEdit(w, r, gardenID, http.StatusOK, gardenEditForms{})
|
|
}
|
|
|
|
func (app *application) gardenEditPost(w http.ResponseWriter, r *http.Request) {
|
|
gardenID, err := app.readPathID(r, "gardenID")
|
|
if err != nil {
|
|
app.notFound(w)
|
|
return
|
|
}
|
|
var form gardenForm
|
|
if err := app.decodePostForm(r, &form); err != nil {
|
|
app.clientError(w, http.StatusBadRequest)
|
|
return
|
|
}
|
|
form.Name, form.Description, form.Errors = strings.TrimSpace(form.Name), strings.TrimSpace(form.Description), map[string]string{}
|
|
if form.Name == "" {
|
|
form.Errors["name"] = "Ein Name ist erforderlich."
|
|
}
|
|
apiClient := client.FromContext(r.Context())
|
|
if len(form.Errors) == 0 {
|
|
name, description, imageData := form.Name, form.Description, form.ImageData
|
|
input := client.UpdateGardenInput{Name: &name, Description: &description, ImageData: &imageData}
|
|
if form.ImageID > 0 {
|
|
imageID := form.ImageID
|
|
input.ImageID = &imageID
|
|
}
|
|
_, _, updateErr := apiClient.UpdateGarden(r.Context(), gardenID, input)
|
|
if updateErr == nil {
|
|
http.Redirect(w, r, webPath("gardens"), http.StatusSeeOther)
|
|
return
|
|
}
|
|
var apiError *client.APIError
|
|
if errors.As(updateErr, &apiError) && apiError.StatusCode == http.StatusUnprocessableEntity {
|
|
form.Errors = apiError.Validation
|
|
} else {
|
|
app.handleAPIError(w, r, updateErr)
|
|
return
|
|
}
|
|
}
|
|
app.renderGardenEdit(w, r, gardenID, http.StatusUnprocessableEntity, gardenEditForms{Garden: form})
|
|
}
|
|
|
|
func (app *application) gardenDeletePost(w http.ResponseWriter, r *http.Request) {
|
|
gardenID, err := app.readPathID(r, "gardenID")
|
|
if err != nil {
|
|
app.notFound(w)
|
|
return
|
|
}
|
|
if _, err = client.FromContext(r.Context()).DeleteGarden(r.Context(), gardenID); err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
http.Redirect(w, r, webPath("gardens"), http.StatusSeeOther)
|
|
}
|
|
|
|
func (app *application) gardenRoleSettingsPost(w http.ResponseWriter, r *http.Request) {
|
|
gardenID, err := app.readPathID(r, "gardenID")
|
|
if err != nil {
|
|
app.notFound(w)
|
|
return
|
|
}
|
|
var form gardenRoleSettingsForm
|
|
if err = app.decodePostForm(r, &form); err != nil {
|
|
app.clientError(w, http.StatusBadRequest)
|
|
return
|
|
}
|
|
if _, _, err = client.FromContext(r.Context()).UpdateGardenRoleSettings(r.Context(), gardenID, form.Name, form.Permissions); err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
http.Redirect(w, r, webPath("garden.edit", gardenID)+"#garden-role-editor", http.StatusSeeOther)
|
|
}
|
|
|
|
func (app *application) gardenRoleCreatePost(w http.ResponseWriter, r *http.Request) {
|
|
gardenID, err := app.readPathID(r, "gardenID")
|
|
if err != nil {
|
|
app.notFound(w)
|
|
return
|
|
}
|
|
var form roleSettingsForm
|
|
if err = app.decodePostForm(r, &form); err != nil {
|
|
app.clientError(w, http.StatusBadRequest)
|
|
return
|
|
}
|
|
_, _, err = client.FromContext(r.Context()).CreateGardenRole(r.Context(), gardenID, client.RoleInput{Name: strings.TrimSpace(form.Name), Label: strings.TrimSpace(form.Label), Permissions: form.Permissions})
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
http.Redirect(w, r, webPath("garden.edit", gardenID)+"#garden-role-editor", http.StatusSeeOther)
|
|
}
|
|
|
|
func (app *application) gardenRoleDeletePost(w http.ResponseWriter, r *http.Request) {
|
|
gardenID, err := app.readPathID(r, "gardenID")
|
|
if err != nil {
|
|
app.notFound(w)
|
|
return
|
|
}
|
|
var form roleSettingsForm
|
|
if err = app.decodePostForm(r, &form); err != nil {
|
|
app.clientError(w, http.StatusBadRequest)
|
|
return
|
|
}
|
|
if _, err = client.FromContext(r.Context()).DeleteGardenRole(r.Context(), gardenID, form.Name); err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
http.Redirect(w, r, webPath("garden.edit", gardenID)+"#garden-role-editor", http.StatusSeeOther)
|
|
}
|
|
|
|
func (app *application) renderGardenEdit(w http.ResponseWriter, r *http.Request, gardenID, status int, forms gardenEditForms) {
|
|
apiClient := client.FromContext(r.Context())
|
|
garden, _, err := apiClient.Garden(r.Context(), gardenID)
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
if forms.Garden.Errors == nil {
|
|
forms.Garden = gardenForm{Name: garden.Name, Description: garden.Description, ImageData: garden.ImageData, Errors: map[string]string{}}
|
|
if garden.ImageID != nil {
|
|
forms.Garden.ImageID = *garden.ImageID
|
|
}
|
|
}
|
|
if forms.Invite.Errors == nil {
|
|
forms.Invite = inviteForm{Role: "member", Errors: map[string]string{}}
|
|
}
|
|
members, _, err := apiClient.GardenMembers(r.Context(), gardenID)
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
invites := []client.GardenInvite{}
|
|
roleSettings := []client.GardenRoleSetting{}
|
|
gardenRoles := []client.Role{}
|
|
if garden.Can("members:write") {
|
|
invites, _, err = apiClient.GardenInvites(r.Context(), gardenID)
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
roleSettings, _, err = apiClient.GardenRoleSettings(r.Context(), gardenID)
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
for _, setting := range roleSettings {
|
|
gardenRoles = append(gardenRoles, setting.Role)
|
|
}
|
|
}
|
|
data := app.newTemplateData(r)
|
|
data.Garden, data.Members, data.Invites, data.Form = &garden, members, invites, forms
|
|
data.GardenRoles, data.GardenRoleSettings = gardenRoles, roleSettings
|
|
data.GardenPermissions = gardenPermissionOptions()
|
|
if garden.Can("garden:delete") {
|
|
data.RoleEditors = []roleEditorData{gardenOverrideRoleEditor(gardenID, roleSettings, data.GardenPermissions, data.CSRFToken)}
|
|
}
|
|
data.Images, err = app.loadImageLibrary(r, gardenID)
|
|
if err != nil {
|
|
app.handleAPIError(w, r, err)
|
|
return
|
|
}
|
|
app.render(w, status, "garden_form.tmpl", data)
|
|
}
|