Initial commit
CI / test (push) Canceled after 0s

This commit is contained in:
2026-09-12 22:22:17 +02:00
commit 904d14b64c
314 changed files with 31884 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
package web
import (
"errors"
"net/http"
"strings"
"gardomatic.kleiax.de/lib/client"
)
type inviteForm struct {
CSRFToken string `form:"csrf_token"`
Email string `form:"email"`
Role string `form:"role"`
Errors map[string]string
}
func (app *application) gardenMembers(w http.ResponseWriter, r *http.Request) {
gardenID, err := app.readPathID(r, "gardenID")
if err != nil {
app.notFound(w)
return
}
http.Redirect(w, r, webPath("garden.edit", gardenID), http.StatusSeeOther)
}
func (app *application) gardenInvitePost(w http.ResponseWriter, r *http.Request) {
gardenID, err := app.readPathID(r, "gardenID")
if err != nil {
app.notFound(w)
return
}
var form inviteForm
if err = app.decodePostForm(r, &form); err != nil {
app.clientError(w, http.StatusBadRequest)
return
}
form.Email, form.Role, form.Errors = strings.TrimSpace(form.Email), strings.TrimSpace(form.Role), map[string]string{}
_, _, err = client.FromContext(r.Context()).CreateGardenInvite(r.Context(), gardenID, client.GardenInviteInput{Email: form.Email, Role: form.Role})
if err != nil {
var apiError *client.APIError
if errors.As(err, &apiError) && apiError.StatusCode == http.StatusUnprocessableEntity {
form.Errors = apiError.Validation
} else {
app.handleAPIError(w, r, err)
return
}
}
if len(form.Errors) == 0 {
http.Redirect(w, r, webPath("garden.edit", gardenID), http.StatusSeeOther)
return
}
app.renderGardenEdit(w, r, gardenID, http.StatusUnprocessableEntity, gardenEditForms{Invite: form})
}
type roleForm struct {
CSRFToken string `form:"csrf_token"`
Role string `form:"role"`
}
func (app *application) gardenMemberRolePost(w http.ResponseWriter, r *http.Request) {
gardenID, err := app.readPathID(r, "gardenID")
if err != nil {
app.notFound(w)
return
}
userID, err := app.readPathID(r, "userID")
if err != nil {
app.notFound(w)
return
}
var form roleForm
if err = app.decodePostForm(r, &form); err != nil {
app.clientError(w, http.StatusBadRequest)
return
}
if _, _, err = client.FromContext(r.Context()).UpdateGardenMember(r.Context(), gardenID, userID, form.Role); err != nil {
app.handleAPIError(w, r, err)
return
}
http.Redirect(w, r, webPath("garden.edit", gardenID), http.StatusSeeOther)
}
func (app *application) gardenMemberDeletePost(w http.ResponseWriter, r *http.Request) {
gardenID, err := app.readPathID(r, "gardenID")
if err != nil {
app.notFound(w)
return
}
userID, err := app.readPathID(r, "userID")
if err != nil {
app.notFound(w)
return
}
if _, err = client.FromContext(r.Context()).DeleteGardenMember(r.Context(), gardenID, userID); err != nil {
app.handleAPIError(w, r, err)
return
}
http.Redirect(w, r, webPath("garden.edit", gardenID), http.StatusSeeOther)
}
func (app *application) gardenOwnershipPost(w http.ResponseWriter, r *http.Request) {
gardenID, err := app.readPathID(r, "gardenID")
if err != nil {
app.notFound(w)
return
}
userID, err := app.readPathID(r, "userID")
if err != nil {
app.notFound(w)
return
}
if _, err = client.FromContext(r.Context()).TransferGardenOwnership(r.Context(), gardenID, userID); err != nil {
app.handleAPIError(w, r, err)
return
}
http.Redirect(w, r, webPath("garden.edit", gardenID), http.StatusSeeOther)
}
func (app *application) gardenInviteDeletePost(w http.ResponseWriter, r *http.Request) {
gardenID, err := app.readPathID(r, "gardenID")
if err != nil {
app.notFound(w)
return
}
inviteID, err := app.readPathID(r, "inviteID")
if err != nil {
app.notFound(w)
return
}
if _, err = client.FromContext(r.Context()).DeleteGardenInvite(r.Context(), gardenID, inviteID); err != nil {
app.handleAPIError(w, r, err)
return
}
http.Redirect(w, r, webPath("garden.edit", gardenID), http.StatusSeeOther)
}
type acceptInviteForm struct {
CSRFToken string `form:"csrf_token"`
Token string `form:"token"`
}
func (app *application) acceptInvite(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r)
data.Form = acceptInviteForm{Token: r.URL.Query().Get("token")}
app.render(w, http.StatusOK, "invite.tmpl", data)
}
func (app *application) acceptInvitePost(w http.ResponseWriter, r *http.Request) {
var form acceptInviteForm
if err := app.decodePostForm(r, &form); err != nil {
app.clientError(w, http.StatusBadRequest)
return
}
member, _, err := client.FromContext(r.Context()).AcceptGardenInvite(r.Context(), form.Token)
if err != nil {
app.handleAPIError(w, r, err)
return
}
http.Redirect(w, r, webPath("plants", member.GardenID), http.StatusSeeOther)
}