Skip to content

Commit

Permalink
Added new stats command
Browse files Browse the repository at this point in the history
  • Loading branch information
TheTipo01 committed Mar 27, 2021
1 parent e13c530 commit 71a52fb
Show file tree
Hide file tree
Showing 8 changed files with 473 additions and 27 deletions.
118 changes: 118 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"database/sql"
"fmt"
"github.com/bwmarrin/discordgo"
"github.com/bwmarrin/lit"
jsoniter "github.com/json-iterator/go"
)

var (
// Commands
commands = []*discordgo.ApplicationCommand{
{
Name: "stats",
Description: "Prints stats for a given channel, or if not specified for the entire server.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionChannel,
Name: "channel",
Description: "Optional channel to get stats for",
Required: false,
},
},
},
}

// Handler
commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
// Prints stats for a given channel, or if not specified for the entire server.
"stats": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
var (
mex *sql.Rows
err error
json = jsoniter.ConfigFastest
messageJSON, toSend string
m discordgo.Message
cont, authorNil int
words = make(map[string]int)
characters = make(map[string]int)
people = make(map[string]string)
messages = make(map[string]int)
charPerMex = make(map[string]int)
)

// If there's a specified channel, use it in the query
if len(i.Data.Options) > 0 {
mex, err = db.Query("SELECT message FROM messages WHERE guildID=? AND channelID=?", i.GuildID, i.Data.Options[0].ChannelValue(s).ID)
} else {
mex, err = db.Query("SELECT message FROM messages WHERE guildID=?", i.GuildID)
}
if err != nil {
lit.Error("Can't query database, %s", err)
return
}

for mex.Next() {
err = mex.Scan(&messageJSON)
if err != nil {
lit.Error("Can't scan m, %s", err)
return
}

err = json.Unmarshal([]byte(messageJSON), &m)
if err != nil {
lit.Error("Can't unmarshal JSON, %s", err)
continue
}

if m.Author != nil {
characters[m.Author.ID] += len(m.Content)
people[m.Author.ID] = m.Author.Username
words[m.Author.ID] += wordCount(m.Content)
messages[m.Author.ID]++
} else {
authorNil++
}
}

// Characters
toSend = ""
chr := sorting(characters)
for i, kv := range chr {
cont += kv.Value
toSend += fmt.Sprintf("%d) %s: %d\n", i+1, people[kv.Key], kv.Value)
charPerMex[kv.Key] = kv.Value / messages[kv.Key]
}
toSend = fmt.Sprintf("Number of characters sent: %d\n\n", cont) + toSend

sendEmbedInteraction(s, NewEmbed().SetTitle(s.State.User.Username).AddField("Characters", toSend).
SetColor(0x7289DA).MessageEmbed, i.Interaction)

// Characters per message
toSend = ""
cont = 0
for i, kv := range sorting(charPerMex) {
cont += kv.Value
toSend += fmt.Sprintf("%d) %s: %d\n", i+1, people[kv.Key], kv.Value)
}
toSend = fmt.Sprintf("Number of characters per message sent: %d\n\n", cont) + toSend

sendEmbedInteractionFollowup(s, NewEmbed().SetTitle(s.State.User.Username).AddField("Characters per message", toSend).
SetColor(0x7289DA).MessageEmbed, i.Interaction)

// Words
toSend = ""
cont = 0
for i, kv := range sorting(words) {
cont += kv.Value
toSend += fmt.Sprintf("%d) %s: %d\n", i+1, people[kv.Key], kv.Value)
}
toSend = fmt.Sprintf("Number of words: %d\n\n", cont) + toSend

sendEmbedInteractionFollowup(s, NewEmbed().SetTitle(s.State.User.Username).AddField("Words", toSend).
SetColor(0x7289DA).MessageEmbed, i.Interaction)
},
}
)
31 changes: 31 additions & 0 deletions commands_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"github.com/bwmarrin/discordgo"
"testing"
)

// Checks if for every commands there's a function to handle that
func TestCommands(t *testing.T) {
for _, c := range commands {
if commandHandlers[c.Name] == nil {
t.Errorf("Declared command %s in application command slice, but there's no handler.", c.Name)
}
}

for ch := range commandHandlers {
if !findCommandInCommandHandlers(commands, ch) {
t.Errorf("Declared command handler %s, but there's no command for it.", ch)
}
}
}

func findCommandInCommandHandlers(commands []*discordgo.ApplicationCommand, el string) bool {
for _, c := range commands {
if c.Name == el {
return true
}
}

return false
}
236 changes: 236 additions & 0 deletions embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
package main

import "github.com/bwmarrin/discordgo"

// Embed ...
type Embed struct {
*discordgo.MessageEmbed
}

// Constants for message embed character limits
const (
EmbedLimitTitle = 256
EmbedLimitDescription = 2048
EmbedLimitFieldValue = 1024
EmbedLimitFieldName = 256
EmbedLimitField = 25
EmbedLimitFooter = 2048
EmbedLimit = 4000
)

// NewEmbed returns a new embed object
func NewEmbed() *Embed {
return &Embed{&discordgo.MessageEmbed{}}
}

// SetTitle ...
func (e *Embed) SetTitle(name string) *Embed {
e.Title = name
return e
}

// SetDescription [desc]
func (e *Embed) SetDescription(description string) *Embed {
if len(description) > 2048 {
description = description[:2048]
}
e.Description = description
return e
}

// AddField [name] [value]
func (e *Embed) AddField(name, value string) *Embed {
if len(value) > 1024 {
value = value[:1024]
}

if len(name) > 1024 {
name = name[:1024]
}

e.Fields = append(e.Fields, &discordgo.MessageEmbedField{
Name: name,
Value: value,
})

return e

}

// SetFooter [Text] [iconURL]
func (e *Embed) SetFooter(args ...string) *Embed {
iconURL := ""
text := ""
proxyURL := ""

switch {
case len(args) > 2:
proxyURL = args[2]
fallthrough
case len(args) > 1:
iconURL = args[1]
fallthrough
case len(args) > 0:
text = args[0]
case len(args) == 0:
return e
}

e.Footer = &discordgo.MessageEmbedFooter{
IconURL: iconURL,
Text: text,
ProxyIconURL: proxyURL,
}

return e
}

// SetImage ...
func (e *Embed) SetImage(args ...string) *Embed {
var URL string
var proxyURL string

if len(args) == 0 {
return e
}
if len(args) > 0 {
URL = args[0]
}
if len(args) > 1 {
proxyURL = args[1]
}
e.Image = &discordgo.MessageEmbedImage{
URL: URL,
ProxyURL: proxyURL,
}
return e
}

// SetThumbnail ...
func (e *Embed) SetThumbnail(args ...string) *Embed {
var URL string
var proxyURL string

if len(args) == 0 {
return e
}
if len(args) > 0 {
URL = args[0]
}
if len(args) > 1 {
proxyURL = args[1]
}
e.Thumbnail = &discordgo.MessageEmbedThumbnail{
URL: URL,
ProxyURL: proxyURL,
}
return e
}

// SetAuthor ...
func (e *Embed) SetAuthor(args ...string) *Embed {
var (
name string
iconURL string
URL string
proxyURL string
)

if len(args) == 0 {
return e
}
if len(args) > 0 {
name = args[0]
}
if len(args) > 1 {
iconURL = args[1]
}
if len(args) > 2 {
URL = args[2]
}
if len(args) > 3 {
proxyURL = args[3]
}

e.Author = &discordgo.MessageEmbedAuthor{
Name: name,
IconURL: iconURL,
URL: URL,
ProxyIconURL: proxyURL,
}

return e
}

// SetURL ...
func (e *Embed) SetURL(url string) *Embed {
e.URL = url
return e
}

// SetColor ...
func (e *Embed) SetColor(clr int) *Embed {
e.Color = clr
return e
}

// InlineAllFields sets all fields in the embed to be inline
func (e *Embed) InlineAllFields() *Embed {
for _, v := range e.Fields {
v.Inline = true
}
return e
}

// Truncate truncates any embed value over the character limit.
func (e *Embed) Truncate() *Embed {
e.TruncateDescription()
e.TruncateFields()
e.TruncateFooter()
e.TruncateTitle()
return e
}

// TruncateFields truncates fields that are too long
func (e *Embed) TruncateFields() *Embed {
if len(e.Fields) > 25 {
e.Fields = e.Fields[:EmbedLimitField]
}

for _, v := range e.Fields {

if len(v.Name) > EmbedLimitFieldName {
v.Name = v.Name[:EmbedLimitFieldName]
}

if len(v.Value) > EmbedLimitFieldValue {
v.Value = v.Value[:EmbedLimitFieldValue]
}

}
return e
}

// TruncateDescription ...
func (e *Embed) TruncateDescription() *Embed {
if len(e.Description) > EmbedLimitDescription {
e.Description = e.Description[:EmbedLimitDescription]
}
return e
}

// TruncateTitle ...
func (e *Embed) TruncateTitle() *Embed {
if len(e.Title) > EmbedLimitTitle {
e.Title = e.Title[:EmbedLimitTitle]
}
return e
}

// TruncateFooter ...
func (e *Embed) TruncateFooter() *Embed {
if e.Footer != nil && len(e.Footer.Text) > EmbedLimitFooter {
e.Footer.Text = e.Footer.Text[:EmbedLimitFooter]
}
return e
}
Loading

0 comments on commit 71a52fb

Please sign in to comment.