Skip to content

Commit

Permalink
api: endpoint /elections can now filter startDate and endDate
Browse files Browse the repository at this point in the history
this includes a refactor of parseElectionParams since the args list went wild
  • Loading branch information
altergui committed Aug 9, 2024
1 parent fb5d43a commit 3ac33c5
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 81 deletions.
26 changes: 10 additions & 16 deletions api/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,16 +355,10 @@ func (a *API) accountCountHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContex
// @Success 200 {object} ElectionsList
// @Router /accounts/{organizationId}/elections/page/{page} [get]
func (a *API) accountElectionsListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
params, err := parseElectionParams(
ctx.URLParam(ParamPage),
"",
"",
ctx.URLParam(ParamOrganizationId),
"",
"",
"",
"",
)
params, err := electionParams(paramsFromURL(ctx,
ParamPage,
ParamOrganizationId,
))
if err != nil {
return err
}
Expand All @@ -391,16 +385,16 @@ func (a *API) accountElectionsListByPageHandler(_ *apirest.APIdata, ctx *httprou
// @Success 200 {object} ElectionsList
// @Router /accounts/{organizationId}/elections/status/{status}/page/{page} [get]
func (a *API) accountElectionsListByStatusAndPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
params, err := parseElectionParams(
ctx.URLParam(ParamPage),
params, err := electionParams(paramsFromURL(ctx,
ParamPage,
ParamStatus,
ParamOrganizationId,
"",
ctx.URLParam(ParamStatus),
ctx.URLParam(ParamOrganizationId),
"",
"",
"",
"",
)
"", "", "", "",
))
if err != nil {
return err
}
Expand Down
36 changes: 20 additions & 16 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,26 @@ const (
//
//nolint:revive
const (
ParamAccountId = "accountId"
ParamCensusId = "censusId"
ParamElectionId = "electionId"
ParamOrganizationId = "organizationId"
ParamVoteId = "voteId"
ParamPage = "page"
ParamLimit = "limit"
ParamStatus = "status"
ParamWithResults = "withResults"
ParamFinalResults = "finalResults"
ParamManuallyEnded = "manuallyEnded"
ParamHeight = "height"
ParamReference = "reference"
ParamType = "type"
ParamAccountIdFrom = "accountIdFrom"
ParamAccountIdTo = "accountIdTo"
ParamAccountId = "accountId"
ParamCensusId = "censusId"
ParamElectionId = "electionId"
ParamOrganizationId = "organizationId"
ParamVoteId = "voteId"
ParamPage = "page"
ParamLimit = "limit"
ParamStatus = "status"
ParamWithResults = "withResults"
ParamFinalResults = "finalResults"
ParamManuallyEnded = "manuallyEnded"
ParamHeight = "height"
ParamReference = "reference"
ParamType = "type"
ParamAccountIdFrom = "accountIdFrom"
ParamAccountIdTo = "accountIdTo"
ParamStartDateAfter = "startDateAfter"
ParamStartDateBefore = "startDateBefore"
ParamEndDateAfter = "endDateAfter"
ParamEndDateBefore = "endDateBefore"
)

var (
Expand Down
16 changes: 10 additions & 6 deletions api/api_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@ type PaginationParams struct {
// ElectionParams allows the client to filter elections
type ElectionParams struct {
PaginationParams
OrganizationID string `json:"organizationId,omitempty"`
ElectionID string `json:"electionId,omitempty"`
Status string `json:"status,omitempty"`
WithResults *bool `json:"withResults,omitempty"`
FinalResults *bool `json:"finalResults,omitempty"`
ManuallyEnded *bool `json:"manuallyEnded,omitempty"`
OrganizationID string `json:"organizationId,omitempty"`
ElectionID string `json:"electionId,omitempty"`
Status string `json:"status,omitempty"`
WithResults *bool `json:"withResults,omitempty"`
FinalResults *bool `json:"finalResults,omitempty"`
ManuallyEnded *bool `json:"manuallyEnded,omitempty"`
StartDateAfter *time.Time `json:"startDateAfter,omitempty"`
StartDateBefore *time.Time `json:"startDateBefore,omitempty"`
EndDateAfter *time.Time `json:"endDateAfter,omitempty"`
EndDateBefore *time.Time `json:"endDateBefore,omitempty"`
}

// OrganizationParams allows the client to filter organizations
Expand Down
85 changes: 42 additions & 43 deletions api/elections.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,9 @@ func (a *API) electionListByFilterHandler(msg *apirest.APIdata, ctx *httprouter.
// @Success 200 {object} ElectionsList
// @Router /elections/page/{page} [get]
func (a *API) electionListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
params, err := parseElectionParams(
ctx.URLParam(ParamPage),
"",
"",
"",
"",
"",
"",
"",
)
params, err := electionParams(paramsFromURL(ctx,
ParamPage,
))
if err != nil {
return err
}
Expand All @@ -241,16 +234,20 @@ func (a *API) electionListByPageHandler(_ *apirest.APIdata, ctx *httprouter.HTTP
// @Success 200 {object} ElectionsList
// @Router /elections [get]
func (a *API) electionListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
params, err := parseElectionParams(
ctx.QueryParam(ParamPage),
ctx.QueryParam(ParamLimit),
ctx.QueryParam(ParamStatus),
ctx.QueryParam(ParamOrganizationId),
ctx.QueryParam(ParamElectionId),
ctx.QueryParam(ParamWithResults),
ctx.QueryParam(ParamFinalResults),
ctx.QueryParam(ParamManuallyEnded),
)
params, err := electionParams(paramsFromQuery(ctx,
ParamPage,
ParamLimit,
ParamStatus,
ParamOrganizationId,
ParamElectionId,
ParamWithResults,
ParamFinalResults,
ParamManuallyEnded,
ParamStartDateAfter,
ParamStartDateBefore,
ParamEndDateAfter,
ParamEndDateBefore,
))
if err != nil {
return err
}
Expand Down Expand Up @@ -757,38 +754,40 @@ func (a *API) buildElectionIDHandler(msg *apirest.APIdata, ctx *httprouter.HTTPC
return ctx.Send(data, apirest.HTTPstatusOK)
}

// parseElectionParams returns an ElectionParams filled with the passed params
func parseElectionParams(paramPage, paramLimit, paramStatus,
paramOrganizationID, paramElectionID,
paramWithResults, paramFinalResults, paramManuallyEnded string,
) (*ElectionParams, error) {
pagination, err := parsePaginationParams(paramPage, paramLimit)
if err != nil {
return nil, err
}

withResults, err := parseBool(paramWithResults)
// electionParams returns an ElectionParams filled in using the passed map
func electionParams(strings map[string]string) (*ElectionParams, error) {
pagination, err := parsePaginationParams(strings[ParamPage], strings[ParamLimit])
if err != nil {
return nil, err
}

finalResults, err := parseBool(paramFinalResults)
if err != nil {
return nil, err
bools := make(map[string]*bool)
for _, v := range []string{ParamWithResults, ParamFinalResults, ParamManuallyEnded} {
bools[v], err = parseBool(strings[v])
if err != nil {
return nil, err
}
}

manuallyEnded, err := parseBool(paramManuallyEnded)
if err != nil {
return nil, err
dates := make(map[string]*time.Time)
for _, v := range []string{ParamStartDateAfter, ParamStartDateBefore, ParamEndDateAfter, ParamEndDateBefore} {
dates[v], err = parseDate(strings[v])
if err != nil {
return nil, err
}
}

return &ElectionParams{
PaginationParams: pagination,
OrganizationID: util.TrimHex(paramOrganizationID),
ElectionID: util.TrimHex(paramElectionID),
Status: paramStatus,
WithResults: withResults,
FinalResults: finalResults,
ManuallyEnded: manuallyEnded,
OrganizationID: util.TrimHex(strings[ParamOrganizationId]),
ElectionID: util.TrimHex(strings[ParamElectionId]),
Status: strings[ParamStatus],
WithResults: bools[ParamWithResults],
FinalResults: bools[ParamFinalResults],
ManuallyEnded: bools[ParamManuallyEnded],
StartDateAfter: dates[ParamStartDateAfter],
StartDateBefore: dates[ParamStartDateBefore],
EndDateAfter: dates[ParamEndDateAfter],
EndDateBefore: dates[ParamEndDateBefore],
}, nil
}
1 change: 1 addition & 0 deletions api/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var (
ErrCantParseBoolean = apirest.APIerror{Code: 4055, HTTPstatus: apirest.HTTPstatusBadRequest, Err: fmt.Errorf("cannot parse string into boolean")}
ErrCantParseHexString = apirest.APIerror{Code: 4056, HTTPstatus: apirest.HTTPstatusBadRequest, Err: fmt.Errorf("cannot parse string into hex bytes")}
ErrPageNotFound = apirest.APIerror{Code: 4057, HTTPstatus: apirest.HTTPstatusNotFound, Err: fmt.Errorf("page not found")}
ErrCantParseDate = apirest.APIerror{Code: 4058, HTTPstatus: apirest.HTTPstatusBadRequest, Err: fmt.Errorf("cannot parse date")}
ErrVochainEmptyReply = apirest.APIerror{Code: 5000, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("vochain returned an empty reply")}
ErrVochainSendTxFailed = apirest.APIerror{Code: 5001, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("vochain SendTx failed")}
ErrVochainGetTxFailed = apirest.APIerror{Code: 5002, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("vochain GetTx failed")}
Expand Down
36 changes: 36 additions & 0 deletions api/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"math/big"
"strconv"
"strings"
"time"

cometpool "github.com/cometbft/cometbft/mempool"
cometcoretypes "github.com/cometbft/cometbft/rpc/core/types"
Expand Down Expand Up @@ -275,6 +276,20 @@ func parseBool(s string) (*bool, error) {
return &b, nil
}

// parseDate parses an RFC3339 string into a time.Time value.
//
// The empty string "" is treated specially, returns a nil pointer with no error.
func parseDate(s string) (*time.Time, error) {
if s == "" {
return nil, nil
}
b, err := time.Parse(time.RFC3339, s)
if err != nil {
return nil, ErrCantParseDate.With(s)
}
return &b, nil
}

// parsePaginationParams returns a PaginationParams filled with the passed params
func parsePaginationParams(paramPage, paramLimit string) (PaginationParams, error) {
page, err := parsePage(paramPage)
Expand Down Expand Up @@ -325,3 +340,24 @@ func calculatePagination(page int, limit int, totalItems uint64) (*Pagination, e
LastPage: uint64(lastp),
}, nil
}

// paramsFromURL calls ctx.URLParam(key) for each key passed,
// and the resulting value is saved in map[key] of the returned map.
func paramsFromURL(ctx *httprouter.HTTPContext, keys ...string) map[string]string {
return paramsFromFunc(ctx.URLParam, keys...)
}

// paramsFromQuery calls ctx.QueryParam(key) for each key passed,
// and the resulting value is saved in map[key] of the returned map.
func paramsFromQuery(ctx *httprouter.HTTPContext, keys ...string) map[string]string {
return paramsFromFunc(ctx.QueryParam, keys...)
}

// paramsFromFunc calls f(key) for each key passed, and the resulting value is saved in map[key] of the returned map
func paramsFromFunc(f func(key string) string, keys ...string) map[string]string {
m := make(map[string]string)
for _, key := range keys {
m[key] = f(key)
}
return m
}
14 changes: 14 additions & 0 deletions vochain/indexer/db/processes.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions vochain/indexer/queries/processes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ WITH results AS (
OR (sqlc.arg(manually_ended) = 1 AND manually_ended = TRUE)
OR (sqlc.arg(manually_ended) = 0 AND manually_ended = FALSE)
)
AND (
(sqlc.arg(start_date_after) IS NULL OR start_date >= sqlc.arg(start_date_after))
AND (sqlc.arg(start_date_before) IS NULL OR start_date <= sqlc.arg(start_date_before))
AND (sqlc.arg(end_date_after) IS NULL OR end_date >= sqlc.arg(end_date_after))
AND (sqlc.arg(end_date_before) IS NULL OR end_date <= sqlc.arg(end_date_before))
)
)
)
SELECT id, total_count
Expand Down

0 comments on commit 3ac33c5

Please sign in to comment.