diff --git a/common/parser.go b/common/parser.go index 2e17844b..cef83a71 100644 --- a/common/parser.go +++ b/common/parser.go @@ -32,7 +32,7 @@ var urlMention = []byte(" class='mention'") var URLClose = []byte("") var imageOpen = []byte("") +var imageClose = []byte("' class='postImage'/>") var attachOpen = []byte("Attachment") var sidParam = []byte("?sid=") diff --git a/common/poll.go b/common/poll.go index 9e8095c1..df45923a 100644 --- a/common/poll.go +++ b/common/poll.go @@ -12,8 +12,8 @@ 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 + 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 @@ -22,8 +22,22 @@ type Poll struct { 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 { - return Polls.CastVote(optionIndex, p.ID, uid, ip) // TODO: Move the query into a pollStmts rather than having it in the store + if Config.DisablePollIP || !p.AntiCheat { + ip = "" + } + _, err := pollStmts.addVote.Exec(p.ID, uid, optionIndex, ip) + if err != nil { + return err + } + _, err = pollStmts.incVoteCount.Exec(p.ID) + if err != nil { + return err + } + _, err = pollStmts.incVoteCountForOption.Exec(optionIndex, p.ID) + return err } func (p *Poll) Delete() error { @@ -44,17 +58,24 @@ func (p *Poll) Copy() Poll { } type PollStmts struct { - deletePoll *sql.Stmt - deletePollOptions *sql.Stmt - deletePollVotes *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" pollStmts = PollStmts{ - deletePoll: acc.Delete("polls").Where("pollID=?").Prepare(), - deletePollOptions: acc.Delete("polls_options").Where("pollID=?").Prepare(), - deletePollVotes: acc.Delete("polls_votes").Where("pollID=?").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("pollID=?").Prepare(), + incVoteCountForOption: acc.Update("polls_options").Set("votes = votes + 1").Where("option=? AND pollID=?").Prepare(), + deletePoll: acc.Delete(p).Where("pollID=?").Prepare(), + deletePollOptions: acc.Delete("polls_options").Where("pollID=?").Prepare(), + deletePollVotes: acc.Delete("polls_votes").Where("pollID=?").Prepare(), } return acc.FirstError() }) diff --git a/common/poll_store.go b/common/poll_store.go index 35791169..cf1253fa 100644 --- a/common/poll_store.go +++ b/common/poll_store.go @@ -27,7 +27,6 @@ type PollStore interface { Get(id int) (*Poll, error) Exists(id int) bool Create(parent Pollable, pollType int, pollOptions map[int]string) (int, error) - CastVote(optionIndex, pollID, uid int, ip string) error Reload(id int) error //Count() int @@ -38,14 +37,11 @@ type PollStore interface { type DefaultPollStore struct { cache PollCache - get *sql.Stmt - exists *sql.Stmt - createPoll *sql.Stmt - createPollOption *sql.Stmt - addVote *sql.Stmt - incVoteCount *sql.Stmt - incVoteCountForOption *sql.Stmt - delete *sql.Stmt + get *sql.Stmt + exists *sql.Stmt + createPoll *sql.Stmt + createPollOption *sql.Stmt + delete *sql.Stmt //count *sql.Stmt } @@ -55,16 +51,14 @@ func NewDefaultPollStore(cache PollCache) (*DefaultPollStore, error) { cache = NewNullPollCache() } // TODO: Add an admin version of registerStmt with more flexibility? + p := "polls" return &DefaultPollStore{ - cache: cache, - get: acc.Select("polls").Columns("parentID, parentTable, type, options, votes").Where("pollID = ?").Prepare(), - exists: acc.Select("polls").Columns("pollID").Where("pollID = ?").Prepare(), - createPoll: acc.Insert("polls").Columns("parentID, parentTable, type, options").Fields("?,?,?,?").Prepare(), - createPollOption: acc.Insert("polls_options").Columns("pollID, option, votes").Fields("?,?,0").Prepare(), - addVote: acc.Insert("polls_votes").Columns("pollID,uid,option,castAt,ip").Fields("?,?,?,UTC_TIMESTAMP(),?").Prepare(), - incVoteCount: acc.Update("polls").Set("votes = votes + 1").Where("pollID = ?").Prepare(), - incVoteCountForOption: acc.Update("polls_options").Set("votes = votes + 1").Where("option=? AND pollID=?").Prepare(), - //count: acc.SimpleCount("polls", "", ""), + cache: cache, + get: acc.Select(p).Columns("parentID, parentTable, type, options, votes").Where("pollID=?").Prepare(), + exists: acc.Select(p).Columns("pollID").Where("pollID=?").Prepare(), + createPoll: acc.Insert(p).Columns("parentID, parentTable, type, options").Fields("?,?,?,?").Prepare(), + createPollOption: acc.Insert("polls_options").Columns("pollID, option, votes").Fields("?,?,0").Prepare(), + //count: acc.SimpleCount(p, "", ""), }, acc.FirstError() } @@ -211,23 +205,6 @@ func (s *DefaultPollStore) unpackOptionsMap(rawOptions map[int]string) []PollOpt return options } -// TODO: Use a transaction for this? -func (s *DefaultPollStore) CastVote(optionIndex, pollID, uid int, ip string) error { - if Config.DisablePollIP { - ip = "" - } - _, err := s.addVote.Exec(pollID, uid, optionIndex, ip) - if err != nil { - return err - } - _, err = s.incVoteCount.Exec(pollID) - if err != nil { - return err - } - _, err = s.incVoteCountForOption.Exec(optionIndex, pollID) - return err -} - // TODO: Use a transaction for this func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map[int]string) (id int, err error) { pollOptionsTxt, err := json.Marshal(pollOptions)