party/cmd/api/issues.go
2026-04-08 07:51:15 +02:00

222 lines
5.7 KiB
Go

package main
import (
// "encoding/json"
"fmt"
// "html/template"
// "log"
"net/http"
"time"
// "github.com/julienschmidt/httprouter"
// "strconv"
"errors"
"party.at/party/internal/data"
"party.at/party/internal/validator"
)
func (app *application) listIssuesHandler(w http.ResponseWriter, r *http.Request) {
// To keep things consistent with our other handlers, we'll define an input struct
// to hold the expected values from the request query string.
var input struct {
Title string
data.Filters
}
// Initialize a new Validator instance.
v := validator.New()
// Call r.URL.Query() to get the url.Values map containing the query string data.
qs := r.URL.Query()
// Use our helpers to extract the title and genres query string values, falling back
// to defaults of an empty string and an empty slice respectively if they are not
// provided by the client.
input.Title = app.readString(qs, "title", "")
// input.Genres = app.readCSV(qs, "genres", []string{})
// Get the page and page_size query string values as integers. Notice that we set
// the default page value to 1 and default page_size to 20, and that we pass the
// validator instance as the final argument here.
input.Filters.Page = app.readInt(qs, "page", 1, v)
input.Filters.PageSize = app.readInt(qs, "page_size", 20, v)
// Extract the sort query string value, falling back to "id" if it is not provided
// by the client (which will imply a ascending sort on issue ID).
input.Filters.Sort = app.readString(qs, "sort", "id")
input.Filters.SortSafelist = []string{"id", "-id", "title", "-title", "description", "-description"}
if data.ValidateFilters(v, input.Filters); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
issues, metadata, err := app.models.Issues.GetAll(input.Title, input.Filters)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
err = app.writeJSON(w, http.StatusOK, envelope{"issues": issues, "metadata": metadata}, nil)
if err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) createIssueHandler(w http.ResponseWriter, r *http.Request) {
var input struct {
Title string `json:"title"`
Description string `json:"description"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
}
err := app.readJSON(w, r, &input)
if err != nil {
// Use the new badRequestResponse() helper.
app.badRequestResponse(w, r, err)
return
}
issue := &data.Issue{
Title: input.Title,
Description: input.Description,
StartTime: input.StartTime,
EndTime: input.EndTime,
}
v := validator.New()
if data.ValidateIssue(v, issue); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
err = app.models.Issues.Insert(issue)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
headers := make(http.Header)
headers.Set("Location", fmt.Sprintf("/v1/issues/%d", issue.ID))
err = app.writeJSON(w, http.StatusCreated, envelope{"issue": issue}, headers)
if err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) readIssueHandler(w http.ResponseWriter, r *http.Request) {
id, err := app.readIDParam(r)
if err != nil {
app.notFoundResponse(w, r)
return
}
issue, err := app.models.Issues.Get(id)
if err != nil {
switch {
case errors.Is(err, data.ErrRecordNotFound):
app.notFoundResponse(w, r)
default:
app.serverErrorResponse(w, r, err)
}
return
}
// Encode the struct to JSON and send it as the HTTP response.
err = app.writeJSON(w, http.StatusOK, envelope{"issue": issue}, nil)
if err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) updateIssueHandler(w http.ResponseWriter, r *http.Request) {
id, err := app.readIDParam(r)
if err != nil {
app.notFoundResponse(w, r)
return
}
issue, err := app.models.Issues.Get(id)
if err != nil {
switch {
case errors.Is(err, data.ErrRecordNotFound):
app.notFoundResponse(w, r)
default:
app.serverErrorResponse(w, r, err)
}
return
}
var input struct {
Title *string `json:"title"`
Description *string `json:"description"`
StartTime *time.Time `json:"start_time"`
EndTime *time.Time `json:"end_time"`
}
err = app.readJSON(w, r, &input)
if err != nil {
app.badRequestResponse(w, r, err)
return
}
if input.Title != nil { issue.Title = *input.Title }
if input.Description != nil { issue.Description = *input.Description }
if input.StartTime != nil { issue.StartTime = *input.StartTime }
if input.StartTime != nil { issue.EndTime = *input.EndTime }
v := validator.New()
if data.ValidateIssue(v, issue); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
err = app.models.Issues.Update(issue)
if err != nil {
switch {
case errors.Is(err, data.ErrEditConflict):
app.editConflictResponse(w, r)
default:
app.serverErrorResponse(w, r, err)
}
return
}
// Write the updated issue record in a JSON response.
err = app.writeJSON(w, http.StatusOK, envelope{"issue": issue}, nil)
if err != nil {
app.serverErrorResponse(w, r, err)
}
}
func (app *application) deleteIssueHandler(w http.ResponseWriter, r *http.Request) {
id, err := app.readIDParam(r)
if err != nil {
app.notFoundResponse(w, r)
return
}
// Delete the issue from the database, sending a 404 Not Found response to the
// client if there isn't a matching record.
err = app.models.Issues.Delete(id)
if err != nil {
switch {
case errors.Is(err, data.ErrRecordNotFound):
app.notFoundResponse(w, r)
default:
app.serverErrorResponse(w, r, err)
}
return
}
// Return a 200 OK status code along with a success message.
err = app.writeJSON(w, http.StatusOK, envelope{"message": "issue successfully deleted"}, nil)
if err != nil {
app.serverErrorResponse(w, r, err)
}
}