package api import ( "fmt" "gardomatic.kleiax.de/internal/platform/validate" "gardomatic.kleiax.de/internal/storage" "net/http" "strings" ) type careInstructionInput struct { Text *string `json:"text"` Status *string `json:"status"` } func (i careInstructionInput) apply(v *storage.CareInstruction) { if i.Text != nil { v.Text = strings.TrimSpace(*i.Text) } if i.Status != nil { v.Status = *i.Status } } func (app *application) validateCareInstruction(w http.ResponseWriter, r *http.Request, item storage.CareInstruction) bool { v := validate.New() storage.ValidateCareInstruction(v, item) if !v.Valid() { app.failedValidationResponse(w, r, v.Errors) return false } return true } func (app *application) listCareInstructionsHandler(w http.ResponseWriter, r *http.Request) { g, _ := app.readGardenIDParam(r) s, e := app.readIDParam(r) if e != nil { app.notFoundResponse(w, r) return } items, e := app.models.CareInstructions.GetAllForSpecies(g, s) if e != nil { app.respondToEntityModelError(w, r, e) return } if e = app.writeJSON(w, http.StatusOK, envelope{"care_instructions": items}, nil); e != nil { app.serverErrorResponse(w, r, e) } } func (app *application) createCareInstructionHandler(w http.ResponseWriter, r *http.Request) { g, _ := app.readGardenIDParam(r) s, e := app.readIDParam(r) if e != nil { app.notFoundResponse(w, r) return } if !app.canWriteCareInstructions(w, r, g, s) { return } var input careInstructionInput if e = app.readJSON(w, r, &input); e != nil { app.badRequestResponse(w, r, e) return } u, _ := app.contextGetAuthenticatedUser(r) item := storage.CareInstruction{SpeciesID: s, Status: "untested", CreatedBy: u.ID, UpdatedBy: u.ID} input.apply(&item) if !app.validateCareInstruction(w, r, item) { return } item, e = app.models.CareInstructions.Insert(item) if e != nil { app.respondToEntityModelError(w, r, e) return } h := make(http.Header) h.Set("Location", fmt.Sprintf("/v1/gardens/%d/species/%d/care-instructions/%d", g, s, item.ID)) _ = app.writeJSON(w, http.StatusCreated, envelope{"care_instruction": item}, h) } func (app *application) updateCareInstructionHandler(w http.ResponseWriter, r *http.Request) { g, _ := app.readGardenIDParam(r) s, e := app.readIDParam(r) if e != nil { app.notFoundResponse(w, r) return } if !app.canWriteCareInstructions(w, r, g, s) { return } id, e := app.readNamedIDParam(r, "instructionID") if e != nil { app.notFoundResponse(w, r) return } item, e := app.models.CareInstructions.Get(g, s, id) if e != nil { app.respondToEntityModelError(w, r, e) return } var input careInstructionInput if e = app.readJSON(w, r, &input); e != nil { app.badRequestResponse(w, r, e) return } input.apply(&item) u, _ := app.contextGetAuthenticatedUser(r) item.UpdatedBy = u.ID if !app.validateCareInstruction(w, r, item) { return } item, e = app.models.CareInstructions.Update(g, item) if e != nil { app.respondToEntityModelError(w, r, e) return } _ = app.writeJSON(w, http.StatusOK, envelope{"care_instruction": item}, nil) } func (app *application) deleteCareInstructionHandler(w http.ResponseWriter, r *http.Request) { g, _ := app.readGardenIDParam(r) s, e := app.readIDParam(r) if e != nil { app.notFoundResponse(w, r) return } if !app.canWriteCareInstructions(w, r, g, s) { return } id, e := app.readNamedIDParam(r, "instructionID") if e != nil { app.notFoundResponse(w, r) return } if e = app.models.CareInstructions.Delete(g, s, id); e != nil { app.respondToEntityModelError(w, r, e) return } w.WriteHeader(http.StatusNoContent) } func (app *application) canWriteCareInstructions(w http.ResponseWriter, r *http.Request, gardenID, speciesID int) bool { species, err := app.models.Species.Get(gardenID, speciesID) if err != nil { app.respondToEntityModelError(w, r, err) return false } member, _ := app.contextGetGardenMember(r) user, _ := app.contextGetAuthenticatedUser(r) if species.GardenID == nil { if !user.Can(storage.ApplicationPermissionGlobalSpeciesWrite) { app.permissionDeniedResponse(w, r) return false } } else if !member.Can(storage.GardenPermissionSpeciesWrite) { app.permissionDeniedResponse(w, r) return false } return true }