2015-10-29 16:16:25 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-11-02 19:48:29 +00:00
|
|
|
"net/http"
|
2015-10-29 16:16:25 +00:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* General Message Processor
|
|
|
|
*/
|
|
|
|
type generalProcessor struct{}
|
|
|
|
|
|
|
|
func (p *generalProcessor) GetName() string {
|
|
|
|
return "stat_bot General Processor"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *generalProcessor) GetHelp() string {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *generalProcessor) ProcessMessage(slack *Slack, m *Message) {}
|
2015-10-29 19:16:45 +00:00
|
|
|
func (p *generalProcessor) ProcessBotMessage(slack *Slack, m *Message) {}
|
|
|
|
func (p *generalProcessor) ProcessAdminMessage(slack *Slack, m *Message) {}
|
2015-10-29 16:16:25 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-29 19:16:45 +00:00
|
|
|
func (p *generalProcessor) ProcessBotUserMessage(slack *Slack, m *Message) {}
|
2015-10-29 16:16:25 +00:00
|
|
|
|
|
|
|
func (p *generalProcessor) ProcessChannelMessage(slack *Slack, m *Message) {}
|
|
|
|
func (p *generalProcessor) ProcessAdminChannelMessage(slack *Slack, m *Message) {}
|
2015-10-29 19:16:45 +00:00
|
|
|
func (p *generalProcessor) ProcessBotChannelMessage(slack *Slack, m *Message) {}
|
2015-10-29 16:16:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*General Statistics Processor
|
|
|
|
*/
|
|
|
|
type generalStatProcessor struct{}
|
|
|
|
|
|
|
|
func (p *generalStatProcessor) GetName() string {
|
|
|
|
return "General Statistics"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *generalStatProcessor) GetStatKeys() []string {
|
|
|
|
return []string{
|
|
|
|
"bot-message",
|
2015-11-05 12:55:49 +00:00
|
|
|
//"bot-reaction-*",
|
2015-10-29 16:16:25 +00:00
|
|
|
"channel-message",
|
2015-11-05 12:55:49 +00:00
|
|
|
//"channel-reaction-*",
|
2015-10-29 16:16:25 +00:00
|
|
|
"message-hour-*",
|
|
|
|
"message-dow-*",
|
|
|
|
"message-dom-*",
|
2015-11-05 12:55:49 +00:00
|
|
|
//"reaction-*-hour-*",
|
|
|
|
//"reaction-*-dow-*",
|
|
|
|
//"reaction-*-dom-*",
|
2015-10-29 16:16:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *generalStatProcessor) ProcessMessage(m *Message) {
|
2015-11-05 12:55:49 +00:00
|
|
|
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"))
|
|
|
|
}
|
2015-10-29 16:16:25 +00:00
|
|
|
}
|
2015-10-29 19:16:45 +00:00
|
|
|
func (p *generalStatProcessor) ProcessBotMessage(m *Message) {}
|
2015-10-29 16:16:25 +00:00
|
|
|
|
|
|
|
func (p *generalStatProcessor) ProcessUserMessage(m *Message) {
|
2015-11-05 12:55:49 +00:00
|
|
|
if m.Type == "message" {
|
|
|
|
incrementUserStat(m.User, "bot-message")
|
|
|
|
//} else if m.Type == "reaction_added" {
|
|
|
|
// incrementUserStat(m.User, "bot-reaction-"+m.Name)
|
|
|
|
}
|
2015-10-29 16:16:25 +00:00
|
|
|
}
|
2015-10-29 19:16:45 +00:00
|
|
|
func (p *generalStatProcessor) ProcessBotUserMessage(m *Message) {}
|
2015-10-29 16:16:25 +00:00
|
|
|
|
|
|
|
func (p *generalStatProcessor) ProcessChannelMessage(m *Message) {
|
2015-11-05 12:55:49 +00:00
|
|
|
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)
|
2015-10-29 16:16:25 +00:00
|
|
|
|
2015-11-05 12:55:49 +00:00
|
|
|
// 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"))
|
|
|
|
}
|
2015-10-29 16:16:25 +00:00
|
|
|
}
|
2015-10-29 19:16:45 +00:00
|
|
|
func (p *generalStatProcessor) ProcessBotChannelMessage(m *Message) {}
|
2015-11-02 19:48:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
|
2015-11-05 12:55:49 +00:00
|
|
|
type ChannelStats struct {
|
2015-11-02 19:48:29 +00:00
|
|
|
Name string
|
|
|
|
MemberCount int
|
|
|
|
MessageCount int
|
|
|
|
}
|
2015-11-05 12:55:49 +00:00
|
|
|
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
|
|
|
|
}
|
2015-11-02 19:48:29 +00:00
|
|
|
type StatData struct {
|
|
|
|
TotalChannelMessages int
|
|
|
|
TotalChannels int
|
2015-11-05 12:55:49 +00:00
|
|
|
ChannelStats []ChannelStats
|
|
|
|
UserStats []UserStats
|
|
|
|
MessageStats MessageStats
|
2015-11-02 19:48:29 +00:00
|
|
|
Error string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the global stats
|
|
|
|
var s StatData
|
|
|
|
var err error
|
|
|
|
|
|
|
|
openDatabase()
|
|
|
|
chanlst := getChannelList()
|
2015-11-05 12:55:49 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-11-02 19:48:29 +00:00
|
|
|
for _, k := range chanlst {
|
2015-11-05 12:55:49 +00:00
|
|
|
chanstats = append(chanstats, ChannelStats{
|
2015-11-02 19:48:29 +00:00
|
|
|
Name: getChannelName(k),
|
|
|
|
MemberCount: getChannelMemberCount(k),
|
|
|
|
MessageCount: getChannelMessageCount(k),
|
|
|
|
})
|
2015-11-05 12:55:49 +00:00
|
|
|
for i := 0; i < 24; i++ {
|
|
|
|
if hrI, err := getChannelStat(k, fmt.Sprintf("message-hour-%0d", 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-%0d", 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,
|
|
|
|
})
|
2015-11-02 19:48:29 +00:00
|
|
|
}
|
2015-11-05 12:55:49 +00:00
|
|
|
|
2015-11-02 19:48:29 +00:00
|
|
|
s.ChannelStats = chanstats
|
2015-11-05 12:55:49 +00:00
|
|
|
s.UserStats = userstats
|
2015-11-02 19:48:29 +00:00
|
|
|
s.TotalChannelMessages = getTotalChannelMsgCount()
|
|
|
|
s.TotalChannels = len(chanlst)
|
2015-11-05 12:55:49 +00:00
|
|
|
|
2015-11-02 19:48:29 +00:00
|
|
|
closeDatabase()
|
|
|
|
|
|
|
|
sc := "var stats = {totalchannelmessages:"
|
|
|
|
sc = fmt.Sprintf("%s%d,", sc, s.TotalChannelMessages)
|
2015-11-05 12:55:49 +00:00
|
|
|
sc = sc + "channels:["
|
2015-11-06 01:36:09 +00:00
|
|
|
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]
|
2015-11-02 19:48:29 +00:00
|
|
|
}
|
2015-11-05 12:55:49 +00:00
|
|
|
sc = sc + "],"
|
|
|
|
sc = sc + "users:["
|
2015-11-06 01:36:09 +00:00
|
|
|
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 + "},"
|
2015-11-05 12:55:49 +00:00
|
|
|
}
|
2015-11-06 01:36:09 +00:00
|
|
|
// Trim the last ,
|
2015-11-05 12:55:49 +00:00
|
|
|
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 + "}}"
|
2015-11-02 19:48:29 +00:00
|
|
|
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)
|
|
|
|
}
|