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)