Compare commits

..

3 Commits

Author SHA1 Message Date
Chris Sexton 00dae33e8a achievements: refactor
Refs #346
2021-01-31 22:17:59 -05:00
Chris Sexton e7ec092c64 counter: update tests 2021-01-31 21:53:48 -05:00
Chris Sexton 1292eaa564 counter: refactor into regex matchers 2021-01-31 21:53:48 -05:00
5 changed files with 449 additions and 410 deletions

View File

@ -41,7 +41,7 @@ RET:
return true return true
} }
func parseValues(r *regexp.Regexp, body string) RegexValues { func ParseValues(r *regexp.Regexp, body string) RegexValues {
out := RegexValues{} out := RegexValues{}
subs := r.FindStringSubmatch(body) subs := r.FindStringSubmatch(body)
if len(subs) == 0 { if len(subs) == 0 {
@ -62,7 +62,7 @@ func (b *bot) runCallback(conn Connector, plugin Plugin, evt Kind, message msg.M
Conn: conn, Conn: conn,
Kind: evt, Kind: evt,
Msg: message, Msg: message,
Values: parseValues(r, message.Body), Values: ParseValues(r, message.Body),
Args: args, Args: args,
} }
if cb(resp) { if cb(resp) {

View File

@ -31,7 +31,11 @@ func New(b bot.Bot) *AchievementsPlugin {
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("unable to create achievements tables") log.Fatal().Err(err).Msg("unable to create achievements tables")
} }
b.Register(ap, bot.Message, ap.message)
b.RegisterRegexCmd(ap, bot.Message, grantRegex, ap.grantCmd)
b.RegisterRegexCmd(ap, bot.Message, createRegex, ap.createCmd)
b.RegisterRegexCmd(ap, bot.Message, greatRegex, ap.greatCmd)
b.Register(ap, bot.Help, ap.help) b.Register(ap, bot.Help, ap.help)
return ap return ap
} }
@ -80,12 +84,55 @@ var grantRegex = regexp.MustCompile(`(?i)grant (?P<emojy>(?::[[:word:][:punct:]]
var createRegex = regexp.MustCompile(`(?i)create trophy (?P<emojy>(?::[[:word:][:punct:]]+:\s?)+) (?P<description>.+)`) var createRegex = regexp.MustCompile(`(?i)create trophy (?P<emojy>(?::[[:word:][:punct:]]+:\s?)+) (?P<description>.+)`)
var greatRegex = regexp.MustCompile(`(?i)how great (?:am i|is :?(?P<who>[[:word:]]+))[[:punct:]]*`) var greatRegex = regexp.MustCompile(`(?i)how great (?:am i|is :?(?P<who>[[:word:]]+))[[:punct:]]*`)
func (p *AchievementsPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { func (p *AchievementsPlugin) grantCmd(r bot.Request) bool {
nick := message.User.Name nick := r.Msg.User.Name
emojy := r.Values["emojy"]
receiver := r.Values["nick"]
trophy, err := p.FindTrophy(emojy)
if err != nil {
log.Error().Err(err).Msg("could not find trophy")
msg := fmt.Sprintf("The %s award doesn't exist.", emojy)
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, msg)
return true
}
if nick == trophy.Creator {
a, err := p.Grant(receiver, emojy)
if err != nil {
log.Error().Err(err).Msg("could not award trophy")
}
msg := fmt.Sprintf("Congrats %s. You just got the %s award for %s.",
receiver, emojy, a.Description)
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, msg)
} else {
msg := fmt.Sprintf("Sorry, %s. %s owns that trophy.", nick, trophy.Creator)
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, msg)
}
return true
}
if greatRegex.MatchString(message.Body) { func (p *AchievementsPlugin) createCmd(r bot.Request) bool {
submatches := greatRegex.FindAllStringSubmatch(message.Body, -1) nick := r.Msg.User.Name
who := submatches[0][1] emojy := r.Values["emojy"]
description := r.Values["description"]
t, err := p.Create(emojy, description, nick)
if err != nil {
log.Error().Err(err).Msg("could not create trophy")
if strings.Contains(err.Error(), "exists") {
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, err.Error())
return true
}
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, "I'm too humble to ever award that trophy")
return true
}
resp := fmt.Sprintf("Okay %s. I have crafted a one-of-a-kind %s trophy to give for %s",
nick, t.Emojy, t.Description)
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, resp)
return true
}
func (p *AchievementsPlugin) greatCmd(r bot.Request) bool {
nick := r.Msg.User.Name
who := r.Values["who"]
if who == "" { if who == "" {
who = nick who = nick
} }
@ -96,61 +143,15 @@ func (p *AchievementsPlugin) message(c bot.Connector, kind bot.Kind, message msg
m = fmt.Sprintf("You have no achievements to your name. "+ m = fmt.Sprintf("You have no achievements to your name. "+
"You are a sad and terrible specimen of the human condition, %s.", who) "You are a sad and terrible specimen of the human condition, %s.", who)
} }
p.bot.Send(c, bot.Message, message.Channel, m) p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, m)
} else { } else {
m := fmt.Sprintf("Wow, let's all clap for %s. Look at these awards:", who) m := fmt.Sprintf("Wow, let's all clap for %s. Look at these awards:", who)
for _, a := range awards { for _, a := range awards {
m += fmt.Sprintf("\n%s - %s", a.Emojy, a.Description) m += fmt.Sprintf("\n%s - %s", a.Emojy, a.Description)
} }
p.bot.Send(c, bot.Message, message.Channel, m) p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, m)
} }
return true return true
}
if message.Command && grantRegex.MatchString(message.Body) {
submatches := grantRegex.FindAllStringSubmatch(message.Body, -1)
emojy := submatches[0][1]
receiver := submatches[0][2]
trophy, err := p.FindTrophy(emojy)
if err != nil {
log.Error().Err(err).Msg("could not find trophy")
msg := fmt.Sprintf("The %s award doesn't exist.", emojy)
p.bot.Send(c, bot.Message, message.Channel, msg)
return true
}
if nick == trophy.Creator {
a, err := p.Grant(receiver, emojy)
if err != nil {
log.Error().Err(err).Msg("could not award trophy")
}
msg := fmt.Sprintf("Congrats %s. You just got the %s award for %s.",
receiver, emojy, a.Description)
p.bot.Send(c, bot.Message, message.Channel, msg)
} else {
msg := fmt.Sprintf("Sorry, %s. %s owns that trophy.", nick, trophy.Creator)
p.bot.Send(c, bot.Message, message.Channel, msg)
}
return true
}
if message.Command && createRegex.MatchString(message.Body) {
submatches := createRegex.FindAllStringSubmatch(message.Body, -1)
emojy := submatches[0][1]
description := submatches[0][2]
t, err := p.Create(emojy, description, nick)
if err != nil {
log.Error().Err(err).Msg("could not create trophy")
if strings.Contains(err.Error(), "exists") {
p.bot.Send(c, bot.Message, message.Channel, err.Error())
return true
}
p.bot.Send(c, bot.Message, message.Channel, "I'm too humble to ever award that trophy")
return true
}
resp := fmt.Sprintf("Okay %s. I have crafted a one-of-a-kind %s trophy to give for %s",
nick, t.Emojy, t.Description)
p.bot.Send(c, bot.Message, message.Channel, resp)
return true
}
return false
} }
func (p *AchievementsPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { func (p *AchievementsPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {

View File

@ -1 +0,0 @@
package achievements

View File

@ -20,8 +20,6 @@ import (
// This is a counter plugin to count arbitrary things. // This is a counter plugin to count arbitrary things.
var teaMatcher = regexp.MustCompile("(?i)^([^.]+)\\. [^.]*\\. ([^.]*\\.?)+$")
type CounterPlugin struct { type CounterPlugin struct {
Bot bot.Bot Bot bot.Bot
DB *sqlx.DB DB *sqlx.DB
@ -262,7 +260,20 @@ func New(b bot.Bot) *CounterPlugin {
Bot: b, Bot: b,
DB: b.DB(), DB: b.DB(),
} }
b.Register(cp, bot.Message, cp.message)
b.RegisterRegexCmd(cp, bot.Message, mkAliasRegex, cp.mkAliasCmd)
b.RegisterRegexCmd(cp, bot.Message, rmAliasRegex, cp.rmAliasCmd)
b.RegisterRegexCmd(cp, bot.Message, leaderboardRegex, cp.leaderboardCmd)
b.RegisterRegex(cp, bot.Message, teaRegex, cp.teaMatchCmd)
b.RegisterRegexCmd(cp, bot.Message, resetRegex, cp.resetCmd)
b.RegisterRegexCmd(cp, bot.Message, inspectRegex, cp.inspectCmd)
b.RegisterRegexCmd(cp, bot.Message, clearRegex, cp.clearCmd)
b.RegisterRegexCmd(cp, bot.Message, countRegex, cp.countCmd)
b.RegisterRegex(cp, bot.Message, incrementRegex, cp.incrementCmd)
b.RegisterRegex(cp, bot.Message, decrementRegex, cp.decrementCmd)
b.RegisterRegex(cp, bot.Message, addToRegex, cp.addToCmd)
b.RegisterRegex(cp, bot.Message, removeFromRegex, cp.removeFromCmd)
b.Register(cp, bot.Help, cp.help) b.Register(cp, bot.Help, cp.help)
cp.registerWeb() cp.registerWeb()
@ -273,46 +284,61 @@ func trimUnicode(s string) string {
return strings.Trim(s, string(rune(0xFE0F))) return strings.Trim(s, string(rune(0xFE0F)))
} }
// Message responds to the bot hook on recieving messages. var mkAliasRegex = regexp.MustCompile(`(?i)^mkalias (?P<what>\S+) (?P<to>\S+)$`)
// This function returns true if the plugin responds in a meaningful way to the var rmAliasRegex = regexp.MustCompile(`(?i)^rmalias (?P<what>\S+)$`)
// users message. Otherwise, the function returns false and the bot continues var leaderboardRegex = regexp.MustCompile(`(?i)^leaderboard\s?(?P<what>\S+)?$`)
// execution of other plugins. var teaRegex = regexp.MustCompile("(?i)^([^.]+)\\. [^.]*\\. ([^.]*\\.?)+$")
func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { var resetRegex = regexp.MustCompile(`(?i)^reset me$`)
// This bot does not reply to anything var inspectRegex = regexp.MustCompile(`(?i)^inspect (?P<who>\S+)$`)
nick := message.User.Name var clearRegex = regexp.MustCompile(`(?i)^clear (?P<what>\S+)$`)
channel := message.Channel var countRegex = regexp.MustCompile(`(?i)^count (?P<who>\S+)\s?(?P<what>\S+)?$`)
parts := strings.Fields(message.Body) var incrementRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s?\+\+$`)
var decrementRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s?--$`)
var addToRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s+\+=\s+(?P<amount>\d+)$`)
var removeFromRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s+-=\s+(?P<amount>\d+)$`)
if len(parts) == 0 { func (p *CounterPlugin) mkAliasCmd(r bot.Request) bool {
return false what := r.Values["what"]
to := r.Values["to"]
if what == "" || to == "" {
p.Bot.Send(r.Conn, bot.Message, fmt.Sprintf("You must provide all fields for an alias: %s", mkAliasRegex))
return true
} }
if _, err := MkAlias(p.DB, what, to); err != nil {
if len(parts) == 3 && strings.ToLower(parts[0]) == "mkalias" {
if _, err := MkAlias(p.DB, parts[1], parts[2]); err != nil {
log.Error().Err(err).Msg("Could not mkalias") log.Error().Err(err).Msg("Could not mkalias")
p.Bot.Send(c, bot.Message, channel, "We're gonna need too much DB space to make an alias for your mom.") p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "We're gonna need too much DB space to make an alias for your mom.")
return true return true
} }
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("Created alias %s -> %s", p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("Created alias %s -> %s",
parts[1], parts[2])) what, to))
return true return true
} else if len(parts) == 2 && strings.ToLower(parts[0]) == "rmalias" { }
if err := RmAlias(p.DB, parts[1]); err != nil {
func (p *CounterPlugin) rmAliasCmd(r bot.Request) bool {
what := r.Values["what"]
if what == "" {
p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "You must specify an alias to remove.")
return true
}
if err := RmAlias(p.DB, what); err != nil {
log.Error().Err(err).Msg("could not RmAlias") log.Error().Err(err).Msg("could not RmAlias")
p.Bot.Send(c, bot.Message, channel, "`sudo rm your mom` => Nope, she's staying with me.") p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "`sudo rm your mom` => Nope, she's staying with me.")
return true return true
} }
p.Bot.Send(c, bot.Message, channel, "`sudo rm your mom`") p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "`sudo rm your mom`")
return true return true
} else if strings.ToLower(parts[0]) == "leaderboard" { }
func (p *CounterPlugin) leaderboardCmd(r bot.Request) bool {
var cmd func() ([]Item, error) var cmd func() ([]Item, error)
itNameTxt := "" itNameTxt := ""
what := r.Values["what"]
if len(parts) == 1 { if what == "" {
cmd = func() ([]Item, error) { return LeaderAll(p.DB) } cmd = func() ([]Item, error) { return LeaderAll(p.DB) }
} else { } else {
itNameTxt = fmt.Sprintf(" for %s", parts[1]) itNameTxt = fmt.Sprintf(" for %s", what)
cmd = func() ([]Item, error) { return Leader(p.DB, parts[1]) } cmd = func() ([]Item, error) { return Leader(p.DB, what) }
} }
its, err := cmd() its, err := cmd()
@ -320,7 +346,8 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
log.Error().Err(err).Msg("Error with leaderboard") log.Error().Err(err).Msg("Error with leaderboard")
return false return false
} else if len(its) == 0 { } else if len(its) == 0 {
return false p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "There are not enough entries for a leaderboard.")
return true
} }
out := fmt.Sprintf("Leaderboard%s:\n", itNameTxt) out := fmt.Sprintf("Leaderboard%s:\n", itNameTxt)
@ -331,34 +358,41 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
it.Item, it.Item,
) )
} }
p.Bot.Send(c, bot.Message, channel, out) p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, out)
return true return true
} else if match := teaMatcher.MatchString(message.Body); match { }
// check for tea match TTT
return p.checkMatch(c, message) func (p *CounterPlugin) resetCmd(r bot.Request) bool {
} else if message.Command && message.Body == "reset me" { nick := r.Msg.User.Name
channel := r.Msg.Channel
items, err := GetItems(p.DB, strings.ToLower(nick)) items, err := GetItems(p.DB, strings.ToLower(nick))
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Str("nick", nick). Str("nick", nick).
Msg("Error getting items to reset") Msg("Error getting items to reset")
p.Bot.Send(c, bot.Message, channel, "Something is technically wrong with your counters.") p.Bot.Send(r.Conn, bot.Message, channel, "Something is technically wrong with your counters.")
return true return true
} }
log.Debug().Msgf("Items: %+v", items) log.Debug().Msgf("Items: %+v", items)
for _, item := range items { for _, item := range items {
item.Delete() item.Delete()
} }
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick)) p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick))
return true return true
} else if message.Command && parts[0] == "inspect" && len(parts) == 2 { }
var subject string
if parts[1] == "me" { func (p *CounterPlugin) inspectCmd(r bot.Request) bool {
subject = strings.ToLower(nick) var subject string
subject = r.Values["who"]
channel := r.Msg.Channel
c := r.Conn
if subject == "me" {
subject = strings.ToLower(r.Msg.User.Name)
} else { } else {
subject = strings.ToLower(parts[1]) subject = strings.ToLower(subject)
} }
log.Debug(). log.Debug().
@ -397,9 +431,13 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
p.Bot.Send(c, bot.Message, channel, resp) p.Bot.Send(c, bot.Message, channel, resp)
return true return true
} else if message.Command && len(parts) == 2 && parts[0] == "clear" { }
subject := strings.ToLower(nick)
itemName := strings.ToLower(parts[1]) func (p *CounterPlugin) clearCmd(r bot.Request) bool {
subject := strings.ToLower(r.Msg.User.Name)
itemName := strings.ToLower(r.Values["what"])
channel := r.Msg.Channel
c := r.Conn
it, err := GetUserItem(p.DB, subject, itemName) it, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -425,27 +463,27 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
p.Bot.Send(c, bot.Action, channel, fmt.Sprintf("chops a few %s out of his brain", p.Bot.Send(c, bot.Action, channel, fmt.Sprintf("chops a few %s out of his brain",
itemName)) itemName))
return true return true
}
} else if message.Command && parts[0] == "count" { func (p *CounterPlugin) countCmd(r bot.Request) bool {
var subject string var subject string
var itemName string var itemName string
if len(parts) == 3 { if r.Values["what"] == "" && r.Values["who"] == "" {
// report count for parts[1]
subject = strings.ToLower(parts[1])
itemName = strings.ToLower(parts[2])
} else if len(parts) == 2 {
subject = strings.ToLower(nick)
itemName = strings.ToLower(parts[1])
} else {
return false return false
} else if r.Values["what"] != "" {
subject = strings.ToLower(r.Values["who"])
itemName = strings.ToLower(r.Values["what"])
} else {
subject = strings.ToLower(r.Msg.User.Name)
itemName = strings.ToLower(r.Values["who"])
} }
var item Item var item Item
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.", p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("I don't think %s has any %s.",
subject, itemName)) subject, itemName))
return true return true
case err != nil: case err != nil:
@ -457,28 +495,19 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
return true return true
} }
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("%s has %d %s.", subject, item.Count,
itemName)) itemName))
return true return true
} else if len(parts) <= 2 { }
if (len(parts) == 2) && (parts[1] == "++" || parts[1] == "--") {
parts = []string{parts[0] + parts[1]}
}
// Need to have at least 3 characters to ++ or --
if len(parts[0]) < 3 {
return false
}
subject := strings.ToLower(nick) func (p *CounterPlugin) incrementCmd(r bot.Request) bool {
itemName := strings.ToLower(parts[0])[:len(parts[0])-2] subject := r.Msg.User.Name
if r.Values["who"] != "" {
if nameParts := strings.SplitN(itemName, ".", 2); len(nameParts) == 2 { subject = strings.TrimSuffix(r.Values["who"], ".")
subject = nameParts[0]
itemName = nameParts[1]
} }
itemName := r.Values["thing"]
if strings.HasSuffix(parts[0], "++") { channel := r.Msg.Channel
// ++ those fuckers // ++ those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -492,10 +521,18 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
} }
log.Debug().Msgf("About to update item: %#v", item) log.Debug().Msgf("About to update item: %#v", item)
item.UpdateDelta(1) item.UpdateDelta(1)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} else if strings.HasSuffix(parts[0], "--") { }
func (p *CounterPlugin) decrementCmd(r bot.Request) bool {
subject := r.Msg.User.Name
if r.Values["who"] != "" {
subject = strings.TrimSuffix(r.Values["who"], ".")
}
itemName := r.Values["thing"]
channel := r.Msg.Channel
// -- those fuckers // -- those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -508,25 +545,18 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
return false return false
} }
item.UpdateDelta(-1) item.UpdateDelta(-1)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} }
} else if len(parts) == 3 {
// Need to have at least 3 characters to ++ or --
if len(parts[0]) < 3 {
return false
}
subject := strings.ToLower(nick) func (p *CounterPlugin) addToCmd(r bot.Request) bool {
itemName := strings.ToLower(parts[0]) subject := r.Msg.User.Name
if r.Values["who"] != "" {
if nameParts := strings.SplitN(itemName, ".", 2); len(nameParts) == 2 { subject = strings.TrimSuffix(r.Values["who"], ".")
subject = nameParts[0]
itemName = nameParts[1]
} }
itemName := r.Values["thing"]
if parts[1] == "+=" { channel := r.Msg.Channel
// += those fuckers // += those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -538,13 +568,21 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
// Item ain't there, I guess // Item ain't there, I guess
return false return false
} }
n, _ := strconv.Atoi(parts[2]) n, _ := strconv.Atoi(r.Values["amount"])
log.Debug().Msgf("About to update item by %d: %#v", n, item) log.Debug().Msgf("About to update item by %d: %#v", n, item)
item.UpdateDelta(n) item.UpdateDelta(n)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} else if parts[1] == "-=" { }
func (p *CounterPlugin) removeFromCmd(r bot.Request) bool {
subject := r.Msg.User.Name
if r.Values["who"] != "" {
subject = strings.TrimSuffix(r.Values["who"], ".")
}
itemName := r.Values["thing"]
channel := r.Msg.Channel
// -= those fuckers // -= those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -556,16 +594,12 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
// Item ain't there, I guess // Item ain't there, I guess
return false return false
} }
n, _ := strconv.Atoi(parts[2]) n, _ := strconv.Atoi(r.Values["amount"])
log.Debug().Msgf("About to update item by -%d: %#v", n, item) log.Debug().Msgf("About to update item by -%d: %#v", n, item)
item.UpdateDelta(-n) item.UpdateDelta(-n)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
}
}
return false
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
@ -579,11 +613,11 @@ func (p *CounterPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message
return true return true
} }
func (p *CounterPlugin) checkMatch(c bot.Connector, message msg.Message) bool { func (p *CounterPlugin) teaMatchCmd(r bot.Request) bool {
nick := message.User.Name nick := r.Msg.User.Name
channel := message.Channel channel := r.Msg.Channel
submatches := teaMatcher.FindStringSubmatch(message.Body) submatches := teaRegex.FindStringSubmatch(r.Msg.Body)
if len(submatches) <= 1 { if len(submatches) <= 1 {
return false return false
} }
@ -605,7 +639,7 @@ func (p *CounterPlugin) checkMatch(c bot.Connector, message msg.Message) bool {
delta = -1 delta = -1
} }
item.UpdateDelta(delta) item.UpdateDelta(delta)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s... %s has %d %s", p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s... %s has %d %s",
strings.Join(everyDayImShuffling([]string{"bleep", "bloop", "blop"}), "-"), nick, item.Count, itemName)) strings.Join(everyDayImShuffling([]string{"bleep", "bloop", "blop"}), "-"), nick, item.Count, itemName))
return true return true
} }

View File

@ -4,6 +4,7 @@ package counter
import ( import (
"fmt" "fmt"
"regexp"
"strings" "strings"
"testing" "testing"
@ -25,24 +26,28 @@ func setup(t *testing.T) (*bot.MockBot, *CounterPlugin) {
return mb, c return mb, c
} }
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { func makeMessage(payload string, r *regexp.Regexp) bot.Request {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return &cli.CliPlugin{}, bot.Message, msg.Message{ values := bot.ParseValues(r, payload)
return bot.Request{
Conn: nil,
Msg: msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test",
Body: payload, Body: payload,
Command: isCmd, Command: isCmd,
},
Values: values,
} }
} }
func TestMkAlias(t *testing.T) { func TestMkAlias(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("mkalias fuck mornings")) c.mkAliasCmd(makeMessage("mkalias fuck mornings", mkAliasRegex))
c.message(makeMessage("fuck++")) c.incrementCmd(makeMessage("fuck++", incrementRegex))
item, err := GetUserItem(mb.DB(), "tester", "mornings") item, err := GetUserItem(mb.DB(), "tester", "mornings")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, item.Count) assert.Equal(t, 1, item.Count)
@ -51,9 +56,9 @@ func TestMkAlias(t *testing.T) {
func TestRmAlias(t *testing.T) { func TestRmAlias(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("mkalias fuck mornings")) c.mkAliasCmd(makeMessage("mkalias fuck mornings", mkAliasRegex))
c.message(makeMessage("rmalias fuck")) c.rmAliasCmd(makeMessage("rmalias fuck", rmAliasRegex))
c.message(makeMessage("fuck++")) c.incrementCmd(makeMessage("fuck++", incrementRegex))
item, err := GetUserItem(mb.DB(), "tester", "mornings") item, err := GetUserItem(mb.DB(), "tester", "mornings")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -62,8 +67,8 @@ func TestRmAlias(t *testing.T) {
func TestThreeSentencesExists(t *testing.T) { func TestThreeSentencesExists(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage(":beer:++")) c.incrementCmd(makeMessage(":beer:++", incrementRegex))
c.message(makeMessage(":beer:. Earl Grey. Hot.")) c.teaMatchCmd(makeMessage(":beer:. Earl Grey. Hot.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":beer:") item, err := GetUserItem(mb.DB(), "tester", ":beer:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, item.Count) assert.Equal(t, 2, item.Count)
@ -73,7 +78,7 @@ func TestThreeSentencesNotExists(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
item, err := GetUserItem(mb.DB(), "tester", ":beer:") item, err := GetUserItem(mb.DB(), "tester", ":beer:")
c.message(makeMessage(":beer:. Earl Grey. Hot.")) c.teaMatchCmd(makeMessage(":beer:. Earl Grey. Hot.", teaRegex))
item, err = GetUserItem(mb.DB(), "tester", ":beer:") item, err = GetUserItem(mb.DB(), "tester", ":beer:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -82,8 +87,8 @@ func TestThreeSentencesNotExists(t *testing.T) {
func TestTeaEarlGreyHot(t *testing.T) { func TestTeaEarlGreyHot(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("Tea. Earl Grey. Hot.")) c.teaMatchCmd(makeMessage("Tea. Earl Grey. Hot.", teaRegex))
c.message(makeMessage("Tea. Earl Grey. Hot.")) c.teaMatchCmd(makeMessage("Tea. Earl Grey. Hot.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, item.Count) assert.Equal(t, 2, item.Count)
@ -92,8 +97,8 @@ func TestTeaEarlGreyHot(t *testing.T) {
func TestTeaTwoPeriods(t *testing.T) { func TestTeaTwoPeriods(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("Tea. Earl Grey.")) c.teaMatchCmd(makeMessage("Tea. Earl Grey.", teaRegex))
c.message(makeMessage("Tea. Earl Grey.")) c.teaMatchCmd(makeMessage("Tea. Earl Grey.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -102,8 +107,8 @@ func TestTeaTwoPeriods(t *testing.T) {
func TestTeaMultiplePeriods(t *testing.T) { func TestTeaMultiplePeriods(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("Tea. Earl Grey. Spiked. Hot.")) c.teaMatchCmd(makeMessage("Tea. Earl Grey. Spiked. Hot.", teaRegex))
c.message(makeMessage("Tea. Earl Grey. Spiked. Hot.")) c.teaMatchCmd(makeMessage("Tea. Earl Grey. Spiked. Hot.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, item.Count) assert.Equal(t, 2, item.Count)
@ -112,9 +117,9 @@ func TestTeaMultiplePeriods(t *testing.T) {
func TestTeaGreenHot(t *testing.T) { func TestTeaGreenHot(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("Tea. Green. Hot.")) c.teaMatchCmd(makeMessage("Tea. Green. Hot.", teaRegex))
c.message(makeMessage("Tea. Green. Hot")) c.teaMatchCmd(makeMessage("Tea. Green. Hot", teaRegex))
c.message(makeMessage("Tea. Green. Iced.")) c.teaMatchCmd(makeMessage("Tea. Green. Iced.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, item.Count) assert.Equal(t, 3, item.Count)
@ -123,8 +128,8 @@ func TestTeaGreenHot(t *testing.T) {
func TestTeaUnrelated(t *testing.T) { func TestTeaUnrelated(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("Tea.")) c.teaMatchCmd(makeMessage("Tea.", teaRegex))
c.message(makeMessage("Tea. It's great.")) c.teaMatchCmd(makeMessage("Tea. It's great.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -133,7 +138,7 @@ func TestTeaUnrelated(t *testing.T) {
func TestTeaSkieselQuote(t *testing.T) { func TestTeaSkieselQuote(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("blah, this is a whole page of explanation where \"we did local search and used a tabu list\" would have sufficed")) c.teaMatchCmd(makeMessage("blah, this is a whole page of explanation where \"we did local search and used a tabu list\" would have sufficed", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -141,7 +146,7 @@ func TestTeaSkieselQuote(t *testing.T) {
func TestTeaUnicodeJapanese(t *testing.T) { func TestTeaUnicodeJapanese(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("Tea. おちや. Hot.")) c.teaMatchCmd(makeMessage("Tea. おちや. Hot.", teaRegex))
item, err := GetUserItem(mb.DB(), "tester", ":tea:") item, err := GetUserItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, item.Count) assert.Equal(t, 1, item.Count)
@ -150,8 +155,8 @@ func TestTeaUnicodeJapanese(t *testing.T) {
func TestResetMe(t *testing.T) { func TestResetMe(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
c.message(makeMessage("!reset me")) c.resetCmd(makeMessage("!reset me", resetRegex))
items, err := GetItems(mb.DB(), "tester") items, err := GetItems(mb.DB(), "tester")
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, items, 0) assert.Len(t, items, 0)
@ -160,7 +165,7 @@ func TestResetMe(t *testing.T) {
func TestCounterOne(t *testing.T) { func TestCounterOne(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, mb.Messages[0], "tester has 1 test.") assert.Equal(t, mb.Messages[0], "tester has 1 test.")
} }
@ -168,7 +173,7 @@ func TestCounterOne(t *testing.T) {
func TestCounterOneWithSpace(t *testing.T) { func TestCounterOneWithSpace(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.message(makeMessage(":test: ++")) c.incrementCmd(makeMessage(":test: ++", incrementRegex))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, mb.Messages[0], "tester has 1 :test:.") assert.Equal(t, mb.Messages[0], "tester has 1 :test:.")
} }
@ -177,7 +182,7 @@ func TestCounterFour(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
} }
assert.Len(t, mb.Messages, 4) assert.Len(t, mb.Messages, 4)
assert.Equal(t, mb.Messages[3], "tester has 4 test.") assert.Equal(t, mb.Messages[3], "tester has 4 test.")
@ -187,10 +192,10 @@ func TestCounterDecrement(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
c.message(makeMessage("test--")) c.decrementCmd(makeMessage("test--", decrementRegex))
assert.Len(t, mb.Messages, 5) assert.Len(t, mb.Messages, 5)
assert.Equal(t, mb.Messages[4], "tester has 3 test.") assert.Equal(t, mb.Messages[4], "tester has 3 test.")
} }
@ -199,10 +204,10 @@ func TestFriendCounterDecrement(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("other.test++")) c.incrementCmd(makeMessage("other.test++", incrementRegex))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("other has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("other has %d test.", i+1))
} }
c.message(makeMessage("other.test--")) c.decrementCmd(makeMessage("other.test--", decrementRegex))
assert.Len(t, mb.Messages, 5) assert.Len(t, mb.Messages, 5)
assert.Equal(t, mb.Messages[4], "other has 3 test.") assert.Equal(t, mb.Messages[4], "other has 3 test.")
} }
@ -211,12 +216,12 @@ func TestDecrementZero(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
j := 4 j := 4
for i := 4; i > 0; i-- { for i := 4; i > 0; i-- {
c.message(makeMessage("test--")) c.decrementCmd(makeMessage("test--", decrementRegex))
assert.Equal(t, mb.Messages[j], fmt.Sprintf("tester has %d test.", i-1)) assert.Equal(t, mb.Messages[j], fmt.Sprintf("tester has %d test.", i-1))
j++ j++
} }
@ -228,10 +233,10 @@ func TestClear(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
res := c.message(makeMessage("!clear test")) res := c.clearCmd(makeMessage("!clear test", clearRegex))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Actions, 1) assert.Len(t, mb.Actions, 1)
assert.Equal(t, mb.Actions[0], "chops a few test out of his brain") assert.Equal(t, mb.Actions[0], "chops a few test out of his brain")
@ -241,10 +246,10 @@ func TestCount(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
res := c.message(makeMessage("!count test")) res := c.countCmd(makeMessage("!count test", countRegex))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 5) assert.Len(t, mb.Messages, 5)
assert.Equal(t, mb.Messages[4], "tester has 4 test.") assert.Equal(t, mb.Messages[4], "tester has 4 test.")
@ -254,18 +259,18 @@ func TestInspectMe(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.message(makeMessage("test++")) c.incrementCmd(makeMessage("test++", incrementRegex))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
c.message(makeMessage("fucks++")) c.incrementCmd(makeMessage("fucks++", incrementRegex))
assert.Equal(t, mb.Messages[i+4], fmt.Sprintf("tester has %d fucks.", i+1)) assert.Equal(t, mb.Messages[i+4], fmt.Sprintf("tester has %d fucks.", i+1))
} }
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
c.message(makeMessage("cheese++")) c.incrementCmd(makeMessage("cheese++", incrementRegex))
assert.Equal(t, mb.Messages[i+6], fmt.Sprintf("tester has %d cheese.", i+1)) assert.Equal(t, mb.Messages[i+6], fmt.Sprintf("tester has %d cheese.", i+1))
} }
res := c.message(makeMessage("!inspect me")) res := c.inspectCmd(makeMessage("!inspect me", inspectRegex))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 27) assert.Len(t, mb.Messages, 27)
assert.Equal(t, mb.Messages[26], "tester has the following counters: test: 4, fucks: 2, cheese: 20.") assert.Equal(t, mb.Messages[26], "tester has the following counters: test: 4, fucks: 2, cheese: 20.")