188 lines
5.5 KiB
Go
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)
|
|
}
|
|
}
|