110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
package common
|
|
|
|
import (
|
|
"database/sql"
|
|
|
|
qgen "git.tuxpa.in/a/gosora/query_gen"
|
|
)
|
|
|
|
var pollStmts PollStmts
|
|
|
|
type Poll struct {
|
|
ID int
|
|
ParentID int
|
|
ParentTable string
|
|
Type int // 0: Single choice, 1: Multiple choice, 2: Multiple choice w/ points
|
|
AntiCheat bool // Apply various mitigations for cheating
|
|
// GroupPower map[gid]points // The number of points a group can spend in this poll, defaults to 1
|
|
|
|
Options map[int]string
|
|
Results map[int]int // map[optionIndex]points
|
|
QuickOptions []PollOption // TODO: Fix up the template transpiler so we don't need to use this hack anymore
|
|
VoteCount int
|
|
}
|
|
|
|
// TODO: Use a transaction for this?
|
|
// TODO: Add a voters table with castAt / IP data and only populate it when poll anti-cheat is on
|
|
func (p *Poll) CastVote(optionIndex, uid int, ip string) error {
|
|
if Config.DisablePollIP || !p.AntiCheat {
|
|
ip = ""
|
|
}
|
|
_, e := pollStmts.addVote.Exec(p.ID, uid, optionIndex, ip)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
_, e = pollStmts.incVoteCount.Exec(p.ID)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
_, e = pollStmts.incVoteCountForOption.Exec(optionIndex, p.ID)
|
|
return e
|
|
}
|
|
|
|
func (p *Poll) Delete() error {
|
|
_, e := pollStmts.deletePollVotes.Exec(p.ID)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
_, e = pollStmts.deletePollOptions.Exec(p.ID)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
_, e = pollStmts.deletePoll.Exec(p.ID)
|
|
_ = Polls.GetCache().Remove(p.ID)
|
|
return e
|
|
}
|
|
|
|
func (p *Poll) Resultsf(f func(votes int) error) error {
|
|
rows, e := pollStmts.getResults.Query(p.ID)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
defer rows.Close()
|
|
|
|
var votes int
|
|
for rows.Next() {
|
|
if e := rows.Scan(&votes); e != nil {
|
|
return e
|
|
}
|
|
if e := f(votes); e != nil {
|
|
return e
|
|
}
|
|
}
|
|
return rows.Err()
|
|
}
|
|
|
|
func (p *Poll) Copy() Poll {
|
|
return *p
|
|
}
|
|
|
|
type PollStmts struct {
|
|
getResults *sql.Stmt
|
|
|
|
addVote *sql.Stmt
|
|
incVoteCount *sql.Stmt
|
|
incVoteCountForOption *sql.Stmt
|
|
|
|
deletePoll *sql.Stmt
|
|
deletePollOptions *sql.Stmt
|
|
deletePollVotes *sql.Stmt
|
|
}
|
|
|
|
func init() {
|
|
DbInits.Add(func(acc *qgen.Accumulator) error {
|
|
p := "polls"
|
|
wh := "pollID=?"
|
|
pollStmts = PollStmts{
|
|
getResults: acc.Select("polls_options").Columns("votes").Where("pollID=?").Orderby("option ASC").Prepare(),
|
|
|
|
addVote: acc.Insert("polls_votes").Columns("pollID,uid,option,castAt,ip").Fields("?,?,?,UTC_TIMESTAMP(),?").Prepare(),
|
|
incVoteCount: acc.Update(p).Set("votes=votes+1").Where(wh).Prepare(),
|
|
incVoteCountForOption: acc.Update("polls_options").Set("votes=votes+1").Where("option=? AND pollID=?").Prepare(),
|
|
|
|
deletePoll: acc.Delete(p).Where(wh).Prepare(),
|
|
deletePollOptions: acc.Delete("polls_options").Where(wh).Prepare(),
|
|
deletePollVotes: acc.Delete("polls_votes").Where(wh).Prepare(),
|
|
}
|
|
return acc.FirstError()
|
|
})
|
|
}
|