mirror of https://github.com/velour/catbase.git
234 lines
6.6 KiB
Go
234 lines
6.6 KiB
Go
package achievements
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
bh "github.com/timshannon/bolthold"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"github.com/velour/catbase/bot"
|
|
"github.com/velour/catbase/bot/msg"
|
|
"github.com/velour/catbase/config"
|
|
)
|
|
|
|
// A plugin to track our misdeeds
|
|
type AchievementsPlugin struct {
|
|
bot bot.Bot
|
|
cfg *config.Config
|
|
store *bh.Store
|
|
}
|
|
|
|
func New(b bot.Bot) *AchievementsPlugin {
|
|
ap := &AchievementsPlugin{
|
|
bot: b,
|
|
cfg: b.Config(),
|
|
store: b.Store(),
|
|
}
|
|
|
|
ap.register()
|
|
|
|
return ap
|
|
}
|
|
|
|
var grantRegex = regexp.MustCompile(`(?i)grant (?P<emojy>(?::[[:word:][:punct:]]+:\s?)+) to :?(?P<nick>[[:word:]]+):?`)
|
|
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 listRegex = regexp.MustCompile(`(?i)^list (?P<whos>.+)?\s?trophies$`)
|
|
|
|
func (p *AchievementsPlugin) register() {
|
|
p.bot.RegisterRegexCmd(p, bot.Message, grantRegex, p.grantCmd)
|
|
p.bot.RegisterRegexCmd(p, bot.Message, createRegex, p.createCmd)
|
|
p.bot.RegisterRegexCmd(p, bot.Message, greatRegex, p.greatCmd)
|
|
p.bot.RegisterRegexCmd(p, bot.Message, listRegex, p.listCmd)
|
|
p.bot.Register(p, bot.Help, p.help)
|
|
}
|
|
|
|
func (p *AchievementsPlugin) GetAwards(nick string) []Award {
|
|
var awards []Award
|
|
err := p.store.Find(&awards, bh.Where("holder").Eq(nick))
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("could not select awards")
|
|
}
|
|
return awards
|
|
}
|
|
|
|
func (p *AchievementsPlugin) listCmd(r bot.Request) bool {
|
|
log.Debug().Msgf("Values: %+v", r.Values)
|
|
whos := strings.TrimSpace(r.Values["whos"])
|
|
if whos == "my" {
|
|
whos = r.Msg.User.Name
|
|
}
|
|
log.Debug().Msgf("whos = %s", whos)
|
|
ts, err := p.AllTrophies()
|
|
if err != nil {
|
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, "Some problem happened.")
|
|
log.Error().Err(err).Msg("could not retrieve trophies")
|
|
return true
|
|
}
|
|
if len(ts) == 0 {
|
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, "There are no trophies.")
|
|
return true
|
|
}
|
|
msg := "Current trophies:\n"
|
|
log.Debug().Msgf("Trophies: %s", ts)
|
|
for _, t := range ts {
|
|
log.Debug().Msgf("t.Creator = %s", t.Creator)
|
|
if strings.TrimSpace(t.Creator) == whos {
|
|
log.Debug().Msgf("adding %s", t)
|
|
msg += fmt.Sprintf("%s - %s\n", t.Emojy, t.Description)
|
|
} else if whos == "" {
|
|
msg += fmt.Sprintf("%s - %s (by %s)\n", t.Emojy, t.Description, t.Creator)
|
|
}
|
|
}
|
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, strings.TrimSpace(msg))
|
|
return true
|
|
}
|
|
|
|
func (p *AchievementsPlugin) grantCmd(r bot.Request) bool {
|
|
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
|
|
}
|
|
|
|
func (p *AchievementsPlugin) createCmd(r bot.Request) bool {
|
|
nick := r.Msg.User.Name
|
|
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 == "" {
|
|
who = nick
|
|
}
|
|
awards := p.GetAwards(who)
|
|
if len(awards) == 0 {
|
|
m := fmt.Sprintf("%s has no achievements to their name. They really suck.", who)
|
|
if who == nick {
|
|
m = fmt.Sprintf("You have no achievements to your name. "+
|
|
"You are a sad and terrible specimen of the human condition, %s.", who)
|
|
}
|
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, m)
|
|
} else {
|
|
m := fmt.Sprintf("Wow, let's all clap for %s. Look at these awards:", who)
|
|
for _, a := range awards {
|
|
m += fmt.Sprintf("\n%s - %s", a.Emojy, a.Description)
|
|
}
|
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, m)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (p *AchievementsPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
ch := message.Channel
|
|
me := p.bot.WhoAmI()
|
|
msg := "The achievements plugins awards trophies."
|
|
msg += fmt.Sprintf("\nYou can create a trophy with `%s, create trophy <emojy> <description>`", me)
|
|
msg += fmt.Sprintf("\nYou can award a trophy with `%s, grant <emojy> to <nick>`", me)
|
|
msg += "\nYou can see others awards with `How great is <nick>`"
|
|
msg += "\nYou can see your awards with `How great am I?`"
|
|
p.bot.Send(c, bot.Message, ch, msg)
|
|
return true
|
|
}
|
|
|
|
// Award is used by other plugins to register a particular award for a user
|
|
func (p *AchievementsPlugin) Grant(nick, emojy string) (Award, error) {
|
|
trophy, err := p.FindTrophy(emojy)
|
|
if err != nil {
|
|
return Award{}, err
|
|
}
|
|
award := Award{
|
|
Holder: nick,
|
|
Emojy: emojy,
|
|
Description: trophy.Description,
|
|
Granted: sql.NullTime{Time: time.Now()},
|
|
}
|
|
if err = p.store.Insert(bh.NextSequence(), &award); err != nil {
|
|
return Award{}, err
|
|
}
|
|
|
|
return award, err
|
|
}
|
|
|
|
func (p *AchievementsPlugin) Create(emojy, description, creator string) (Trophy, error) {
|
|
t, err := p.FindTrophy(emojy)
|
|
if err == nil {
|
|
return t, fmt.Errorf("the trophy %s already exists", emojy)
|
|
}
|
|
|
|
t = Trophy{
|
|
Emojy: emojy,
|
|
Description: description,
|
|
Creator: creator,
|
|
}
|
|
|
|
err = p.store.Insert(emojy, t)
|
|
return t, err
|
|
}
|
|
|
|
type Trophy struct {
|
|
Emojy string `boltholderKey:"Emojy"`
|
|
Description string
|
|
Creator string
|
|
}
|
|
|
|
type Award struct {
|
|
ID uint64 `boltholderKey:"ID"`
|
|
Emojy string
|
|
Description string
|
|
Holder string
|
|
Amount int64
|
|
Granted sql.NullTime
|
|
}
|
|
|
|
func (p *AchievementsPlugin) AllTrophies() ([]Trophy, error) {
|
|
var t []Trophy
|
|
err := p.store.Find(&t, &bh.Query{})
|
|
return t, err
|
|
}
|
|
|
|
func (p *AchievementsPlugin) FindTrophy(emojy string) (Trophy, error) {
|
|
var t Trophy
|
|
err := p.store.Find(&t, bh.Where("emojy").Eq(emojy))
|
|
return t, err
|
|
}
|