2024-12-27 18:03:46 +01:00
|
|
|
package main
|
|
|
|
|
2024-12-28 17:13:22 +01:00
|
|
|
import (
|
|
|
|
api "code.dlmw.ch/dlmw/qv/internal"
|
|
|
|
"code.dlmw.ch/dlmw/qv/internal/validator"
|
2024-12-30 23:01:32 +01:00
|
|
|
"encoding/json"
|
|
|
|
"math/rand"
|
2024-12-28 17:13:22 +01:00
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type createElectionRequestWithValidator struct {
|
|
|
|
api.CreateElectionRequest
|
|
|
|
validator.Validator
|
|
|
|
}
|
2024-12-27 18:03:46 +01:00
|
|
|
|
|
|
|
func (app *application) createElection(w http.ResponseWriter, r *http.Request) {
|
2024-12-28 17:13:22 +01:00
|
|
|
var request createElectionRequestWithValidator
|
2024-12-30 23:13:39 +01:00
|
|
|
|
|
|
|
if err := app.unmarshalRequest(r, &request); err != nil {
|
2024-12-28 17:13:22 +01:00
|
|
|
app.clientError(w, http.StatusBadRequest, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-12-30 23:13:39 +01:00
|
|
|
if !isRequestValid(&request) {
|
2024-12-28 17:13:22 +01:00
|
|
|
app.unprocessableEntityError(w, request.Validator)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-12-30 23:13:39 +01:00
|
|
|
electionId, err := app.elections.Insert(
|
|
|
|
request.Name,
|
|
|
|
request.Tokens,
|
|
|
|
request.AreVotersKnown,
|
|
|
|
request.MaxVoters,
|
|
|
|
request.Choices,
|
|
|
|
request.ExpiresAt,
|
|
|
|
)
|
2024-12-30 20:41:28 +01:00
|
|
|
if err != nil {
|
|
|
|
app.serverError(w, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-12-30 23:01:32 +01:00
|
|
|
var res []byte
|
|
|
|
if request.AreVotersKnown {
|
|
|
|
voterIdentities := make([]string, 0, request.MaxVoters)
|
|
|
|
for i := 0; i < request.MaxVoters; i++ {
|
|
|
|
randomIdentity := generateRandomVoterIdentity()
|
|
|
|
_, err := app.voters.Insert(randomIdentity, electionId)
|
|
|
|
if err != nil {
|
|
|
|
app.serverError(w, r, err)
|
|
|
|
}
|
|
|
|
voterIdentities = append(voterIdentities, randomIdentity)
|
|
|
|
}
|
2024-12-30 20:41:28 +01:00
|
|
|
|
2024-12-30 23:01:32 +01:00
|
|
|
res, err = json.Marshal(api.CreateElectionResponse{VoterIdentities: &voterIdentities})
|
|
|
|
if err != nil {
|
|
|
|
app.serverError(w, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Write(res)
|
|
|
|
}
|
|
|
|
|
2024-12-30 23:13:39 +01:00
|
|
|
func isRequestValid(r *createElectionRequestWithValidator) bool {
|
|
|
|
r.CheckField(validator.NotBlank(r.Name), "name", "must not be blank")
|
|
|
|
r.CheckField(validator.GreaterThan(r.Tokens, 0), "tokens", "must be greater than 0")
|
|
|
|
r.CheckField(validator.After(r.ExpiresAt, time.Now()), "expiresAt", "must expire in a future date")
|
|
|
|
r.CheckField(validator.GreaterThan(len(r.Choices), 1), "choices", "there must be more than 1 choice")
|
|
|
|
|
|
|
|
r.CheckField(
|
|
|
|
!(r.AreVotersKnown && r.MaxVoters < 1),
|
|
|
|
"maxVoters",
|
|
|
|
"must be greater than 0 when voters are known",
|
|
|
|
)
|
|
|
|
|
|
|
|
return r.Valid()
|
|
|
|
}
|
|
|
|
|
2024-12-30 23:01:32 +01:00
|
|
|
func generateRandomVoterIdentity() string {
|
|
|
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
|
|
b := make([]byte, 16)
|
|
|
|
for i := range b {
|
|
|
|
b[i] = charset[rand.Intn(len(charset))]
|
|
|
|
}
|
|
|
|
return string(b)
|
2024-12-27 18:03:46 +01:00
|
|
|
}
|