go: Implement voting

There are currently no ways to start vote so the code cannot be tested currently.
master
Luther Wen Xu 2019-10-10 18:38:30 +07:00
parent 7fed3d8dd3
commit 8d51fb02b8
Signed by untrusted user: chanbakjsd
GPG Key ID: B7D77E3E9D102B70
5 changed files with 154 additions and 0 deletions

@ -23,4 +23,12 @@ func init() {
if err != nil {
panic(err)
}
_, err = db.Exec("CREATE TABLE IF NOT EXISTS vote (id INTEGER PRIMARY KEY, messageId TEXT, name TEXT, finished BOOLEAN, UNIQUE(id))")
if err != nil {
panic(err)
}
_, err = db.Exec("CREATE TABLE IF NOT EXISTS choices (voteId INTEGER, userId INTEGER, date TIMEDATE, value INTEGER, UNIQUE(voteId, userId))")
if err != nil {
panic(err)
}
}

@ -0,0 +1,68 @@
package main
import (
"errors"
"time"
)
const (
forceRejectionVote = -1
nuclearOptionVote = 10
)
var errForceRejectionVoteReuse = errors.New("db: the user has used force rejection vote in the last month")
var errVoteIsOver = errors.New("db: the vote cannot be changed once it's over")
func getVoteName(id int) (string, error) {
rows, err := db.Query("SELECT name FROM vote WHERE id=?", id)
if err != nil {
return "", err
}
if rows.Next() {
var name string
err := rows.Scan(&name)
if err != nil {
return "", err
}
return name, nil
}
return "", errNotFound
}
func getVoteFromMessageID(msgID string) (int, error) {
rows, err := db.Query("SELECT id FROM vote WHERE messageId=?", msgID)
if err != nil {
return 0, err
}
if rows.Next() {
var id int
err := rows.Scan(&id)
if err != nil {
return 0, err
}
return id, nil
}
return 0, errNotFound
}
func updateVote(voteID int, userID string, voteValue int) error {
if voteValue == forceRejectionVote {
//Check if they used it within a month.
rows, err := db.Query("SELECT voteId FROM choices WHERE date >= ? AND value=?", time.Now().AddDate(0, -1, 0))
if err != nil {
return err
}
if rows.Next() {
return errForceRejectionVoteReuse
}
}
//Check if the vote is finished and don't allow change of vote that way.
rows, err := db.Query("SELECT finished FROM vote WHERE id=? AND finished=?", voteID, true)
if rows.Next() {
return errVoteIsOver
}
_, err = db.Exec("REPLACE INTO choices (voteId, userId, date, value) VALUES (?, ?, ?, ?)", voteID, userID, time.Now(), voteValue)
return err
}

@ -18,6 +18,7 @@ func main() {
panic(err)
}
dg.AddHandler(messageCreate)
dg.AddHandler(checkForVote)
if err := dg.Open(); err != nil {
panic(err)
}

@ -5,6 +5,8 @@ import "github.com/bwmarrin/discordgo"
const guildID = "626424729234046987"
const memberRoleID = "626434632614805526"
const auditChannel = "631789849929711627"
func enforceDM(s *discordgo.Session, m *discordgo.MessageCreate) bool {
if m.GuildID != "" {
//This command can only be used in DM to protect the invite creator.
@ -38,3 +40,16 @@ func membersOnly(s *discordgo.Session, m *discordgo.MessageCreate) bool {
)
return false
}
func sendPrivateMessage(s *discordgo.Session, recipient, message string) error {
channel, err := s.UserChannelCreate(recipient)
if err != nil {
return err
}
_, err = s.ChannelMessageSend(channel.ID, message)
return err
}
func auditLog(s *discordgo.Session, message string) {
s.ChannelMessageSend(auditChannel, message)
}

@ -0,0 +1,62 @@
package main
import (
"fmt"
"github.com/bwmarrin/discordgo"
)
func checkForVote(s *discordgo.Session, r *discordgo.MessageReactionAdd) {
voteID, err := getVoteFromMessageID(r.MessageID)
if err != nil {
return
}
s.MessageReactionRemove(r.ChannelID, r.MessageID, r.Emoji.ID, r.UserID)
var value int
switch r.Emoji.Name {
case "x":
value = forceRejectionVote
case "one":
value = 1
case "two":
value = 2
case "three":
value = 3
case "four":
value = 4
case "five":
value = 5
case "white_check_mark":
value = nuclearOptionVote
default:
return
}
err = updateVote(voteID, r.UserID, value)
if err == errForceRejectionVoteReuse {
sendPrivateMessage(s, r.UserID, "您在这个月内已使用过:x:。请选择其他选项。\nYou have used :x: this month. Please choose another option.")
return
}
if err == errVoteIsOver {
sendPrivateMessage(s, r.UserID, "这个投票已结束。你投的票没有被记录。\nThe vote is over so your vote is not recorded.")
return
}
var voteName string
if err == nil {
voteName, err = getVoteName(voteID)
}
if err != nil {
sendPrivateMessage(s, r.UserID, "一个错误已发生,请重新尝试。\nAn error has occurred while voting. Please try again.")
auditLog(s,
fmt.Sprintf("Error occurred while processing vote for <@%s>.\n%v\nError: %s", r.UserID, r, err.Error()),
)
return
}
sendPrivateMessage(s, r.UserID, "您投票已成功。\nYou have voted successfully.\n名字Vote Name: "+voteName+"\n目前投的票 :"+r.Emoji.Name+":")
}