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) } }