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