Move voting to a new endpoint

/election/{id}/votes
This commit is contained in:
2025-01-11 18:29:01 +01:00
parent 86d7d0e881
commit cad5cfe636
8 changed files with 186 additions and 100 deletions

View File

@ -11,6 +11,7 @@ import (
"math/rand" "math/rand"
"net/http" "net/http"
"slices" "slices"
"strconv"
"time" "time"
) )
@ -111,8 +112,6 @@ type createVotesRequestWithValidator struct {
} }
func (r *createVotesRequestWithValidator) isValid() bool { func (r *createVotesRequestWithValidator) isValid() bool {
r.CheckField(validator.GreaterThan(r.ElectionId, 0), "electionId", "must be greater than 0")
for _, choice := range r.Choices { for _, choice := range r.Choices {
r.CheckField(validator.NotBlank(choice.ChoiceText), "choiceText", "must not be blank") r.CheckField(validator.NotBlank(choice.ChoiceText), "choiceText", "must not be blank")
} }
@ -133,10 +132,16 @@ func (app *application) createVotes(w http.ResponseWriter, r *http.Request) {
return return
} }
election, err := app.elections.GetById(request.ElectionId) // get from path instead of from the JSON electionID, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
app.clientError(w, http.StatusBadRequest, "Couldn't convert the id you provided to a number")
return
}
election, err := app.elections.GetById(electionID)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
app.unprocessableEntityErrorSingle(w, fmt.Errorf("election with id %v doesn't exist", request.ElectionId)) // TODO: return 404 app.clientError(w, http.StatusNotFound, "Couldn't find an election with the ID you provided")
return return
} }
app.serverError(w, r, err) app.serverError(w, r, err)
@ -145,7 +150,7 @@ func (app *application) createVotes(w http.ResponseWriter, r *http.Request) {
for _, c := range request.Choices { for _, c := range request.Choices {
choiceExists := slices.Contains(election.Choices, c.ChoiceText) choiceExists := slices.Contains(election.Choices, c.ChoiceText)
if !choiceExists { if !choiceExists {
app.unprocessableEntityErrorSingle(w, fmt.Errorf("choice %v doesn't exist", c.ChoiceText)) app.clientError(w, http.StatusUnprocessableEntity, fmt.Sprintf("choice %v doesn't exist", c.ChoiceText))
return return
} }
} }
@ -156,13 +161,13 @@ func (app *application) createVotes(w http.ResponseWriter, r *http.Request) {
} }
if tokensUsed > election.Tokens { if tokensUsed > election.Tokens {
app.unprocessableEntityErrorSingle(w, fmt.Errorf("you used too many tokens; must not exceed %v tokens", election.Tokens)) app.clientError(w, http.StatusUnprocessableEntity, fmt.Sprintf("you used too many tokens; must not exceed %v tokens", election.Tokens))
return return
} }
electionHasExpired := election.ExpiresAt.Before(time.Now()) electionHasExpired := election.ExpiresAt.Before(time.Now())
if electionHasExpired { if electionHasExpired {
app.unprocessableEntityErrorSingle(w, fmt.Errorf("election has expired")) app.clientError(w, http.StatusUnprocessableEntity, "election has expired")
return return
} }
@ -193,9 +198,9 @@ func (app *application) createVotes(w http.ResponseWriter, r *http.Request) {
func (app *application) createVotesHandleKnownVotersElection(w http.ResponseWriter, r *http.Request, request createVotesRequestWithValidator, election *models.Election) (string, error) { func (app *application) createVotesHandleKnownVotersElection(w http.ResponseWriter, r *http.Request, request createVotesRequestWithValidator, election *models.Election) (string, error) {
if request.VoterIdentity == nil || validator.Blank(*request.VoterIdentity) { if request.VoterIdentity == nil || validator.Blank(*request.VoterIdentity) {
err := fmt.Errorf("election has known voters; you must provide an identity provided by the organizer") message := "election has known voters; you must provide an identity provided by the organizer"
app.unprocessableEntityErrorSingle(w, err) app.clientError(w, http.StatusUnprocessableEntity, message)
return "", err return "", fmt.Errorf(message)
} }
voterIdentity := *request.VoterIdentity voterIdentity := *request.VoterIdentity
@ -205,9 +210,9 @@ func (app *application) createVotesHandleKnownVotersElection(w http.ResponseWrit
return "", err return "", err
} }
if hasCastVotes { if hasCastVotes {
err := fmt.Errorf("you already voted") message := "you already voted"
app.unprocessableEntityErrorSingle(w, err) app.clientError(w, http.StatusUnprocessableEntity, message)
return "", err return "", fmt.Errorf(message)
} }
voterExists, err := app.voters.Exists(voterIdentity, election.ID) voterExists, err := app.voters.Exists(voterIdentity, election.ID)
@ -216,9 +221,9 @@ func (app *application) createVotesHandleKnownVotersElection(w http.ResponseWrit
return "", err return "", err
} }
if !voterExists { if !voterExists {
err := fmt.Errorf("invalid voter identity") message := "invalid voter identity"
app.unprocessableEntityErrorSingle(w, err) app.clientError(w, http.StatusUnprocessableEntity, message)
return "", err return "", fmt.Errorf(message)
} }
return voterIdentity, nil return voterIdentity, nil
@ -233,9 +238,9 @@ func (app *application) createVotesHandleUnknownVotersElection(w http.ResponseWr
return "", err return "", err
} }
if voterExists { if voterExists {
err := fmt.Errorf("you already voted") message := "you already voted"
app.unprocessableEntityErrorSingle(w, err) app.clientError(w, http.StatusUnprocessableEntity, message)
return "", err return "", fmt.Errorf(message)
} }
_, err = app.voters.Insert(voterIdentity, election.ID) _, err = app.voters.Insert(voterIdentity, election.ID)
@ -250,9 +255,9 @@ func (app *application) createVotesHandleUnknownVotersElection(w http.ResponseWr
return "", err return "", err
} }
if voterCount == election.MaxVoters { if voterCount == election.MaxVoters {
err := fmt.Errorf("maximum voters reached") message := "maximum voters reached"
app.unprocessableEntityErrorSingle(w, err) app.clientError(w, http.StatusUnprocessableEntity, message)
return "", err return "", fmt.Errorf(message)
} }
return voterIdentity, nil return voterIdentity, nil

View File

@ -254,7 +254,7 @@ func TestCreateVotes_UnknownVotersElection(t *testing.T) {
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything). On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(1, nil) Return(1, nil)
path := "/votes" path := "/election/1/votes"
tests := []struct { tests := []struct {
name string name string
@ -273,7 +273,6 @@ func TestCreateVotes_UnknownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
}, },
expectedCode: http.StatusCreated, expectedCode: http.StatusCreated,
@ -289,7 +288,6 @@ func TestCreateVotes_UnknownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 41}, {ChoiceText: "Buddha", Tokens: 41},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -305,7 +303,6 @@ func TestCreateVotes_UnknownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddh", Tokens: 40}, {ChoiceText: "Buddh", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -362,7 +359,7 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
On("Exists", mock.Anything, mock.Anything). On("Exists", mock.Anything, mock.Anything).
Return(false, nil) Return(false, nil)
path := "/votes" path := "/election/1/votes"
tests := []struct { tests := []struct {
name string name string
@ -381,7 +378,6 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: &EXISTING_VOTER_IDENTITY, VoterIdentity: &EXISTING_VOTER_IDENTITY,
}, },
expectedCode: http.StatusCreated, expectedCode: http.StatusCreated,
@ -397,7 +393,6 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: &NON_EXISTING_VOTER_IDENTITY, VoterIdentity: &NON_EXISTING_VOTER_IDENTITY,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -413,7 +408,6 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -429,7 +423,6 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 41}, {ChoiceText: "Buddha", Tokens: 41},
}, },
ElectionId: 1,
VoterIdentity: &EXISTING_VOTER_IDENTITY, VoterIdentity: &EXISTING_VOTER_IDENTITY,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -445,7 +438,6 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddh", Tokens: 40}, {ChoiceText: "Buddh", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: &EXISTING_VOTER_IDENTITY, VoterIdentity: &EXISTING_VOTER_IDENTITY,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -475,7 +467,7 @@ func TestCreateVotes_NonExistingElection(t *testing.T) {
On("GetById", mock.Anything). On("GetById", mock.Anything).
Return((*models.Election)(nil), sql.ErrNoRows) Return((*models.Election)(nil), sql.ErrNoRows)
path := "/votes" path := "/election/1/votes"
requestBody := api.CreateVotesRequest{ requestBody := api.CreateVotesRequest{
Choices: []struct { Choices: []struct {
ChoiceText string `json:"choiceText"` ChoiceText string `json:"choiceText"`
@ -484,7 +476,6 @@ func TestCreateVotes_NonExistingElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
} }
requestBodyJson, err := json.Marshal(requestBody) requestBodyJson, err := json.Marshal(requestBody)
@ -494,7 +485,38 @@ func TestCreateVotes_NonExistingElection(t *testing.T) {
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson)) code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusUnprocessableEntity, code) assert.Equal(t, http.StatusNotFound, code)
}
func TestCreateVotes_NonNumberElectionID(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return((*models.Election)(nil), sql.ErrNoRows)
path := "/election/1a/votes"
requestBody := api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusBadRequest, code)
} }
func TestCreateVotes_AlreadyVoted(t *testing.T) { func TestCreateVotes_AlreadyVoted(t *testing.T) {
@ -533,7 +555,8 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
On("Exists", mock.Anything, mock.Anything). On("Exists", mock.Anything, mock.Anything).
Return(true, nil) Return(true, nil)
path := "/votes" existingElectionPath := "/election/1/votes"
nonExistingElectionPath := "/election/1/votes"
voterIdentity := "anything" voterIdentity := "anything"
tests := []struct { tests := []struct {
@ -544,7 +567,7 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
}{ }{
{ {
name: "Invalid request for known voters election (already voted)", name: "Invalid request for known voters election (already voted)",
urlPath: path, urlPath: existingElectionPath,
body: api.CreateVotesRequest{ body: api.CreateVotesRequest{
Choices: []struct { Choices: []struct {
ChoiceText string `json:"choiceText"` ChoiceText string `json:"choiceText"`
@ -553,14 +576,13 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: &voterIdentity, VoterIdentity: &voterIdentity,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
}, },
{ {
name: "Invalid request for unknown voters election (already voted)", name: "Invalid request for unknown voters election (already voted)",
urlPath: path, urlPath: nonExistingElectionPath,
body: api.CreateVotesRequest{ body: api.CreateVotesRequest{
Choices: []struct { Choices: []struct {
ChoiceText string `json:"choiceText"` ChoiceText string `json:"choiceText"`
@ -569,7 +591,6 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 2,
VoterIdentity: &voterIdentity, VoterIdentity: &voterIdentity,
}, },
expectedCode: http.StatusUnprocessableEntity, expectedCode: http.StatusUnprocessableEntity,
@ -619,7 +640,7 @@ func TestCreateVotes_UnknownVotersElectionMaxVotersReached(t *testing.T) {
On("CountByElection", mock.Anything). On("CountByElection", mock.Anything).
Return(10, nil) Return(10, nil)
path := "/votes" path := "/election/1/votes"
requestBody := api.CreateVotesRequest{ requestBody := api.CreateVotesRequest{
Choices: []struct { Choices: []struct {
ChoiceText string `json:"choiceText"` ChoiceText string `json:"choiceText"`
@ -628,7 +649,6 @@ func TestCreateVotes_UnknownVotersElectionMaxVotersReached(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
} }
requestBodyJson, err := json.Marshal(requestBody) requestBodyJson, err := json.Marshal(requestBody)
@ -671,7 +691,7 @@ func TestCreateVotes_ExpiredElection(t *testing.T) {
On("CountByElection", mock.Anything). On("CountByElection", mock.Anything).
Return(10, nil) Return(10, nil)
path := "/votes" path := "/election/1/votes"
requestBody := api.CreateVotesRequest{ requestBody := api.CreateVotesRequest{
Choices: []struct { Choices: []struct {
ChoiceText string `json:"choiceText"` ChoiceText string `json:"choiceText"`
@ -680,7 +700,6 @@ func TestCreateVotes_ExpiredElection(t *testing.T) {
{ChoiceText: "Gandhi", Tokens: 60}, {ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40}, {ChoiceText: "Buddha", Tokens: 40},
}, },
ElectionId: 1,
VoterIdentity: nil, VoterIdentity: nil,
} }
requestBodyJson, err := json.Marshal(requestBody) requestBodyJson, err := json.Marshal(requestBody)

View File

@ -22,11 +22,9 @@ func (app *application) serverError(w http.ResponseWriter, r *http.Request, err
func (app *application) clientError(w http.ResponseWriter, status int, message string) { func (app *application) clientError(w http.ResponseWriter, status int, message string) {
w.WriteHeader(status) w.WriteHeader(status)
var response = api.ErrorResponse{ var response = api.ErrorResponse{
Code: http.StatusUnprocessableEntity, Code: status,
Details: &map[string]interface{}{ Details: nil,
"error": message, Message: message,
},
Message: "There was an error in the request",
} }
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
} }
@ -38,16 +36,7 @@ func (app *application) unprocessableEntityError(w http.ResponseWriter, v valida
Details: &map[string]interface{}{ Details: &map[string]interface{}{
"fields": v.FieldErrors, "fields": v.FieldErrors,
}, },
Message: "Election data is invalid", Message: "Request data is invalid",
}
json.NewEncoder(w).Encode(response)
}
func (app *application) unprocessableEntityErrorSingle(w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusUnprocessableEntity)
var response = api.ErrorResponse{
Code: http.StatusUnprocessableEntity,
Message: err.Error(),
} }
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
} }

View File

@ -58,6 +58,46 @@ paths:
schema: schema:
$ref: "#/components/schemas/ErrorResponse" $ref: "#/components/schemas/ErrorResponse"
/election/{id}/votes:
post:
tags:
- vote
summary: Cast your votes for an election
operationId: createVotes
parameters:
- name: id
in: path
required: true
description: The ID of the election
schema:
type: integer
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/CreateVotesRequest"
responses:
200:
description: Votes cast
404:
description: Election not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
422:
description: Unprocessable content
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
500:
description: Server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/election/{id}/results: /election/{id}/results:
get: get:
tags: tags:
@ -90,33 +130,6 @@ paths:
schema: schema:
$ref: "#/components/schemas/ErrorResponse" $ref: "#/components/schemas/ErrorResponse"
/votes:
post:
tags:
- vote
summary: Cast your votes for an election
operationId: createVotes
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/CreateVotesRequest"
responses:
200:
description: Votes cast
422:
description: Unprocessable content
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
500:
description: Server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
components: components:
schemas: schemas:
Election: Election:
@ -266,14 +279,11 @@ components:
CreateVotesRequest: CreateVotesRequest:
type: object type: object
required: required:
- electionId
- choices - choices
properties: properties:
voterIdentity: voterIdentity:
type: string type: string
description: Must be filled if election has known voters description: Must be filled if election has known voters
electionId:
type: integer
choices: choices:
type: array type: array
items: items:

View File

@ -18,7 +18,7 @@ func (app *application) routes() http.Handler {
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("POST /election", app.createElection) mux.HandleFunc("POST /election", app.createElection)
mux.HandleFunc("POST /votes", app.createVotes) mux.HandleFunc("POST /election/{id}/votes", app.createVotes)
standard := alice.New(app.recoverPanic, app.logRequest) standard := alice.New(app.recoverPanic, app.logRequest)
return standard.Then(mux) return standard.Then(mux)

8
go.mod
View File

@ -7,15 +7,18 @@ require (
github.com/golang-migrate/migrate/v4 v4.18.1 github.com/golang-migrate/migrate/v4 v4.18.1
github.com/justinas/alice v1.2.0 github.com/justinas/alice v1.2.0
github.com/mattn/go-sqlite3 v1.14.24 github.com/mattn/go-sqlite3 v1.14.24
github.com/oapi-codegen/runtime v1.1.1
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
) )
require ( require (
github.com/Eun/go-convert v0.0.0-20200421145326-bef6c56666ee // indirect github.com/Eun/go-convert v0.0.0-20200421145326-bef6c56666ee // indirect
github.com/Eun/go-doppelgangerreader v0.0.0-20190911075941-30f1527f16b2 // indirect github.com/Eun/go-doppelgangerreader v0.0.0-20190911075941-30f1527f16b2 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 // indirect github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.5.6 // indirect github.com/google/go-cmp v0.5.6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/color v1.4.2 // indirect github.com/gookit/color v1.4.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
@ -24,8 +27,8 @@ require (
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/lunixbochs/vtclean v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
@ -35,5 +38,6 @@ require (
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
golang.org/x/sys v0.25.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

20
go.sum
View File

@ -7,11 +7,15 @@ github.com/Eun/go-hit v0.5.23/go.mod h1:LCHZ6WSPFDXlTQkFUSLe0VsrOhzzEEzbPzCGc6FY
github.com/Eun/go-testdoc v0.0.1/go.mod h1:uT+GeDi7TpqQx6MBkcfXD9nF15Q8IX+kTNEnUUPbuUo= github.com/Eun/go-testdoc v0.0.1/go.mod h1:uT+GeDi7TpqQx6MBkcfXD9nF15Q8IX+kTNEnUUPbuUo=
github.com/Eun/yaegi-template v1.5.16/go.mod h1:eyFQ1QHbKLNHKpUvdjt8+99ZR1ji7lVVbduSK1M5N/U= github.com/Eun/yaegi-template v1.5.16/go.mod h1:eyFQ1QHbKLNHKpUvdjt8+99ZR1ji7lVVbduSK1M5N/U=
github.com/Eun/yaegi-template v1.5.18/go.mod h1:iVHjge496SWL7hLf1euBZIO40Bk0R38g6lu8iyvpc30= github.com/Eun/yaegi-template v1.5.18/go.mod h1:iVHjge496SWL7hLf1euBZIO40Bk0R38g6lu8iyvpc30=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/aaw/maybe_tls v0.0.0-20160803104303-89c499bcc6aa h1:6yJyU8MlPBB2enGJdPciPlr8P+PC0nhCFHnSHYMirZI= github.com/aaw/maybe_tls v0.0.0-20160803104303-89c499bcc6aa h1:6yJyU8MlPBB2enGJdPciPlr8P+PC0nhCFHnSHYMirZI=
github.com/aaw/maybe_tls v0.0.0-20160803104303-89c499bcc6aa/go.mod h1:I0wzMZvViQzmJjxK+AtfFAnqDCkQV/+r17PO1CCSYnU= github.com/aaw/maybe_tls v0.0.0-20160803104303-89c499bcc6aa/go.mod h1:I0wzMZvViQzmJjxK+AtfFAnqDCkQV/+r17PO1CCSYnU=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 h1:TEBmxO80TM04L8IuMWk77SGL1HomBmKTdzdJLLWznxI= github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 h1:TEBmxO80TM04L8IuMWk77SGL1HomBmKTdzdJLLWznxI=
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA= github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -22,6 +26,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk= github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
@ -39,6 +45,7 @@ github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921i
github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
@ -54,12 +61,14 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
@ -70,9 +79,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
@ -117,6 +129,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -136,8 +149,9 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSm
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -9,6 +9,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"time" "time"
"github.com/oapi-codegen/runtime"
) )
// CreateElectionRequest defines model for CreateElectionRequest. // CreateElectionRequest defines model for CreateElectionRequest.
@ -34,12 +36,14 @@ type CreateVotesRequest struct {
ChoiceText string `json:"choiceText"` ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"` Tokens int `json:"tokens"`
} `json:"choices"` } `json:"choices"`
ElectionId int `json:"electionId"`
// VoterIdentity Must be filled if election has known voters // VoterIdentity Must be filled if election has known voters
VoterIdentity *string `json:"voterIdentity,omitempty"` VoterIdentity *string `json:"voterIdentity,omitempty"`
} }
// ElectionResultsResponse defines model for ElectionResultsResponse.
type ElectionResultsResponse = map[string]interface{}
// ErrorResponse defines model for ErrorResponse. // ErrorResponse defines model for ErrorResponse.
type ErrorResponse struct { type ErrorResponse struct {
// Code Machine-readable error code // Code Machine-readable error code
@ -63,9 +67,12 @@ type ServerInterface interface {
// Create a new election // Create a new election
// (POST /election) // (POST /election)
CreateElection(w http.ResponseWriter, r *http.Request) CreateElection(w http.ResponseWriter, r *http.Request)
// Get the results of an election
// (GET /election/{id}/results)
GetElectionIdResults(w http.ResponseWriter, r *http.Request, id int)
// Cast your votes for an election // Cast your votes for an election
// (POST /votes) // (POST /election/{id}/votes)
CreateVotes(w http.ResponseWriter, r *http.Request) CreateVotes(w http.ResponseWriter, r *http.Request, id int)
} }
// ServerInterfaceWrapper converts contexts to parameters. // ServerInterfaceWrapper converts contexts to parameters.
@ -92,12 +99,49 @@ func (siw *ServerInterfaceWrapper) CreateElection(w http.ResponseWriter, r *http
handler.ServeHTTP(w, r.WithContext(ctx)) handler.ServeHTTP(w, r.WithContext(ctx))
} }
// GetElectionIdResults operation middleware
func (siw *ServerInterfaceWrapper) GetElectionIdResults(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
// ------------- Path parameter "id" -------------
var id int
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
}
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetElectionIdResults(w, r, id)
}))
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler.ServeHTTP(w, r.WithContext(ctx))
}
// CreateVotes operation middleware // CreateVotes operation middleware
func (siw *ServerInterfaceWrapper) CreateVotes(w http.ResponseWriter, r *http.Request) { func (siw *ServerInterfaceWrapper) CreateVotes(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
var err error
// ------------- Path parameter "id" -------------
var id int
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
}
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.CreateVotes(w, r) siw.Handler.CreateVotes(w, r, id)
})) }))
for _, middleware := range siw.HandlerMiddlewares { for _, middleware := range siw.HandlerMiddlewares {
@ -222,7 +266,8 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
} }
m.HandleFunc("POST "+options.BaseURL+"/election", wrapper.CreateElection) m.HandleFunc("POST "+options.BaseURL+"/election", wrapper.CreateElection)
m.HandleFunc("POST "+options.BaseURL+"/votes", wrapper.CreateVotes) m.HandleFunc("GET "+options.BaseURL+"/election/{id}/results", wrapper.GetElectionIdResults)
m.HandleFunc("POST "+options.BaseURL+"/election/{id}/votes", wrapper.CreateVotes)
return m return m
} }