Events system

This commit is contained in:
Caleb Denio 2021-05-02 15:39:41 -04:00
parent ad7207c15f
commit 4dec84e9a9
7 changed files with 147 additions and 1 deletions

View file

@ -16,6 +16,6 @@ func main() {
config := jia.NewConfig()
// Start receiving messages
fmt.Println(fmt.Sprintf("Listening on port %d", config.Port))
fmt.Printf("Listening on port %d\n", config.Port)
jia.StartServer(config)
}

6
events.yaml Normal file
View file

@ -0,0 +1,6 @@
- name: Test Event
start: 8:00 May 2, 2021 EDT
end: 7:59 May 3, 2021 EDT
- name: May Counting
start: 8:00 May 3, 2021 EDT
end: 20:00 May 31, 2021 EDT

1
go.mod
View file

@ -7,4 +7,5 @@ require (
github.com/joho/godotenv v1.3.0
github.com/pkg/errors v0.9.1 // indirect
github.com/slack-go/slack v0.6.5
gopkg.in/yaml.v2 v2.4.0 // indirect
)

3
go.sum
View file

@ -18,3 +18,6 @@ github.com/slack-go/slack v0.6.4/go.mod h1:sGRjv3w+ERAUMMMbldHObQPBcNSyVB7KLKYfn
github.com/slack-go/slack v0.6.5 h1:IkDKtJ2IROJNoe3d6mW870/NRKvq2fhLB/Q5XmzWk00=
github.com/slack-go/slack v0.6.5/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View file

@ -3,23 +3,67 @@ package jia
import (
"os"
"strconv"
"time"
"gopkg.in/yaml.v2"
)
type Event struct {
Name string `yaml:"name"`
StartTime time.Time
EndTime time.Time
StartString string `yaml:"start"`
EndString string `yaml:"end"`
}
type Config struct {
BotToken string
ChannelID string
Port int
RedisURL string
VerificationToken string
Events []Event
}
func (c Config) GetRunningEvents() []Event {
var running_events []Event
for _, event := range c.Events {
if time.Since(event.StartTime) > 0 && time.Until(event.EndTime) > 0 {
running_events = append(running_events, event)
}
}
return running_events
}
func NewConfig() *Config {
events_file, err := os.ReadFile("events.yaml")
if err != nil {
panic(err)
}
var events []Event
err = yaml.Unmarshal(events_file, &events)
if err != nil {
panic(err)
}
for i, event := range events {
events[i].StartTime, _ = time.Parse("15:04 Jan 2, 2006 MST", event.StartString)
events[i].EndTime, _ = time.Parse("15:04 Jan 2, 2006 MST", event.EndString)
}
return &Config{
BotToken: getEnv("SLACK_BOT_TOKEN", ""),
ChannelID: getEnv("SLACK_CHANNEL_ID", ""),
Port: getEnvAsInt("PORT", 3000),
RedisURL: getEnv("REDIS_URL", "redis://localhost:6379/0"),
VerificationToken: getEnv("SLACK_VERIFICATION_TOKEN", ""),
Events: events,
}
}

View file

@ -94,6 +94,11 @@ func onMessage(slackClient *slack.Client, event *slackevents.MessageEvent) {
// Increment the person's monthly count
redisClient.Incr(fmt.Sprintf("leaderboard:%d-%d:%s", year, month, event.User))
// Increment the person's count for any running events
for _, counting_event := range jiaConfig.GetRunningEvents() {
redisClient.Incr(fmt.Sprintf("event:%s:%s", counting_event.Name, event.User))
}
}
func HandleLeaderboardSlashCommand(w http.ResponseWriter, r *http.Request) {
@ -171,6 +176,76 @@ func HandleLeaderboardSlashCommand(w http.ResponseWriter, r *http.Request) {
w.Write(resp)
}
func HandleEventsSlashCommand(w http.ResponseWriter, r *http.Request) {
events := jiaConfig.GetRunningEvents()
var blocks []slack.Block
if len(events) == 0 {
blocks = append(blocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", "There aren't any counting events running right now.", false, false), nil, nil))
} else if len(events) == 1 {
blocks = append(blocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", fmt.Sprintf(":calendar: Counting stats for event *%s*:", events[0].Name), false, false), nil, nil))
scan := redisClient.Scan(0, fmt.Sprintf("event:%s:*", events[0].Name), 10)
scanIterator := scan.Iterator()
type Entry struct {
Number int
User string
}
entries := []Entry{}
for scanIterator.Next() {
entry := redisClient.Get(scanIterator.Val())
entryInt, err := entry.Int()
if err != nil {
return
}
if _, user, ok := parseEventEntry(scanIterator.Val()); ok {
entries = append(entries, Entry{
Number: entryInt,
User: user,
})
}
}
// Sort entries
sort.Slice(entries, func(i, j int) bool {
return entries[i].Number > entries[j].Number
})
for i, v := range entries {
emoji := ""
if i == 0 {
emoji = ":first_place_medal:"
} else if i == 1 {
emoji = ":second_place_medal:"
} else if i == 2 {
emoji = ":third_place_medal:"
}
blocks = append(blocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("%s <@%s> has counted *%d* so far", emoji, v.User, v.Number), false, false), nil, nil))
}
if len(entries) > 10 {
entries = entries[:10]
}
blocks = append(blocks, slack.NewContextBlock("", slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("Event will end at *<!date^%d^{time} on {date}|some date>*, your time", events[0].EndTime.Unix()), false, false)))
} else {
blocks = append(blocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", "Something went wrong fetching the events leaderboard :cry:", false, false), nil, nil))
}
resp, _ := json.Marshal(map[string]interface{}{
"blocks": blocks,
"response_type": "ephemeral",
})
w.Header().Add("Content-Type", "application/json")
w.Write(resp)
}
func parseLeaderboardEntry(key string) (string, bool) {
re := regexp.MustCompile(`leaderboard:\d+-\d+:(\w+)`)
@ -180,3 +255,19 @@ func parseLeaderboardEntry(key string) (string, bool) {
}
return match[1], true
}
func parseEventEntry(key string) (event_name string, user_id string, ok bool) {
re := regexp.MustCompile(`event:(.+):(\w+)`)
match := re.FindStringSubmatch(key)
if match == nil {
ok = false
return
}
ok = true
event_name = match[1]
user_id = match[2]
return
}

View file

@ -36,6 +36,7 @@ func StartServer(config *Config) {
// Start receiving events
http.HandleFunc("/slack/events", handleSlackEvents)
http.HandleFunc("/slack/leaderboard", HandleLeaderboardSlashCommand)
http.HandleFunc("/slack/eventsCommand", HandleEventsSlashCommand)
http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", config.Port), nil)
}