Insert election with uuid instead of auto-generated id
This commit is contained in:
@ -145,7 +145,7 @@ func (r *createVotesRequestWithValidator) isValid() bool {
|
|||||||
return r.Valid()
|
return r.Valid()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) CreateVotes(w http.ResponseWriter, r *http.Request, id int) {
|
func (app *application) CreateVotes(w http.ResponseWriter, r *http.Request, id string) {
|
||||||
var request createVotesRequestWithValidator
|
var request createVotesRequestWithValidator
|
||||||
|
|
||||||
if err := app.unmarshalRequest(r, &request); err != nil {
|
if err := app.unmarshalRequest(r, &request); err != nil {
|
||||||
@ -284,7 +284,7 @@ func (app *application) createVotesHandleUnknownVotersElection(w http.ResponseWr
|
|||||||
return voterIdentity, nil
|
return voterIdentity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) GetElectionResults(w http.ResponseWriter, r *http.Request, id int) {
|
func (app *application) GetElectionResults(w http.ResponseWriter, r *http.Request, id string) {
|
||||||
votes, err := app.votes.GetByElection(id)
|
votes, err := app.votes.GetByElection(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(sql.ErrNoRows, err) {
|
if errors.Is(sql.ErrNoRows, err) {
|
||||||
@ -325,7 +325,7 @@ func getResultsFromVotes(votes *[]models.Vote) []api.VotesForChoice {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) GetElection(w http.ResponseWriter, r *http.Request, id int) {
|
func (app *application) GetElection(w http.ResponseWriter, r *http.Request, id string) {
|
||||||
election, err := app.elections.GetById(id)
|
election, err := app.elections.GetById(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(sql.ErrNoRows, err) {
|
if errors.Is(sql.ErrNoRows, err) {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -21,10 +22,11 @@ func TestCreateElection(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
id, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||||
Return(1, nil)
|
Return(id.String(), nil)
|
||||||
|
|
||||||
path := baseUri + "election"
|
path := baseUri + "election"
|
||||||
|
|
||||||
@ -197,10 +199,11 @@ func TestCreateElection_KnownVoters(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
electionId, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||||
Return(1, nil)
|
Return(electionId.String(), nil)
|
||||||
|
|
||||||
mockVoters := app.voters.(*mockVoterModel)
|
mockVoters := app.voters.(*mockVoterModel)
|
||||||
mockVoters.
|
mockVoters.
|
||||||
@ -270,11 +273,12 @@ func TestCreateVotes_UnknownVotersElection(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
id, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", mock.Anything).
|
On("GetById", mock.Anything).
|
||||||
Return(&models.Election{
|
Return(&models.Election{
|
||||||
ID: 1,
|
ID: id.String(),
|
||||||
Name: "Guy of the year",
|
Name: "Guy of the year",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: false,
|
AreVotersKnown: false,
|
||||||
@ -373,11 +377,12 @@ func TestCreateVotes_KnownVotersElection(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
id, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", mock.Anything).
|
On("GetById", mock.Anything).
|
||||||
Return(&models.Election{
|
Return(&models.Election{
|
||||||
ID: 1,
|
ID: id.String(),
|
||||||
Name: "Guy of the year",
|
Name: "Guy of the year",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: true,
|
AreVotersKnown: true,
|
||||||
@ -534,7 +539,7 @@ func TestCreateVotes_NonExistingElection(t *testing.T) {
|
|||||||
assert.Equal(t, http.StatusNotFound, code)
|
assert.Equal(t, http.StatusNotFound, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateVotes_NonNumberElectionID(t *testing.T) {
|
func TestCreateVotes_NonUuidElectionID(t *testing.T) {
|
||||||
app := newTestApplication(t)
|
app := newTestApplication(t)
|
||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
@ -562,7 +567,7 @@ func TestCreateVotes_NonNumberElectionID(t *testing.T) {
|
|||||||
|
|
||||||
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
|
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
|
||||||
|
|
||||||
assert.Equal(t, http.StatusBadRequest, code)
|
assert.Equal(t, http.StatusNotFound, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateVotes_AlreadyVoted(t *testing.T) {
|
func TestCreateVotes_AlreadyVoted(t *testing.T) {
|
||||||
@ -570,8 +575,9 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
unknownVotersElectionId, _ := uuid.NewV7()
|
||||||
unknownVotersElection := models.Election{
|
unknownVotersElection := models.Election{
|
||||||
ID: 1,
|
ID: unknownVotersElectionId.String(),
|
||||||
Name: "Guy of the year",
|
Name: "Guy of the year",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: false,
|
AreVotersKnown: false,
|
||||||
@ -580,15 +586,18 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
|
|||||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||||
Choices: []string{"Gandhi", "Buddha"},
|
Choices: []string{"Gandhi", "Buddha"},
|
||||||
}
|
}
|
||||||
|
|
||||||
knownVotersElection := unknownVotersElection
|
knownVotersElection := unknownVotersElection
|
||||||
|
knownVotersElectionId, _ := uuid.NewV7()
|
||||||
|
knownVotersElection.ID = knownVotersElectionId.String()
|
||||||
knownVotersElection.AreVotersKnown = true
|
knownVotersElection.AreVotersKnown = true
|
||||||
|
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", 1).
|
On("GetById", knownVotersElectionId.String()).
|
||||||
Return(&knownVotersElection, nil)
|
Return(&knownVotersElection, nil)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", 2).
|
On("GetById", unknownVotersElectionId.String()).
|
||||||
Return(&unknownVotersElection, nil)
|
Return(&unknownVotersElection, nil)
|
||||||
|
|
||||||
mockVotes := app.votes.(*mockVoteModel)
|
mockVotes := app.votes.(*mockVoteModel)
|
||||||
@ -601,8 +610,9 @@ func TestCreateVotes_AlreadyVoted(t *testing.T) {
|
|||||||
On("Exists", mock.Anything, mock.Anything).
|
On("Exists", mock.Anything, mock.Anything).
|
||||||
Return(true, nil)
|
Return(true, nil)
|
||||||
|
|
||||||
knownVotersElectionPath := baseUri + "election/1/votes"
|
layout := baseUri + "election/%v/votes"
|
||||||
unknownVotersElectionPath := baseUri + "election/2/votes"
|
knownVotersElectionPath := fmt.Sprintf(layout, unknownVotersElectionId)
|
||||||
|
unknownVotersElectionPath := fmt.Sprintf(layout, knownVotersElectionId)
|
||||||
voterIdentity := "anything"
|
voterIdentity := "anything"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -661,11 +671,12 @@ func TestCreateVotes_UnknownVotersElectionMaxVotersReached(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
id, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", mock.Anything).
|
On("GetById", mock.Anything).
|
||||||
Return(&models.Election{
|
Return(&models.Election{
|
||||||
ID: 1,
|
ID: id.String(),
|
||||||
Name: "Guy of the year",
|
Name: "Guy of the year",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: false,
|
AreVotersKnown: false,
|
||||||
@ -712,11 +723,12 @@ func TestCreateVotes_ExpiredElection(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
id, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", mock.Anything).
|
On("GetById", mock.Anything).
|
||||||
Return(&models.Election{
|
Return(&models.Election{
|
||||||
ID: 1,
|
ID: id.String(),
|
||||||
Name: "Guy of the year",
|
Name: "Guy of the year",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: false,
|
AreVotersKnown: false,
|
||||||
@ -763,38 +775,39 @@ func TestGetElectionResults(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
electionID, _ := uuid.NewV7()
|
||||||
votes := []models.Vote{
|
votes := []models.Vote{
|
||||||
{
|
{
|
||||||
VoterIdentity: "Voter1",
|
VoterIdentity: "Voter1",
|
||||||
ElectionID: 1,
|
ElectionID: electionID.String(),
|
||||||
ChoiceText: "Choice1",
|
ChoiceText: "Choice1",
|
||||||
Tokens: 2,
|
Tokens: 2,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
VoterIdentity: "Voter2",
|
VoterIdentity: "Voter2",
|
||||||
ElectionID: 1,
|
ElectionID: electionID.String(),
|
||||||
ChoiceText: "Choice2",
|
ChoiceText: "Choice2",
|
||||||
Tokens: 4,
|
Tokens: 4,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
VoterIdentity: "Voter3",
|
VoterIdentity: "Voter3",
|
||||||
ElectionID: 1,
|
ElectionID: electionID.String(),
|
||||||
ChoiceText: "Choice3",
|
ChoiceText: "Choice3",
|
||||||
Tokens: 6,
|
Tokens: 6,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
VoterIdentity: "Voter4",
|
VoterIdentity: "Voter4",
|
||||||
ElectionID: 1,
|
ElectionID: electionID.String(),
|
||||||
ChoiceText: "Choice1",
|
ChoiceText: "Choice1",
|
||||||
Tokens: 8,
|
Tokens: 8,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
VoterIdentity: "Voter5",
|
VoterIdentity: "Voter5",
|
||||||
ElectionID: 1,
|
ElectionID: electionID.String(),
|
||||||
ChoiceText: "Choice2",
|
ChoiceText: "Choice2",
|
||||||
Tokens: 10,
|
Tokens: 10,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
@ -802,10 +815,10 @@ func TestGetElectionResults(t *testing.T) {
|
|||||||
}
|
}
|
||||||
mockVotes := app.votes.(*mockVoteModel)
|
mockVotes := app.votes.(*mockVoteModel)
|
||||||
mockVotes.
|
mockVotes.
|
||||||
On("GetByElection", mock.Anything).
|
On("GetByElection", electionID.String()).
|
||||||
Return(&votes, nil)
|
Return(&votes, nil)
|
||||||
|
|
||||||
path := baseUri + "election/1/results"
|
path := baseUri + fmt.Sprintf("election/%v/results", electionID)
|
||||||
code, _, body := server.get(t, path)
|
code, _, body := server.get(t, path)
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, code)
|
assert.Equal(t, http.StatusOK, code)
|
||||||
@ -857,11 +870,12 @@ func TestGetElection_Found(t *testing.T) {
|
|||||||
server := newTestServer(t, app.routes())
|
server := newTestServer(t, app.routes())
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
id, _ := uuid.NewV7()
|
||||||
mockElections := app.elections.(*mockElectionModel)
|
mockElections := app.elections.(*mockElectionModel)
|
||||||
mockElections.
|
mockElections.
|
||||||
On("GetById", mock.Anything).
|
On("GetById", mock.Anything).
|
||||||
Return(&models.Election{
|
Return(&models.Election{
|
||||||
ID: 1,
|
ID: id.String(),
|
||||||
Name: "Guy of the year",
|
Name: "Guy of the year",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: false,
|
AreVotersKnown: false,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
//go:build !integration
|
|
||||||
|
|
||||||
//go:generate oapi-codegen --config=oapi-codegen.yml openapi.yml
|
//go:generate oapi-codegen --config=oapi-codegen.yml openapi.yml
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
@ -1,281 +0,0 @@
|
|||||||
//go:build integration
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"code.dlmw.ch/dlmw/qv/internal/migrations"
|
|
||||||
"code.dlmw.ch/dlmw/qv/internal/models"
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
. "github.com/Eun/go-hit"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var addr = ":8080"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
|
||||||
|
|
||||||
err := os.Remove("./qv.integration.sqlite")
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("couldn't delete qv.integration.sqlite")
|
|
||||||
}
|
|
||||||
db, err := openDb()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
err = migrations.Run(db)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
app := &application{
|
|
||||||
logger: logger,
|
|
||||||
elections: &models.ElectionModel{DB: db},
|
|
||||||
voters: &models.VoterModel{DB: db},
|
|
||||||
votes: &models.VoteModel{DB: db},
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("Starting integration tests server", "addr", addr)
|
|
||||||
|
|
||||||
srv := &http.Server{
|
|
||||||
Addr: addr,
|
|
||||||
Handler: app.routes(),
|
|
||||||
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
|
||||||
IdleTimeout: time.Minute,
|
|
||||||
ReadTimeout: 5 * time.Second,
|
|
||||||
WriteTimeout: 10 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
logger.Info("Starting integration test server", "addr", addr)
|
|
||||||
|
|
||||||
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
logger.Error("Server error", "error", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
time.Sleep(1 * time.Second) // wait until srv starts
|
|
||||||
runTests()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
srv.Shutdown(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func openDb() (*sql.DB, error) {
|
|
||||||
db, err := sql.Open("sqlite3", "./qv.integration.sqlite?_foreign_keys=on")
|
|
||||||
if err == nil {
|
|
||||||
err = db.Ping()
|
|
||||||
}
|
|
||||||
|
|
||||||
return db, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func runTests() {
|
|
||||||
runCreateElectionTests()
|
|
||||||
runCreateVotesTests()
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCreateElectionTests() {
|
|
||||||
template := CombineSteps(
|
|
||||||
Post("http://127.0.0.1:8080/api/election"),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
template,
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": false,
|
|
||||||
"maxVoters": 10,
|
|
||||||
"expiresAt": "2124-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi",
|
|
||||||
"Buddha"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusOK),
|
|
||||||
Expect().Headers("Location").Contains("/election/1"),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
template,
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": false,
|
|
||||||
"maxVoters": 0,
|
|
||||||
"expiresAt": "2124-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi",
|
|
||||||
"Buddha"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusOK),
|
|
||||||
Expect().Headers("Location").Contains("/election/2"),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
template,
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": true,
|
|
||||||
"maxVoters": 10,
|
|
||||||
"expiresAt": "2124-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi",
|
|
||||||
"Buddha"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusOK),
|
|
||||||
Expect().Headers("Location").Contains("/election/3"),
|
|
||||||
Expect().Body().JSON().JQ(".voterIdentities").Len().Equal(10),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
template,
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": true,
|
|
||||||
"maxVoters": -1,
|
|
||||||
"expiresAt": "2124-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi",
|
|
||||||
"Buddha"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusUnprocessableEntity),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
template,
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": false,
|
|
||||||
"maxVoters": -1,
|
|
||||||
"expiresAt": "2124-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusUnprocessableEntity),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
template,
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": false,
|
|
||||||
"maxVoters": 10,
|
|
||||||
"expiresAt": "2018-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi",
|
|
||||||
"Buddha"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusUnprocessableEntity),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCreateVotesTests() {
|
|
||||||
uri := "http://127.0.0.1:8080/api/election/%v/votes"
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
Post(fmt.Sprintf(uri, "1")),
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"choiceText": "Buddha",
|
|
||||||
"tokens": 90
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"choiceText": "Gandhi",
|
|
||||||
"tokens": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusCreated),
|
|
||||||
)
|
|
||||||
|
|
||||||
MustDo(
|
|
||||||
Post(fmt.Sprintf(uri, "3")),
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"choiceText": "Buddha",
|
|
||||||
"tokens": 90
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"choiceText": "Gandhi",
|
|
||||||
"tokens": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusUnprocessableEntity),
|
|
||||||
)
|
|
||||||
|
|
||||||
voterIdentities := make([]string, 0)
|
|
||||||
locationHeader := ""
|
|
||||||
MustDo(
|
|
||||||
Post("http://127.0.0.1:8080/api/election"),
|
|
||||||
Send().Body().String(`
|
|
||||||
{
|
|
||||||
"name": "Guy of the year",
|
|
||||||
"tokens": 100,
|
|
||||||
"areVotersKnown": true,
|
|
||||||
"maxVoters": 10,
|
|
||||||
"expiresAt": "2124-12-31T14:15:22Z",
|
|
||||||
"choices": [
|
|
||||||
"Gandhi",
|
|
||||||
"Buddha"
|
|
||||||
]
|
|
||||||
}`),
|
|
||||||
Expect().Status().Equal(http.StatusOK),
|
|
||||||
Store().Response().Body().JSON().JQ(".voterIdentities").In(&voterIdentities),
|
|
||||||
Store().Response().Headers("Location").In(&locationHeader),
|
|
||||||
)
|
|
||||||
|
|
||||||
electionId := strings.Split(locationHeader, "/")[2]
|
|
||||||
MustDo(
|
|
||||||
Post(fmt.Sprintf(uri, electionId)),
|
|
||||||
Send().Body().String(fmt.Sprintf(`
|
|
||||||
{
|
|
||||||
"voterIdentity": "%v",
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"choiceText": "Buddha",
|
|
||||||
"tokens": 90
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"choiceText": "Gandhi",
|
|
||||||
"tokens": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`, voterIdentities[0])),
|
|
||||||
Expect().Status().Equal(http.StatusCreated),
|
|
||||||
)
|
|
||||||
}
|
|
@ -34,7 +34,7 @@ paths:
|
|||||||
required: true
|
required: true
|
||||||
description: The ID of the election
|
description: The ID of the election
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: string
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Election returned
|
description: Election returned
|
||||||
@ -102,7 +102,7 @@ paths:
|
|||||||
required: true
|
required: true
|
||||||
description: The ID of the election
|
description: The ID of the election
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: string
|
||||||
requestBody:
|
requestBody:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
@ -148,7 +148,7 @@ paths:
|
|||||||
required: true
|
required: true
|
||||||
description: The ID of the election
|
description: The ID of the election
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: string
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Election results returned
|
description: Election results returned
|
||||||
@ -190,7 +190,7 @@ components:
|
|||||||
- choices
|
- choices
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
tokens:
|
tokens:
|
||||||
|
@ -65,12 +65,12 @@ type mockElectionModel struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *mockElectionModel) Insert(name string, tokens int, areVotersKnown bool, maxVoters int, choices []string, expiresAt time.Time) (int, error) {
|
func (e *mockElectionModel) Insert(name string, tokens int, areVotersKnown bool, maxVoters int, choices []string, expiresAt time.Time) (string, error) {
|
||||||
args := e.Called(name, tokens, areVotersKnown, maxVoters, choices, expiresAt)
|
args := e.Called(name, tokens, areVotersKnown, maxVoters, choices, expiresAt)
|
||||||
return args.Int(0), args.Error(1)
|
return args.String(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *mockElectionModel) GetById(id int) (*models.Election, error) {
|
func (e *mockElectionModel) GetById(id string) (*models.Election, error) {
|
||||||
args := e.Called(id)
|
args := e.Called(id)
|
||||||
return args.Get(0).(*models.Election), args.Error(1)
|
return args.Get(0).(*models.Election), args.Error(1)
|
||||||
}
|
}
|
||||||
@ -79,17 +79,17 @@ type mockVoterModel struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockVoterModel) InsertMultiple(identities []string, electionID int) ([]int, error) {
|
func (v *mockVoterModel) InsertMultiple(identities []string, electionID string) ([]int, error) {
|
||||||
args := v.Called(identities, electionID)
|
args := v.Called(identities, electionID)
|
||||||
return args.Get(0).([]int), args.Error(1)
|
return args.Get(0).([]int), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockVoterModel) CountByElection(electionID int) (int, error) {
|
func (v *mockVoterModel) CountByElection(electionID string) (int, error) {
|
||||||
args := v.Called(electionID)
|
args := v.Called(electionID)
|
||||||
return args.Int(0), args.Error(1)
|
return args.Int(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockVoterModel) Exists(voterIdentity string, electionID int) (bool, error) {
|
func (v *mockVoterModel) Exists(voterIdentity string, electionID string) (bool, error) {
|
||||||
args := v.Called(voterIdentity, electionID)
|
args := v.Called(voterIdentity, electionID)
|
||||||
return args.Bool(0), args.Error(1)
|
return args.Bool(0), args.Error(1)
|
||||||
}
|
}
|
||||||
@ -98,17 +98,17 @@ type mockVoteModel struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockVoteModel) Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error) {
|
func (v *mockVoteModel) Insert(voterIdentity string, electionId string, choiceText string, tokens int) (int, error) {
|
||||||
args := v.Called(voterIdentity, electionId, choiceText, tokens)
|
args := v.Called(voterIdentity, electionId, choiceText, tokens)
|
||||||
return args.Int(0), args.Error(1)
|
return args.Int(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockVoteModel) Exists(voterIdentity string, electionID int) (bool, error) {
|
func (v *mockVoteModel) Exists(voterIdentity string, electionID string) (bool, error) {
|
||||||
args := v.Called(voterIdentity, electionID)
|
args := v.Called(voterIdentity, electionID)
|
||||||
return args.Bool(0), args.Error(1)
|
return args.Bool(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockVoteModel) GetByElection(electionID int) (*[]models.Vote, error) {
|
func (v *mockVoteModel) GetByElection(electionID string) (*[]models.Vote, error) {
|
||||||
args := v.Called(electionID)
|
args := v.Called(electionID)
|
||||||
return args.Get(0).(*[]models.Vote), args.Error(1)
|
return args.Get(0).(*[]models.Vote), args.Error(1)
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ type Election struct {
|
|||||||
Choices []string `json:"choices"`
|
Choices []string `json:"choices"`
|
||||||
CreatedAt string `json:"createdAt"`
|
CreatedAt string `json:"createdAt"`
|
||||||
ExpiresAt string `json:"expiresAt"`
|
ExpiresAt string `json:"expiresAt"`
|
||||||
Id int `json:"id"`
|
Id string `json:"id"`
|
||||||
MaxVoters int `json:"maxVoters"`
|
MaxVoters int `json:"maxVoters"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Tokens int `json:"tokens"`
|
Tokens int `json:"tokens"`
|
||||||
@ -89,13 +89,13 @@ type ServerInterface interface {
|
|||||||
CreateElection(w http.ResponseWriter, r *http.Request)
|
CreateElection(w http.ResponseWriter, r *http.Request)
|
||||||
// Get an election
|
// Get an election
|
||||||
// (GET /election/{id})
|
// (GET /election/{id})
|
||||||
GetElection(w http.ResponseWriter, r *http.Request, id int)
|
GetElection(w http.ResponseWriter, r *http.Request, id string)
|
||||||
// Get the results of an election
|
// Get the results of an election
|
||||||
// (GET /election/{id}/results)
|
// (GET /election/{id}/results)
|
||||||
GetElectionResults(w http.ResponseWriter, r *http.Request, id int)
|
GetElectionResults(w http.ResponseWriter, r *http.Request, id string)
|
||||||
// Cast your votes for an election
|
// Cast your votes for an election
|
||||||
// (POST /election/{id}/votes)
|
// (POST /election/{id}/votes)
|
||||||
CreateVotes(w http.ResponseWriter, r *http.Request, id int)
|
CreateVotes(w http.ResponseWriter, r *http.Request, id string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerInterfaceWrapper converts contexts to parameters.
|
// ServerInterfaceWrapper converts contexts to parameters.
|
||||||
@ -129,7 +129,7 @@ func (siw *ServerInterfaceWrapper) GetElection(w http.ResponseWriter, r *http.Re
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
// ------------- Path parameter "id" -------------
|
// ------------- Path parameter "id" -------------
|
||||||
var id int
|
var id string
|
||||||
|
|
||||||
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,7 +155,7 @@ func (siw *ServerInterfaceWrapper) GetElectionResults(w http.ResponseWriter, r *
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
// ------------- Path parameter "id" -------------
|
// ------------- Path parameter "id" -------------
|
||||||
var id int
|
var id string
|
||||||
|
|
||||||
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -181,7 +181,7 @@ func (siw *ServerInterfaceWrapper) CreateVotes(w http.ResponseWriter, r *http.Re
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
// ------------- Path parameter "id" -------------
|
// ------------- Path parameter "id" -------------
|
||||||
var id int
|
var id string
|
||||||
|
|
||||||
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,6 +2,7 @@ package mappers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"code.dlmw.ch/dlmw/qv/internal/models"
|
"code.dlmw.ch/dlmw/qv/internal/models"
|
||||||
|
uuid2 "github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -19,8 +20,9 @@ func TestElectionResponse(t *testing.T) {
|
|||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uuid, _ := uuid2.NewV7()
|
||||||
election := models.Election{
|
election := models.Election{
|
||||||
ID: 15,
|
ID: uuid.String(),
|
||||||
Name: "The best",
|
Name: "The best",
|
||||||
Tokens: 100,
|
Tokens: 100,
|
||||||
AreVotersKnown: true,
|
AreVotersKnown: true,
|
||||||
@ -32,7 +34,7 @@ func TestElectionResponse(t *testing.T) {
|
|||||||
|
|
||||||
response := ElectionResponse(&election)
|
response := ElectionResponse(&election)
|
||||||
|
|
||||||
assert.Equal(t, 15, response.Id)
|
assert.Equal(t, uuid.String(), response.Id)
|
||||||
assert.Equal(t, "The best", response.Name)
|
assert.Equal(t, "The best", response.Name)
|
||||||
assert.Equal(t, 100, response.Tokens)
|
assert.Equal(t, 100, response.Tokens)
|
||||||
assert.Equal(t, true, response.AreVotersKnown)
|
assert.Equal(t, true, response.AreVotersKnown)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CREATE TABLE elections (
|
CREATE TABLE elections (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT, -- TODO: try to generate a UUID
|
id TEXT PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
tokens INTEGER NOT NULL,
|
tokens INTEGER NOT NULL,
|
||||||
are_voters_known INTEGER NOT NULL,
|
are_voters_known INTEGER NOT NULL,
|
||||||
|
@ -2,12 +2,13 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"github.com/google/uuid"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ElectionModelInterface interface {
|
type ElectionModelInterface interface {
|
||||||
Insert(name string, tokens int, areVotersKnown bool, maxVoters int, Choices []string, ExpiresAt time.Time) (int, error)
|
Insert(name string, tokens int, areVotersKnown bool, maxVoters int, Choices []string, ExpiresAt time.Time) (string, error)
|
||||||
GetById(id int) (*Election, error)
|
GetById(id string) (*Election, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ElectionModel struct {
|
type ElectionModel struct {
|
||||||
@ -15,7 +16,7 @@ type ElectionModel struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Election struct {
|
type Election struct {
|
||||||
ID int
|
ID string
|
||||||
Name string
|
Name string
|
||||||
Tokens int
|
Tokens int
|
||||||
AreVotersKnown bool
|
AreVotersKnown bool
|
||||||
@ -25,48 +26,48 @@ type Election struct {
|
|||||||
Choices []string
|
Choices []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ElectionModel) Insert(name string, tokens int, areVotersKnown bool, maxVoters int, choices []string, expiresAt time.Time) (int, error) {
|
func (e *ElectionModel) Insert(name string, tokens int, areVotersKnown bool, maxVoters int, choices []string, expiresAt time.Time) (string, error) {
|
||||||
tx, err := e.DB.Begin()
|
tx, err := e.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", err
|
||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
result, err := tx.Exec(`
|
electionID, err := uuid.NewV7()
|
||||||
INSERT INTO elections (name, tokens, are_voters_known, max_voters, expires_at)
|
|
||||||
VALUES (?, ?, ?, ?, ?)`, name, tokens, areVotersKnown, maxVoters, expiresAt)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
electionID, err := result.LastInsertId()
|
_, err = tx.Exec(`
|
||||||
|
INSERT INTO elections (id, name, tokens, are_voters_known, max_voters, expires_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)`, electionID, name, tokens, areVotersKnown, maxVoters, expiresAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt, err := tx.Prepare(`
|
stmt, err := tx.Prepare(`
|
||||||
INSERT INTO choices (text, election_id)
|
INSERT INTO choices (text, election_id)
|
||||||
VALUES (?, ?)`)
|
VALUES (?, ?)`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", err
|
||||||
}
|
}
|
||||||
defer stmt.Close()
|
defer stmt.Close()
|
||||||
|
|
||||||
for _, choice := range choices {
|
for _, choice := range choices {
|
||||||
_, err = stmt.Exec(choice, electionID)
|
_, err = stmt.Exec(choice, electionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = tx.Commit(); err != nil {
|
if err = tx.Commit(); err != nil {
|
||||||
return 0, err
|
return "0", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(electionID), nil
|
return electionID.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ElectionModel) GetById(id int) (*Election, error) {
|
func (e *ElectionModel) GetById(id string) (*Election, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, name, tokens, are_voters_known, max_voters, created_at, expires_at
|
SELECT id, name, tokens, are_voters_known, max_voters, created_at, expires_at
|
||||||
FROM elections
|
FROM elections
|
||||||
|
@ -6,16 +6,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type VoterModelInterface interface {
|
type VoterModelInterface interface {
|
||||||
InsertMultiple(identities []string, electionID int) ([]int, error)
|
InsertMultiple(identities []string, electionID string) ([]int, error)
|
||||||
CountByElection(electionID int) (int, error)
|
CountByElection(electionID string) (int, error)
|
||||||
Exists(voterIdentity string, electionID int) (bool, error)
|
Exists(voterIdentity string, electionID string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type VoterModel struct {
|
type VoterModel struct {
|
||||||
DB *sql.DB
|
DB *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoterModel) InsertMultiple(identities []string, electionID int) ([]int, error) {
|
func (v *VoterModel) InsertMultiple(identities []string, electionID string) ([]int, error) {
|
||||||
tx, err := v.DB.Begin()
|
tx, err := v.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -53,7 +53,7 @@ func (v *VoterModel) InsertMultiple(identities []string, electionID int) ([]int,
|
|||||||
return voterIDs, nil
|
return voterIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoterModel) CountByElection(electionID int) (int, error) {
|
func (v *VoterModel) CountByElection(electionID string) (int, error) {
|
||||||
// use a transaction to prevent race conditions
|
// use a transaction to prevent race conditions
|
||||||
tx, err := v.DB.Begin()
|
tx, err := v.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -82,7 +82,7 @@ func (v *VoterModel) CountByElection(electionID int) (int, error) {
|
|||||||
return voterCount, nil
|
return voterCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoterModel) Exists(voterIdentity string, electionID int) (bool, error) {
|
func (v *VoterModel) Exists(voterIdentity string, electionID string) (bool, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT EXISTS (
|
SELECT EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type VoteModelInterface interface {
|
type VoteModelInterface interface {
|
||||||
Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error)
|
Insert(voterIdentity string, electionId string, choiceText string, tokens int) (int, error)
|
||||||
Exists(voterIdentity string, electionID int) (bool, error)
|
Exists(voterIdentity string, electionID string) (bool, error)
|
||||||
GetByElection(electionID int) (*[]Vote, error)
|
GetByElection(electionID string) (*[]Vote, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type VoteModel struct {
|
type VoteModel struct {
|
||||||
@ -18,13 +18,13 @@ type VoteModel struct {
|
|||||||
|
|
||||||
type Vote struct {
|
type Vote struct {
|
||||||
VoterIdentity string
|
VoterIdentity string
|
||||||
ElectionID int
|
ElectionID string
|
||||||
ChoiceText string
|
ChoiceText string
|
||||||
Tokens int
|
Tokens int
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoteModel) Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error) {
|
func (v *VoteModel) Insert(voterIdentity string, electionId string, choiceText string, tokens int) (int, error) {
|
||||||
tx, err := v.DB.Begin()
|
tx, err := v.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -47,7 +47,7 @@ func (v *VoteModel) Insert(voterIdentity string, electionId int, choiceText stri
|
|||||||
return int(voteId), nil
|
return int(voteId), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoteModel) Exists(voterIdentity string, electionID int) (bool, error) {
|
func (v *VoteModel) Exists(voterIdentity string, electionID string) (bool, error) {
|
||||||
var exists bool
|
var exists bool
|
||||||
query := `
|
query := `
|
||||||
SELECT EXISTS (
|
SELECT EXISTS (
|
||||||
@ -66,7 +66,7 @@ func (v *VoteModel) Exists(voterIdentity string, electionID int) (bool, error) {
|
|||||||
return exists, nil
|
return exists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoteModel) GetByElection(electionID int) (*[]Vote, error) {
|
func (v *VoteModel) GetByElection(electionID string) (*[]Vote, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT voter_identity, election_id, choice_text, tokens, created_at
|
SELECT voter_identity, election_id, choice_text, tokens, created_at
|
||||||
FROM votes
|
FROM votes
|
||||||
|
@ -93,7 +93,7 @@
|
|||||||
<template x-if="createdElectionId > 0">
|
<template x-if="createdElectionId > 0">
|
||||||
<div class="mt-6 bg-green-100 p-4 rounded-md">
|
<div class="mt-6 bg-green-100 p-4 rounded-md">
|
||||||
<h2 class="text-green-700 font-bold">Election Created Successfully</h2>
|
<h2 class="text-green-700 font-bold">Election Created Successfully</h2>
|
||||||
<p class="mt-2">Election ID: <span class="font-mono" x-text="createdElectionId"></span></p>
|
<p class="mt-2">Election ID: <span class="font-mono" x-text="createdElectionId"></span></p> <!-- TODO: link to created election -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user