package main import ( "fmt" "net/http" "strings" ) /* * General Message Processor * Handles general message stuff, stats, etc. */ type generalProcessor struct{} func (p *generalProcessor) GetName() string { return "stat_bot General Processor" } func (p *generalProcessor) GetHelp() string { return "" } func (p *generalProcessor) Initialize() {} func (p *generalProcessor) ProcessMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessBotMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessAdminMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessUserMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessAdminUserMessage(slack *Slack, m *Message) { // Check if we were mentioned if strings.HasPrefix(m.Text, "<@"+slack.id+">") { parts := strings.Fields(m.Text) var action, target string if len(parts) >= 2 { action = parts[1] if len(parts) >= 3 { target = parts[2] } } if action == "mkadmin" && target != "" { // Make a user an admin if strings.HasPrefix(target, "<@") && strings.HasSuffix(target, ">") { target = strings.Trim(target, "<@>") if e := addAdmin(target); e == nil { m.Text = "User <@" + target + "> has been made an admin" } else { m.Text = fmt.Sprintf("%s", e) } } else { m.Text = "Please specify an existing user starting with a '@'" } slack.postMessage(*m) } else if action == "rmadmin" && target != "" { // Revoke a user as an admin if strings.HasPrefix(target, "<@") && strings.HasSuffix(target, ">") { target = strings.Trim(target, "<@>") if e := removeAdmin(target); e == nil { m.Text = "Admin privileges revoked from <@" + target + ">" } else { m.Text = fmt.Sprintf("%s", e) } } else { m.Text = "Please specify an existing user starting with a '@'" } slack.postMessage(*m) } else { // huh? m.Text = fmt.Sprintf("Beep boop beep, that does not compute\n") slack.postMessage(*m) } } } func (p *generalProcessor) ProcessBotUserMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessChannelMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessAdminChannelMessage(slack *Slack, m *Message) {} func (p *generalProcessor) ProcessBotChannelMessage(slack *Slack, m *Message) {} /* *General Statistics Processor */ type generalStatProcessor struct{} func (p *generalStatProcessor) GetName() string { return "General Statistics" } func (p *generalStatProcessor) GetStatKeys() []string { return []string{ "bot-message", //"bot-reaction-*", "channel-message", //"channel-reaction-*", "message-hour-*", "message-dow-*", "message-dom-*", //"reaction-*-hour-*", //"reaction-*-dow-*", //"reaction-*-dom-*", } } func (p *generalStatProcessor) Initialize() {} func (p *generalStatProcessor) ProcessMessage(m *Message) { if m.Type == "message" { incrementUserStat(m.User, "message-hour-"+m.Time.Format("15")) incrementUserStat(m.User, "message-dow-"+m.Time.Format("Mon")) incrementUserStat(m.User, "message-dom-"+m.Time.Format("02")) //} else if m.Type == "reaction_added" { //incrementUserStat(m.User, "reaction-"+m.Name+"-hour-"+m.Time.Format("15")) //incrementUserStat(m.User, "reaction-"+m.Name+"-dow-"+m.Time.Format("Mon")) //incrementUserStat(m.User, "reaction-"+m.Name+"-dom-"+m.Time.Format("02")) } } func (p *generalStatProcessor) ProcessBotMessage(m *Message) {} func (p *generalStatProcessor) ProcessUserMessage(m *Message) { if m.Type == "message" { incrementUserStat(m.User, "bot-message") //} else if m.Type == "reaction_added" { // incrementUserStat(m.User, "bot-reaction-"+m.Name) } } func (p *generalStatProcessor) ProcessBotUserMessage(m *Message) {} func (p *generalStatProcessor) ProcessChannelMessage(m *Message) { if m.Type == "message" { incrementUserStat(m.User, "channel-message") incrementChannelStat(m.Channel, "message-hour-"+m.Time.Format("15")) incrementChannelStat(m.Channel, "message-dow-"+m.Time.Format("Mon")) incrementChannelStat(m.Channel, "message-dom-"+m.Time.Format("02")) //} else if m.Type == "reaction_added" { // incrementUserStat(m.User, "channel-reaction-"+m.Name) // incrementChannelStat(m.Channel, "reaction-"+m.Name+"-hour-"+m.Time.Format("15")) // incrementChannelStat(m.Channel, "reaction-"+m.Name+"-dow-"+m.Time.Format("Mon")) // incrementChannelStat(m.Channel, "reaction-"+m.Name+"-dom-"+m.Time.Format("02")) } } func (p *generalStatProcessor) ProcessBotChannelMessage(m *Message) {} /* * Web Site Module */ type generalWebModule struct{} func (wm *generalWebModule) GetName() string { return "General Web Module" } func (wm *generalWebModule) GetRoutes() map[string]func(http.ResponseWriter, *http.Request) { ret := make(map[string]func(http.ResponseWriter, *http.Request)) ret["/"] = wm.handleStats return ret } func (wm *generalWebModule) Register() { for k, v := range wm.GetRoutes() { r.HandleFunc(k, v) } } func (wm *generalWebModule) GetMenuEntries() []menuItem { var ret []menuItem ret = append(ret, menuItem{Text: "Stats", Link: "/"}) return ret } func (wm *generalWebModule) GetBottomMenuEntries() []menuItem { var ret []menuItem return ret } func (wm *generalWebModule) handleStats(w http.ResponseWriter, req *http.Request) { initRequest(w, req) type ChannelStats struct { Name string MemberCount int MessageCount int } type MessageStats struct { Hours map[int]int Dow map[string]int } type UserStats struct { Name string Hours map[int]int Dow map[string]int Messages int } type StatData struct { TotalChannelMessages int TotalChannels int ChannelStats []ChannelStats UserStats []UserStats MessageStats MessageStats Error string } // Get the global stats var s StatData var err error openDatabase() chanlst := getChannelList() userlst := getUserList() var chanstats []ChannelStats var userstats []UserStats s.MessageStats.Hours = make(map[int]int) for i := 0; i < 24; i++ { s.MessageStats.Hours[i] = 0 } s.MessageStats.Dow = make(map[string]int) for _, k := range []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} { s.MessageStats.Dow[k] = 0 } for _, k := range chanlst { chanstats = append(chanstats, ChannelStats{ Name: getChannelName(k), MemberCount: getChannelMemberCount(k), MessageCount: getChannelMessageCount(k), }) for i := 0; i < 24; i++ { if hrI, err := getChannelStat(k, fmt.Sprintf("message-hour-%02d", i)); err == nil { s.MessageStats.Hours[i] = s.MessageStats.Hours[i] + hrI } } for _, dow := range []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} { if dowI, err := getChannelStat(k, fmt.Sprintf("message-dow-%s", dow)); err == nil { s.MessageStats.Dow[dow] = s.MessageStats.Dow[dow] + dowI } } } for _, k := range userlst { usrName := getUserName(k) if usrName == "stat_bot" || usrName == "bot" { continue } usrHourStats := make(map[int]int) usrDowStats := make(map[string]int) var chanMsg int var err error if chanMsg, err = getUserStat(k, "channel-message"); err != nil { chanMsg = 0 } for i := 0; i < 24; i++ { if hrI, err := getUserStat(k, fmt.Sprintf("message-hour-%02d", i)); err == nil { usrHourStats[i] = hrI } else { usrHourStats[i] = 0 } } for _, dow := range []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} { if dowI, err := getUserStat(k, fmt.Sprintf("message-dow-%s", dow)); err == nil { usrDowStats[dow] = dowI } else { usrDowStats[dow] = 0 } } userstats = append(userstats, UserStats{ Name: usrName, Messages: chanMsg, Hours: usrHourStats, Dow: usrDowStats, }) } s.ChannelStats = chanstats s.UserStats = userstats s.TotalChannelMessages = getTotalChannelMsgCount() s.TotalChannels = len(chanlst) closeDatabase() sc := "var stats = {totalchannelmessages:" sc = fmt.Sprintf("%s%d,", sc, s.TotalChannelMessages) sc = sc + "channels:[" if len(s.ChannelStats) > 0 { for _, k := range s.ChannelStats { sc = fmt.Sprintf("%s{name:\"%s\",member_count:%d,message_count:%d},", sc, k.Name, k.MemberCount, k.MessageCount, ) } // Trim the last , sc = sc[:len(sc)-1] } sc = sc + "]," sc = sc + "users:[" if len(s.UserStats) > 0 { for _, usr := range s.UserStats { sc = fmt.Sprintf("%s{name:\"%s\",message_count:%d,", sc, usr.Name, usr.Messages, ) sc = sc + "messages:{" sc = sc + "hours:{" for i, k := range usr.Hours { sc = sc + fmt.Sprintf("%d:%d,", i, k) } sc = sc[:len(sc)-1] sc = sc + "}," sc = sc + "dow:{" for _, k := range []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} { sc = sc + fmt.Sprintf("%s:%d,", k, usr.Dow[k]) } sc = sc[:len(sc)-1] sc = sc + "}}" sc = sc + "}," } // Trim the last , sc = sc[:len(sc)-1] } sc = sc + "]," // Get all of the message stats sc = sc + "messages:{" sc = sc + "hours:{" for i, k := range s.MessageStats.Hours { sc = sc + fmt.Sprintf("%d:%d,", i, k) } sc = sc[:len(sc)-1] sc = sc + "}," sc = sc + "dow:{" for _, k := range []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} { sc = sc + fmt.Sprintf("%s:%d,", k, s.MessageStats.Dow[k]) } sc = sc[:len(sc)-1] sc = sc + "}}" sc = sc + "};" addToInlineScript(sc) site.Scripts = append(site.Scripts, "/assets/js/main_stats.js") if err != nil { setFlashMessage("Error Counting Channel Messages", "error") } site.TemplateData = s setMenuItemActive("Stats") showPage("stats.html", site, w) }