296 lines
6.4 KiB
Go
296 lines
6.4 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"
|
|
"encoding/hex"
|
|
)
|
|
|
|
func (app *application) listIssuesHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
var input struct {
|
|
Title string
|
|
data.Filters
|
|
}
|
|
|
|
|
|
v := validator.New()
|
|
|
|
qs := r.URL.Query()
|
|
|
|
|
|
input.Title = app.readString(qs, "title", "")
|
|
// input.Genres = app.readCSV(qs, "genres", []string{})
|
|
|
|
|
|
input.Filters.Page = app.readInt(qs, "page", 1, v)
|
|
input.Filters.PageSize = app.readInt(qs, "page_size", 20, v)
|
|
|
|
|
|
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
|
|
}
|
|
|
|
n, e, private_pem, err := GenerateIssueKey()
|
|
if err != nil {
|
|
app.serverErrorResponse(w, r, err)
|
|
return
|
|
}
|
|
|
|
issue := &data.Issue{
|
|
Title: input.Title,
|
|
Description: input.Description,
|
|
StartTime: input.StartTime,
|
|
EndTime: input.EndTime,
|
|
N: n,
|
|
E: e,
|
|
PrivatePem: private_pem,
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
func (app *application) readIssuePubKeyHandler(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
|
|
}
|
|
|
|
type response struct {
|
|
N string `json:"n"`
|
|
E int `json:"e"`
|
|
}
|
|
|
|
res := response{
|
|
N: hex.EncodeToString(issue.N),
|
|
E: issue.E,
|
|
}
|
|
|
|
|
|
err = app.writeJSON(w, http.StatusOK, envelope{"public_key": res}, nil)
|
|
if err != nil {
|
|
app.serverErrorResponse(w, r, err)
|
|
}
|
|
}
|
|
|
|
func (app *application) blindSignIssueVoteHandler(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
|
|
}
|
|
|
|
type response struct {
|
|
N string `json:"n"`
|
|
E int `json:"e"`
|
|
}
|
|
|
|
res := response{
|
|
N: hex.EncodeToString(issue.N),
|
|
E: issue.E,
|
|
}
|
|
|
|
|
|
err = app.writeJSON(w, http.StatusOK, envelope{"public_key": res}, nil)
|
|
if err != nil {
|
|
app.serverErrorResponse(w, r, err)
|
|
}
|
|
}
|