Files
kleiax 904d14b64c
CI / test (push) Canceled after 0s
Initial commit
2026-09-12 22:22:17 +02:00

188 lines
5.5 KiB
Go

package api
import (
"errors"
"fmt"
"net/http"
"strings"
"gardomatic.kleiax.de/internal/platform/validate"
"gardomatic.kleiax.de/internal/storage"
)
func (app *application) createGardenHandler(w http.ResponseWriter, r *http.Request) {
var input struct {
Name string `json:"name"`
Description string `json:"description"`
ImageData string `json:"image_data"`
ImageID *int `json:"image_id"`
}
if err := app.readJSON(w, r, &input); err != nil {
app.badRequestResponse(w, r, err)
return
}
user, _ := app.contextGetAuthenticatedUser(r)
garden := storage.Garden{
Name: strings.TrimSpace(input.Name),
Description: strings.TrimSpace(input.Description),
ImageData: input.ImageData,
}
v := validate.New()
validateImageData(v, garden.ImageData)
if storage.ValidateGarden(v, garden); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
garden, err := app.models.Gardens.Insert(garden, user.ID)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
if input.ImageData != "" || input.ImageID != nil {
garden.ImageID, err = app.resolveImage(garden.ID, input.ImageData, input.ImageID, user.ID, "garden")
if err != nil {
app.badRequestResponse(w, r, err)
return
}
garden.ImageData = ""
garden, err = app.models.Gardens.Update(garden)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
}
garden.Role = storage.GardenRoleOwner
garden.Permissions = storage.GardenRoleOwner.Permissions()
headers := make(http.Header)
headers.Set("Location", fmt.Sprintf("/v1/gardens/%d", garden.ID))
if err := app.writeJSON(w, http.StatusCreated, envelope{"garden": garden}, headers); err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) listGardensHandler(w http.ResponseWriter, r *http.Request) {
user, _ := app.contextGetAuthenticatedUser(r)
gardens, err := app.models.Gardens.GetAllForUser(user.ID)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
for i := range gardens {
member, memberErr := app.models.GardenMembers.Get(gardens[i].ID, user.ID)
if memberErr != nil {
app.serverErrorResponse(w, r, memberErr)
return
}
applyGardenMembership(&gardens[i], member)
}
if err := app.writeJSON(w, http.StatusOK, envelope{"gardens": gardens}, nil); err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) showGardenHandler(w http.ResponseWriter, r *http.Request) {
gardenID, _ := app.readGardenIDParam(r)
garden, err := app.models.Gardens.Get(gardenID)
if err != nil {
app.respondToGardenModelError(w, r, err)
return
}
member, _ := app.contextGetGardenMember(r)
applyGardenMembership(&garden, member)
if err := app.writeJSON(w, http.StatusOK, envelope{"garden": garden}, nil); err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) updateGardenHandler(w http.ResponseWriter, r *http.Request) {
gardenID, _ := app.readGardenIDParam(r)
garden, err := app.models.Gardens.Get(gardenID)
if err != nil {
app.respondToGardenModelError(w, r, err)
return
}
member, _ := app.contextGetGardenMember(r)
applyGardenMembership(&garden, member)
var input struct {
Name *string `json:"name"`
Description *string `json:"description"`
ImageData *string `json:"image_data"`
ImageID *int `json:"image_id"`
}
if err := app.readJSON(w, r, &input); err != nil {
app.badRequestResponse(w, r, err)
return
}
if input.Name != nil {
garden.Name = strings.TrimSpace(*input.Name)
}
if input.Description != nil {
garden.Description = strings.TrimSpace(*input.Description)
}
previousImageID := garden.ImageID
previousImageData := garden.ImageData
if input.ImageData != nil {
garden.ImageData = *input.ImageData
}
v := validate.New()
validateImageData(v, garden.ImageData)
if storage.ValidateGarden(v, garden); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
user, _ := app.contextGetAuthenticatedUser(r)
if input.ImageData != nil && *input.ImageData != previousImageData {
garden.ImageID, err = app.resolveImage(gardenID, *input.ImageData, input.ImageID, user.ID, "garden")
if err != nil {
app.badRequestResponse(w, r, err)
return
}
}
garden.ImageData = ""
garden, err = app.models.Gardens.Update(garden)
if err != nil {
app.respondToGardenModelError(w, r, err)
return
}
if err = app.recordImageAssignment(storage.ImageAssignment{GardenID: gardenID, EntityType: "garden", EntityID: garden.ID, PreviousImageID: previousImageID, ImageID: garden.ImageID, ChangedBy: user.ID}); err != nil {
app.serverErrorResponse(w, r, err)
return
}
if err := app.writeJSON(w, http.StatusOK, envelope{"garden": garden}, nil); err != nil {
app.serverErrorResponse(w, r, err)
}
}
func applyGardenMembership(garden *storage.Garden, member storage.GardenMember) {
garden.Role = member.Role
garden.Permissions = member.Permissions
if garden.Permissions == nil {
garden.Permissions = member.Role.Permissions()
}
}
func (app *application) deleteGardenHandler(w http.ResponseWriter, r *http.Request) {
gardenID, _ := app.readGardenIDParam(r)
if err := app.models.Gardens.Delete(gardenID); err != nil {
app.respondToGardenModelError(w, r, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
func (app *application) respondToGardenModelError(w http.ResponseWriter, r *http.Request, err error) {
switch {
case errors.Is(err, storage.ErrRecordNotFound):
app.notFoundResponse(w, r)
case errors.Is(err, storage.ErrEditConflict):
app.editConflictResponse(w, r)
default:
app.serverErrorResponse(w, r, err)
}
}