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

notably, the indexer.ProcessList method was not refactored.
  • Loading branch information
altergui committed Aug 19, 2024
1 parent 809b765 commit cd62600
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 99 deletions.
25 changes: 7 additions & 18 deletions api/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,9 @@ 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(ctx.URLParam,
ParamPage,
ParamOrganizationId,
)
if err != nil {
return err
Expand Down Expand Up @@ -391,15 +385,10 @@ 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),
"",
ctx.URLParam(ParamStatus),
ctx.URLParam(ParamOrganizationId),
"",
"",
"",
"",
params, err := electionParams(ctx.URLParam,
ParamPage,
ParamStatus,
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
86 changes: 46 additions & 40 deletions api/elections.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,15 +207,8 @@ 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(ctx.URLParam,
ParamPage,
)
if err != nil {
return err
Expand All @@ -241,15 +234,19 @@ 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(ctx.QueryParam,
ParamPage,
ParamLimit,
ParamStatus,
ParamOrganizationId,
ParamElectionId,
ParamWithResults,
ParamFinalResults,
ParamManuallyEnded,
ParamStartDateAfter,
ParamStartDateBefore,
ParamEndDateAfter,
ParamEndDateBefore,
)
if err != nil {
return err
Expand Down Expand Up @@ -282,6 +279,10 @@ func (a *API) sendElectionList(ctx *httprouter.HTTPContext, params *ElectionPara
params.WithResults,
params.FinalResults,
params.ManuallyEnded,
params.StartDateAfter,
params.StartDateBefore,
params.EndDateAfter,
params.EndDateBefore,
)
if err != nil {
return ErrIndexerQueryFailed.WithErr(err)
Expand Down Expand Up @@ -757,38 +758,43 @@ 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
}
// electionParams produces an ElectionParams, calling the passed func (ctx.QueryParam or ctx.URLParam)
// to retrieve all the values of all keys passed.
func electionParams(f func(key string) string, keys ...string) (*ElectionParams, error) {
strings := paramsFromCtxFunc(f, keys...)

withResults, err := parseBool(paramWithResults)
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
28 changes: 28 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,24 @@ func parseBool(s string) (*bool, error) {
return &b, nil
}

// parseDate parses an RFC3339 string into a time.Time value.
// As a convenience, accepts also time.DateOnly format (i.e. 2006-01-02).
//
// 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 {
if b, err := time.Parse(time.DateOnly, s); err == nil {
return &b, nil
}
return nil, ErrCantParseDate.WithErr(err)
}
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 +344,12 @@ func calculatePagination(page int, limit int, totalItems uint64) (*Pagination, e
LastPage: uint64(lastp),
}, nil
}

// paramsFromCtxFunc calls f(key) for each key passed, and the resulting value is saved in map[key] of the returned map
func paramsFromCtxFunc(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
}
12 changes: 12 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.

Loading

0 comments on commit cd62600

Please sign in to comment.