summaryrefslogtreecommitdiff
path: root/models.go
diff options
context:
space:
mode:
authorJan Dittberner <jandd@cacert.org>2021-01-09 15:49:19 +0100
committerJan Dittberner <jandd@cacert.org>2021-01-09 15:49:19 +0100
commit03827874cfc51b4be6709459d5263ef87f31dbe4 (patch)
tree521618919516cf130aba35c0fca119d1e660d157 /models.go
parent594df29dc132c1573dddda3883eb4a31cdd99756 (diff)
downloadcacert-boardvoting-03827874cfc51b4be6709459d5263ef87f31dbe4.tar.gz
cacert-boardvoting-03827874cfc51b4be6709459d5263ef87f31dbe4.tar.xz
cacert-boardvoting-03827874cfc51b4be6709459d5263ef87f31dbe4.zip
Configure golangci-lint and apply suggestions
Diffstat (limited to 'models.go')
-rw-r--r--models.go439
1 files changed, 259 insertions, 180 deletions
diff --git a/models.go b/models.go
index 2ce7db4..3647097 100644
--- a/models.go
+++ b/models.go
@@ -1,51 +1,54 @@
/*
- Copyright 2017-2020 Jan Dittberner
+Copyright 2017-2021 Jan Dittberner
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this program except in compliance with the License.
- You may obtain a copy of the License at
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this program except in compliance with the License.
+You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
*/
+
package main
import (
"database/sql"
+ "errors"
"fmt"
- "github.com/jmoiron/sqlx"
- "github.com/rubenv/sql-migrate"
"time"
- migrations "git.cacert.org/cacert-boardvoting/db"
+ "github.com/jmoiron/sqlx"
+ migrate "github.com/rubenv/sql-migrate"
log "github.com/sirupsen/logrus"
+
+ migrations "git.cacert.org/cacert-boardvoting/db"
)
type sqlKey int
const (
sqlLoadDecisions sqlKey = iota
- sqlLoadUnvotedDecisions
+ sqlLoadUnVotedDecisions
sqlLoadDecisionByTag
- sqlLoadDecisionById
+ sqlLoadDecisionByID
sqlLoadVoteCountsForDecision
sqlLoadVotesForDecision
sqlLoadEnabledVoterByEmail
sqlCountOlderThanDecision
- sqlCountOlderThanUnvotedDecision
+ sqlCountOlderThanUnVotedDecision
sqlCreateDecision
sqlUpdateDecision
sqlUpdateDecisionStatus
sqlSelectClosableDecisions
sqlGetNextPendingDecisionDue
sqlGetReminderVoters
- sqlFindUnvotedDecisionsForVoter
- sqlGetEnabledVoterById
+ sqlFindUnVotedDecisionsForVoter
+ sqlGetEnabledVoterByID
sqlCreateVote
sqlLoadVote
sqlGetVotersForProxy
@@ -59,7 +62,7 @@ FROM decisions
JOIN voters ON decisions.proponent=voters.id
ORDER BY proposed DESC
LIMIT 10 OFFSET 10 * $1`,
- sqlLoadUnvotedDecisions: `
+ sqlLoadUnVotedDecisions: `
SELECT decisions.id, decisions.tag, decisions.proponent, voters.name AS proposer, decisions.proposed, decisions.title,
decisions.content, decisions.votetype, decisions.status, decisions.due, decisions.modified
FROM decisions
@@ -73,7 +76,7 @@ SELECT decisions.id, decisions.tag, decisions.proponent, voters.name AS proposer
FROM decisions
JOIN voters ON decisions.proponent=voters.id
WHERE decisions.tag=$1;`,
- sqlLoadDecisionById: `
+ sqlLoadDecisionByID: `
SELECT decisions.id, decisions.tag, decisions.proponent, decisions.proposed, decisions.title, decisions.content,
decisions.votetype, decisions.status, decisions.due, decisions.modified
FROM decisions
@@ -91,14 +94,14 @@ FROM voters
JOIN emails ON voters.id=emails.voter
JOIN user_roles ON user_roles.voter_id=voters.id
WHERE emails.address=$1 AND user_roles.role='VOTER'`,
- sqlGetEnabledVoterById: `
+ sqlGetEnabledVoterByID: `
SELECT voters.id, voters.name, voters.reminder
FROM voters
JOIN user_roles ON user_roles.voter_id=voters.id
WHERE user_roles.role='VOTER' AND voters.id=$1`,
sqlCountOlderThanDecision: `
SELECT COUNT(*) > 0 FROM decisions WHERE proposed < $1`,
- sqlCountOlderThanUnvotedDecision: `
+ sqlCountOlderThanUnVotedDecision: `
SELECT COUNT(*) > 0 FROM decisions
WHERE proposed < $1 AND status=0 AND id NOT IN (SELECT decision FROM votes WHERE votes.voter=$2)`,
sqlCreateDecision: `
@@ -134,7 +137,7 @@ SELECT voters.id, voters.name, voters.reminder
FROM voters
JOIN user_roles ON user_roles.voter_id=voters.id
WHERE user_roles.role='VOTER' AND reminder!='' AND reminder IS NOT NULL`,
- sqlFindUnvotedDecisionsForVoter: `
+ sqlFindUnVotedDecisionsForVoter: `
SELECT tag, title, votetype, due
FROM decisions
WHERE status = 0 AND id NOT IN (SELECT decision FROM votes WHERE voter = $1)
@@ -152,9 +155,9 @@ type VoteType uint8
type VoteStatus int8
type Decision struct {
- Id int64
+ ID int64 `db:"id"`
Proposed time.Time
- ProponentId int64 `db:"proponent"`
+ ProponentID int64 `db:"proponent"`
Title string
Content string
Quorum int
@@ -167,7 +170,7 @@ type Decision struct {
}
type Voter struct {
- Id int64
+ ID int64 `db:"id"`
Name string
Reminder string // reminder email address
}
@@ -185,23 +188,36 @@ const (
voteTypeVeto = 1
)
+const (
+ voteTypeLabelMotion = "motion"
+ voteTypeLabelUnknown = "unknown"
+ voteTypeLabelVeto = "veto"
+)
+
func (v VoteType) String() string {
switch v {
case voteTypeMotion:
- return "motion"
+ return voteTypeLabelMotion
case voteTypeVeto:
- return "veto"
+ return voteTypeLabelVeto
default:
- return "unknown"
+ return voteTypeLabelUnknown
}
}
-func (v VoteType) QuorumAndMajority() (int, int) {
+func (v VoteType) QuorumAndMajority() (int, float32) {
+ const (
+ majorityDefault = 0.99
+ majorityMotion = 0.50
+ quorumDefault = 1
+ quorumMotion = 3
+ )
+
switch v {
case voteTypeMotion:
- return 3, 50
+ return quorumMotion, majorityMotion
default:
- return 1, 99
+ return quorumDefault, majorityDefault
}
}
@@ -253,36 +269,42 @@ func (v VoteStatus) String() string {
}
type Vote struct {
- DecisionId int64 `db:"decision"`
- VoterId int64 `db:"voter"`
+ DecisionID int64 `db:"decision"`
+ VoterID int64 `db:"voter"`
Vote VoteChoice
Voted time.Time
Notes string
}
-type dbHandler struct {
+type DbHandler struct {
db *sqlx.DB
}
-var db *dbHandler
+var db *DbHandler
+
+func NewDB(database *sql.DB) *DbHandler {
+ handler := &DbHandler{db: sqlx.NewDb(database, "sqlite3")}
-func NewDB(database *sql.DB) *dbHandler {
- handler := &dbHandler{db: sqlx.NewDb(database, "sqlite3")}
_, err := migrate.Exec(database, "sqlite3", migrations.Migrations(), migrate.Up)
if err != nil {
log.Panicf("running database migration failed: %v", err)
}
failedStatements := make([]string, 0)
+
for _, sqlStatement := range sqlStatements {
var stmt *sqlx.Stmt
+
stmt, err := handler.db.Preparex(sqlStatement)
if err != nil {
log.Errorf("error parsing statement %s: %s", sqlStatement, err)
failedStatements = append(failedStatements, sqlStatement)
}
+
+ // nolint:sqlclosecheck
_ = stmt.Close()
}
+
if len(failedStatements) > 0 {
log.Panicf("%d statements failed to prepare", len(failedStatements))
}
@@ -290,44 +312,48 @@ func NewDB(database *sql.DB) *dbHandler {
return handler
}
-func (d *dbHandler) Close() error {
+func (d *DbHandler) Close() error {
return d.db.Close()
}
-func (d *dbHandler) getPreparedNamedStatement(statementKey sqlKey) *sqlx.NamedStmt {
+func (d *DbHandler) getPreparedNamedStatement(statementKey sqlKey) *sqlx.NamedStmt {
statement, err := d.db.PrepareNamed(sqlStatements[statementKey])
if err != nil {
log.Panicf("Preparing statement failed: %v", err)
}
+
return statement
}
-func (d *dbHandler) getPreparedStatement(statementKey sqlKey) *sqlx.Stmt {
+func (d *DbHandler) getPreparedStatement(statementKey sqlKey) *sqlx.Stmt {
statement, err := d.db.Preparex(sqlStatements[statementKey])
if err != nil {
log.Panicf("Preparing statement failed: %v", err)
}
+
return statement
}
-func (v *Vote) Save() (err error) {
+func (v *Vote) Save() error {
insertVoteStmt := db.getPreparedNamedStatement(sqlCreateVote)
+
defer func() { _ = insertVoteStmt.Close() }()
+ var err error
+
if _, err = insertVoteStmt.Exec(v); err != nil {
- log.Errorf("saving vote failed: %v", err)
- return
+ return fmt.Errorf("saving vote failed: %w", err)
}
getVoteStmt := db.getPreparedStatement(sqlLoadVote)
+
defer func() { _ = getVoteStmt.Close() }()
- if err = getVoteStmt.Get(v, v.DecisionId, v.VoterId); err != nil {
- log.Errorf("getting inserted vote failed: %v", err)
- return
+ if err = getVoteStmt.Get(v, v.DecisionID, v.VoterID); err != nil {
+ return fmt.Errorf("getting inserted vote failed: %w", err)
}
- return
+ return nil
}
type VoteSums struct {
@@ -349,18 +375,20 @@ func (v *VoteSums) Percent() int {
if totalVotes == 0 {
return 0
}
+
return v.Ayes * 100 / totalVotes
}
-func (v *VoteSums) CalculateResult(quorum int, majority int) (status VoteStatus, reasoning string) {
+func (v *VoteSums) CalculateResult(quorum int, majority float32) (VoteStatus, string) {
if v.VoteCount() < quorum {
- status, reasoning = voteStatusDeclined, fmt.Sprintf("Needed quorum of %d has not been reached.", quorum)
- } else if (v.Ayes / v.TotalVotes()) < (majority / 100) {
- status, reasoning = voteStatusDeclined, fmt.Sprintf("Needed majority of %d%% has not been reached.", majority)
- } else {
- status, reasoning = voteStatusApproved, "Quorum and majority have been reached"
+ return voteStatusDeclined, fmt.Sprintf("Needed quorum of %d has not been reached.", quorum)
}
- return
+
+ if (float32(v.Ayes) / float32(v.TotalVotes())) < majority {
+ return voteStatusDeclined, fmt.Sprintf("Needed majority of %0.2f%% has not been reached.", majority)
+ }
+
+ return voteStatusApproved, "Quorum and majority have been reached"
}
type VoteForDisplay struct {
@@ -375,23 +403,26 @@ type DecisionForDisplay struct {
Votes []VoteForDisplay
}
-func FindDecisionForDisplayByTag(tag string) (decision *DecisionForDisplay, err error) {
+func FindDecisionForDisplayByTag(tag string) (*DecisionForDisplay, error) {
decisionStmt := db.getPreparedStatement(sqlLoadDecisionByTag)
+
defer func() { _ = decisionStmt.Close() }()
- decision = &DecisionForDisplay{}
+ decision := &DecisionForDisplay{}
+
+ var err error
+
if err = decisionStmt.Get(decision, tag); err != nil {
- if err == sql.ErrNoRows {
- decision = nil
- err = nil
- return
- } else {
- log.Errorf("getting motion %s failed: %v", tag, err)
- return
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, nil
}
+
+ return nil, fmt.Errorf("getting motion %s failed: %w", tag, err)
}
+
decision.VoteSums, err = decision.Decision.VoteSums()
- return
+
+ return decision, err
}
// FindDecisionsForDisplayOnPage loads a set of decisions from the database.
@@ -399,61 +430,78 @@ func FindDecisionForDisplayByTag(tag string) (decision *DecisionForDisplay, err
// This function uses OFFSET for pagination which is not a good idea for larger data sets.
//
// TODO: migrate to timestamp base pagination
-func FindDecisionsForDisplayOnPage(page int64, unvoted bool, voter *Voter) (decisions []*DecisionForDisplay, err error) {
+func FindDecisionsForDisplayOnPage(page int64, unVoted bool, voter *Voter) ([]*DecisionForDisplay, error) {
var decisionsStmt *sqlx.Stmt
- if unvoted && voter != nil {
- decisionsStmt = db.getPreparedStatement(sqlLoadUnvotedDecisions)
+
+ if unVoted && voter != nil {
+ decisionsStmt = db.getPreparedStatement(sqlLoadUnVotedDecisions)
} else {
decisionsStmt = db.getPreparedStatement(sqlLoadDecisions)
}
+
defer func() { _ = decisionsStmt.Close() }()
- var rows *sqlx.Rows
- if unvoted && voter != nil {
- rows, err = decisionsStmt.Queryx(voter.Id, page-1)
+ var (
+ rows *sqlx.Rows
+ err error
+ decisions []*DecisionForDisplay
+ )
+
+ if unVoted && voter != nil {
+ rows, err = decisionsStmt.Queryx(voter.ID, page-1)
} else {
rows, err = decisionsStmt.Queryx(page - 1)
}
+
if err != nil {
- log.Errorf("loading motions for page %d failed: %v", page, err)
- return
+ return nil, fmt.Errorf("loading motions for page %d failed: %w", page, err)
}
+
defer func() { _ = rows.Close() }()
for rows.Next() {
var d DecisionForDisplay
+
if err = rows.StructScan(&d); err != nil {
- log.Errorf("loading motions for page %d failed: %v", page, err)
- return
+ return nil, fmt.Errorf("loading motions for page %d failed: %w", page, err)
}
+
d.VoteSums, err = d.Decision.VoteSums()
+
if err != nil {
- return
+ return nil, err
}
+
decisions = append(decisions, &d)
}
- return
+
+ return decisions, nil
}
-func (d *Decision) VoteSums() (sums *VoteSums, err error) {
+func (d *Decision) VoteSums() (*VoteSums, error) {
votesStmt := db.getPreparedStatement(sqlLoadVoteCountsForDecision)
+
defer func() { _ = votesStmt.Close() }()
- voteRows, err := votesStmt.Queryx(d.Id)
+ voteRows, err := votesStmt.Queryx(d.ID)
if err != nil {
- log.Errorf("fetching vote sums for motion %s failed: %v", d.Tag, err)
- return
+ return nil, fmt.Errorf("fetching vote sums for motion %s failed: %w", d.Tag, err)
}
+
defer func() { _ = voteRows.Close() }()
- sums = &VoteSums{}
+ sums := &VoteSums{}
+
for voteRows.Next() {
- var vote VoteChoice
- var count int
+ var (
+ vote VoteChoice
+ count int
+ )
+
if err = voteRows.Scan(&vote, &count); err != nil {
- log.Errorf("fetching vote sums for motion %s failed: %v", d.Tag, err)
- return
+ return nil, fmt.Errorf("fetching vote sums for motion %s failed: %w", d.Tag, err)
}
+
switch vote {
case voteAye:
sums.Ayes = count
@@ -463,79 +511,86 @@ func (d *Decision) VoteSums() (sums *VoteSums, err error) {
sums.Abstains = count
}
}
- return
+
+ return sums, nil
}
func (d *DecisionForDisplay) LoadVotes() (err error) {
votesStmt := db.getPreparedStatement(sqlLoadVotesForDecision)
+
defer func() { _ = votesStmt.Close() }()
- err = votesStmt.Select(&d.Votes, d.Id)
+ err = votesStmt.Select(&d.Votes, d.ID)
if err != nil {
log.Errorf("selecting votes for motion %s failed: %v", d.Tag, err)
+
return
}
+
return
}
-func (d *Decision) OlderExists(unvoted bool, voter *Voter) (result bool, err error) {
+func (d *Decision) OlderExists(unvoted bool, voter *Voter) (bool, error) {
+ var result bool
+
if unvoted && voter != nil {
- olderStmt := db.getPreparedStatement(sqlCountOlderThanUnvotedDecision)
+ olderStmt := db.getPreparedStatement(sqlCountOlderThanUnVotedDecision)
+
defer func() { _ = olderStmt.Close() }()
- if err = olderStmt.Get(&result, d.Proposed, voter.Id); err != nil {
- log.Errorf("finding older motions than %s failed: %v", d.Tag, err)
- return
+ if err := olderStmt.Get(&result, d.Proposed, voter.ID); err != nil {
+ return false, fmt.Errorf("finding older motions than %s failed: %w", d.Tag, err)
}
} else {
olderStmt := db.getPreparedStatement(sqlCountOlderThanDecision)
+
defer func() { _ = olderStmt.Close() }()
- if err = olderStmt.Get(&result, d.Proposed); err != nil {
- log.Errorf("finding older motions than %s failed: %v", d.Tag, err)
- return
+ if err := olderStmt.Get(&result, d.Proposed); err != nil {
+ return false, fmt.Errorf("finding older motions than %s failed: %w", d.Tag, err)
}
}
- return
+ return result, nil
}
-func (d *Decision) Create() (err error) {
+func (d *Decision) Create() error {
insertDecisionStmt := db.getPreparedNamedStatement(sqlCreateDecision)
+
defer func() { _ = insertDecisionStmt.Close() }()
result, err := insertDecisionStmt.Exec(d)
if err != nil {
- log.Errorf("creating motion failed: %v", err)
- return
+ return fmt.Errorf("creating motion failed: %w", err)
}
- lastInsertId, err := result.LastInsertId()
+ decisionID, err := result.LastInsertId()
if err != nil {
- log.Errorf("getting id of inserted motion failed: %v", err)
- return
+ return fmt.Errorf("getting id of inserted motion failed: %w", err)
}
- rescheduleChannel <- JobIdCloseDecisions
+ rescheduleChannel <- JobIDCloseDecisions
+
+ getDecisionStmt := db.getPreparedStatement(sqlLoadDecisionByID)
- getDecisionStmt := db.getPreparedStatement(sqlLoadDecisionById)
defer func() { _ = getDecisionStmt.Close() }()
- err = getDecisionStmt.Get(d, lastInsertId)
+ err = getDecisionStmt.Get(d, decisionID)
if err != nil {
- log.Errorf("getting inserted motion failed: %v", err)
- return
+ return fmt.Errorf("getting inserted motion failed: %w", err)
}
- return
+ return nil
}
-func (d *Decision) LoadWithId() (err error) {
- getDecisionStmt := db.getPreparedStatement(sqlLoadDecisionById)
+func (d *Decision) LoadWithID() (err error) {
+ getDecisionStmt := db.getPreparedStatement(sqlLoadDecisionByID)
+
defer func() { _ = getDecisionStmt.Close() }()
- err = getDecisionStmt.Get(d, d.Id)
+ err = getDecisionStmt.Get(d, d.ID)
if err != nil {
log.Errorf("loading updated motion failed: %v", err)
+
return
}
@@ -544,93 +599,110 @@ func (d *Decision) LoadWithId() (err error) {
func (d *Decision) Update() (err error) {
updateDecisionStmt := db.getPreparedNamedStatement(sqlUpdateDecision)
+
defer func() { _ = updateDecisionStmt.Close() }()
result, err := updateDecisionStmt.Exec(d)
if err != nil {
log.Errorf("updating motion failed: %v", err)
+
return
}
+
affectedRows, err := result.RowsAffected()
if err != nil {
log.Error("Problem determining the affected rows")
+
return
} else if affectedRows != 1 {
log.Warningf("wrong number of affected rows: %d (1 expected)", affectedRows)
}
- rescheduleChannel <- JobIdCloseDecisions
- err = d.LoadWithId()
+ rescheduleChannel <- JobIDCloseDecisions
+
+ err = d.LoadWithID()
+
return
}
-func (d *Decision) UpdateStatus() (err error) {
+func (d *Decision) UpdateStatus() error {
updateStatusStmt := db.getPreparedNamedStatement(sqlUpdateDecisionStatus)
+
defer func() { _ = updateStatusStmt.Close() }()
result, err := updateStatusStmt.Exec(d)
if err != nil {
- log.Errorf("setting motion status failed: %v", err)
- return
+ return fmt.Errorf("setting motion status failed: %w", err)
}
+
affectedRows, err := result.RowsAffected()
if err != nil {
- log.Errorf("determining the affected rows failed: %v", err)
- return
+ return fmt.Errorf("determining the affected rows failed: %w", err)
} else if affectedRows != 1 {
log.Warningf("wrong number of affected rows: %d (1 expected)", affectedRows)
}
- rescheduleChannel <- JobIdCloseDecisions
- err = d.LoadWithId()
- return
+ rescheduleChannel <- JobIDCloseDecisions
+
+ err = d.LoadWithID()
+
+ return err
}
func (d *Decision) String() string {
- return fmt.Sprintf("%s %s (Id %d)", d.Tag, d.Title, d.Id)
+ return fmt.Sprintf("%s %s (ID %d)", d.Tag, d.Title, d.ID)
}
-func FindVoterByAddress(emailAddress string) (voter *Voter, err error) {
+func FindVoterByAddress(emailAddress string) (*Voter, error) {
findVoterStmt := db.getPreparedStatement(sqlLoadEnabledVoterByEmail)
+
defer func() { _ = findVoterStmt.Close() }()
- voter = &Voter{}
- if err = findVoterStmt.Get(voter, emailAddress); err != nil {
- if err != sql.ErrNoRows {
- log.Errorf("getting voter for address %s failed: %v", emailAddress, err)
- } else {
- err = nil
- voter = nil
+ voter := &Voter{}
+ if err := findVoterStmt.Get(voter, emailAddress); err != nil {
+ if !errors.Is(err, sql.ErrNoRows) {
+ return nil, fmt.Errorf("getting voter for address %s failed: %w", emailAddress, err)
}
+
+ voter = nil
}
- return
+
+ return voter, nil
}
func (d *Decision) Close() error {
quorum, majority := d.VoteType.QuorumAndMajority()
- var voteSums *VoteSums
- var err error
+ var (
+ voteSums *VoteSums
+ err error
+ )
if voteSums, err = d.VoteSums(); err != nil {
log.Errorf("getting vote sums failed: %v", err)
+
return err
}
+
var reasoning string
+
d.Status, reasoning = voteSums.CalculateResult(quorum, majority)
closeDecisionStmt := db.getPreparedNamedStatement(sqlUpdateDecisionStatus)
+
defer func() { _ = closeDecisionStmt.Close() }()
result, err := closeDecisionStmt.Exec(d)
if err != nil {
- log.Errorf("closing vote failed: %v", err)
- return err
+ return fmt.Errorf("closing vote failed: %w", err)
}
- if affectedRows, err := result.RowsAffected(); err != nil {
- log.Errorf("getting affected rows failed: %v", err)
- return err
- } else if affectedRows != 1 {
+
+ affectedRows, err := result.RowsAffected()
+ if err != nil {
+ return fmt.Errorf("getting affected rows failed: %w", err)
+ }
+
+ if affectedRows != 1 {
log.Warningf("wrong number of affected rows: %d (1 expected)", affectedRows)
}
@@ -641,110 +713,117 @@ func (d *Decision) Close() error {
return nil
}
-func CloseDecisions() (err error) {
+func CloseDecisions() error {
getClosableDecisionsStmt := db.getPreparedNamedStatement(sqlSelectClosableDecisions)
+
defer func() { _ = getClosableDecisionsStmt.Close() }()
decisions := make([]*Decision, 0)
+
rows, err := getClosableDecisionsStmt.Queryx(struct{ Now time.Time }{time.Now().UTC()})
if err != nil {
- log.Errorf("fetching closable decisions failed: %v", err)
- return
+ return fmt.Errorf("fetching closable decisions failed: %w", err)
}
+
defer func() { _ = rows.Close() }()
+
for rows.Next() {
decision := &Decision{}
if err = rows.StructScan(decision); err != nil {
- log.Errorf("scanning row failed: %v", err)
- return
+ return fmt.Errorf("scanning row failed: %w", err)
}
+
decisions = append(decisions, decision)
}
+
defer func() { _ = rows.Close() }()
for _, decision := range decisions {
log.Infof("found closable decision %s", decision.Tag)
+
if err = decision.Close(); err != nil {
- log.Errorf("closing decision %s failed: %s", decision.Tag, err)
- return
+ return fmt.Errorf("closing decision %s failed: %w", decision.Tag, err)
}
}
- return
+ return nil
}
-func GetNextPendingDecisionDue() (due *time.Time, err error) {
+func GetNextPendingDecisionDue() (*time.Time, error) {
getNextPendingDecisionDueStmt := db.getPreparedStatement(sqlGetNextPendingDecisionDue)
+
defer func() { _ = getNextPendingDecisionDueStmt.Close() }()
row := getNextPendingDecisionDueStmt.QueryRow()
- due = &time.Time{}
- if err = row.Scan(due); err != nil {
- if err == sql.ErrNoRows {
+ due := &time.Time{}
+ if err := row.Scan(due); err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
log.Debug("No pending decisions")
+
return nil, nil
}
- log.Errorf("parsing result failed: %v", err)
- return nil, err
+
+ return nil, fmt.Errorf("parsing result failed: %w", err)
}
- return
+ return due, nil
}
-func GetReminderVoters() (voters *[]Voter, err error) {
+func GetReminderVoters() ([]Voter, error) {
getReminderVotersStmt := db.getPreparedStatement(sqlGetReminderVoters)
+
defer func() { _ = getReminderVotersStmt.Close() }()
- voterSlice := make([]Voter, 0)
+ var voters []Voter
- if err = getReminderVotersStmt.Select(&voterSlice); err != nil {
- log.Errorf("getting voters failed: %v", err)
- return
+ if err := getReminderVotersStmt.Select(&voters); err != nil {
+ return nil, fmt.Errorf("getting voters failed: %w", err)
}
- voters = &voterSlice
- return
+ return voters, nil
}
-func FindUnvotedDecisionsForVoter(voter *Voter) (decisions *[]Decision, err error) {
- findUnvotedDecisionsForVoterStmt := db.getPreparedStatement(sqlFindUnvotedDecisionsForVoter)
- defer func() { _ = findUnvotedDecisionsForVoterStmt.Close() }()
+func FindUnVotedDecisionsForVoter(voter *Voter) ([]Decision, error) {
+ findUnVotedDecisionsForVoterStmt := db.getPreparedStatement(sqlFindUnVotedDecisionsForVoter)
- decisionsSlice := make([]Decision, 0)
+ defer func() { _ = findUnVotedDecisionsForVoterStmt.Close() }()
- if err = findUnvotedDecisionsForVoterStmt.Select(&decisionsSlice, voter.Id); err != nil {
- log.Errorf("getting unvoted decisions failed: %v", err)
- return
+ var decisions []Decision
+
+ if err := findUnVotedDecisionsForVoterStmt.Select(&decisions, voter.ID); err != nil {
+ return nil, fmt.Errorf("getting unvoted decisions failed: %w", err)
}
- decisions = &decisionsSlice
- return
+ return decisions, nil
}
-func GetVoterById(id int64) (voter *Voter, err error) {
- getVoterByIdStmt := db.getPreparedStatement(sqlGetEnabledVoterById)
- defer func() { _ = getVoterByIdStmt.Close() }()
+func GetVoterByID(id int64) (*Voter, error) {
+ getVoterByIDStmt := db.getPreparedStatement(sqlGetEnabledVoterByID)
- voter = &Voter{}
- if err = getVoterByIdStmt.Get(voter, id); err != nil {
- log.Errorf("getting voter failed: %v", err)
- return
+ defer func() { _ = getVoterByIDStmt.Close() }()
+
+ voter := &Voter{}
+ if err := getVoterByIDStmt.Get(voter, id); err != nil {
+ return nil, fmt.Errorf("getting voter failed: %w", err)
}
- return
+ return voter, nil
}
func GetVotersForProxy(proxy *Voter) (voters *[]Voter, err error) {
getVotersForProxyStmt := db.getPreparedStatement(sqlGetVotersForProxy)
+
defer func() { _ = getVotersForProxyStmt.Close() }()
votersSlice := make([]Voter, 0)
- if err = getVotersForProxyStmt.Select(&votersSlice, proxy.Id); err != nil {
+ if err = getVotersForProxyStmt.Select(&votersSlice, proxy.ID); err != nil {
log.Errorf("Error getting voters for proxy failed: %v", err)
+
return
}
+
voters = &votersSlice
return