Merge pull request #177 from velour/cli

cli: make a new plugin
This commit is contained in:
Chris Sexton 2019-05-27 19:30:36 -04:00 committed by GitHub
commit e219b99179
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 741 additions and 498 deletions

1
.gitignore vendored
View File

@ -68,3 +68,4 @@ Temporary Items
util/*/files
util/*/files
run.sh
.idea

View File

@ -59,7 +59,7 @@ func New(config *config.Config, connector Connector) Bot {
msglog.RunNew(logIn, logOut)
users := []user.User{
user.User{
{
Name: config.Get("Nick", "bot"),
},
}
@ -87,6 +87,14 @@ func New(config *config.Config, connector Connector) Bot {
return bot
}
func (b *bot) DefaultConnector() Connector {
return b.conn
}
func (b *bot) WhoAmI() string {
return b.me.Name
}
// Config gets the configuration that the bot is using
func (b *bot) Config() *config.Config {
return b.config

View File

@ -17,7 +17,7 @@ import (
"github.com/velour/catbase/bot/msg"
)
func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool {
func (b *bot) Receive(conn Connector, kind Kind, msg msg.Message, args ...interface{}) bool {
log.Debug().
Interface("msg", msg).
Msg("Received event")
@ -26,13 +26,13 @@ func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool {
// do need to look up user and fix it
if kind == Message && strings.HasPrefix(msg.Body, "help") && msg.Command {
parts := strings.Fields(strings.ToLower(msg.Body))
b.checkHelp(msg.Channel, parts)
b.checkHelp(conn, msg.Channel, parts)
log.Debug().Msg("Handled a help, returning")
goto RET
}
for _, name := range b.pluginOrdering {
if b.runCallback(b.plugins[name], kind, msg, args...) {
if b.runCallback(conn, b.plugins[name], kind, msg, args...) {
goto RET
}
}
@ -42,10 +42,10 @@ RET:
return true
}
func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
func (b *bot) runCallback(conn Connector, plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
t := reflect.TypeOf(plugin).String()
for _, cb := range b.callbacks[t][evt] {
if cb(evt, message, args...) {
if cb(conn, evt, message, args...) {
return true
}
}
@ -53,8 +53,8 @@ func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...
}
// Send a message to the connection
func (b *bot) Send(kind Kind, args ...interface{}) (string, error) {
return b.conn.Send(kind, args...)
func (b *bot) Send(conn Connector, kind Kind, args ...interface{}) (string, error) {
return conn.Send(kind, args...)
}
func (b *bot) GetEmojiList() map[string]string {
@ -62,38 +62,38 @@ func (b *bot) GetEmojiList() map[string]string {
}
// Checks to see if the user is asking for help, returns true if so and handles the situation.
func (b *bot) checkHelp(channel string, parts []string) {
func (b *bot) checkHelp(conn Connector, channel string, parts []string) {
if len(parts) == 1 {
// just print out a list of help topics
topics := "Help topics: about variables"
for name, _ := range b.plugins {
for name := range b.plugins {
name = strings.Split(strings.TrimPrefix(name, "*"), ".")[0]
topics = fmt.Sprintf("%s, %s", topics, name)
}
b.Send(Message, channel, topics)
b.Send(conn, Message, channel, topics)
} else {
// trigger the proper plugin's help response
if parts[1] == "about" {
b.Help(channel, parts)
b.Help(conn, channel, parts)
return
}
if parts[1] == "variables" {
b.listVars(channel, parts)
b.listVars(conn, channel, parts)
return
}
for name, plugin := range b.plugins {
if strings.HasPrefix(name, "*"+parts[1]) {
if b.runCallback(plugin, Help, msg.Message{Channel: channel}, channel, parts) {
if b.runCallback(conn, plugin, Help, msg.Message{Channel: channel}, channel, parts) {
return
} else {
msg := fmt.Sprintf("I'm sorry, I don't know how to help you with %s.", parts[1])
b.Send(Message, channel, msg)
b.Send(conn, Message, channel, msg)
return
}
}
}
msg := fmt.Sprintf("I'm sorry, I don't know what %s is!", strings.Join(parts, " "))
b.Send(Message, channel, msg)
b.Send(conn, Message, channel, msg)
}
}
@ -178,7 +178,7 @@ func (b *bot) getVar(varName string) (string, error) {
return text, nil
}
func (b *bot) listVars(channel string, parts []string) {
func (b *bot) listVars(conn Connector, channel string, parts []string) {
var variables []string
err := b.DB().Select(&variables, `select name from variables group by name`)
if err != nil {
@ -188,18 +188,18 @@ func (b *bot) listVars(channel string, parts []string) {
if len(variables) > 0 {
msg += ", " + strings.Join(variables, ", ")
}
b.Send(Message, channel, msg)
b.Send(conn, Message, channel, msg)
}
func (b *bot) Help(channel string, parts []string) {
func (b *bot) Help(conn Connector, channel string, parts []string) {
msg := fmt.Sprintf("Hi, I'm based on godeepintir version %s. I'm written in Go, and you "+
"can find my source code on the internet here: "+
"http://github.com/velour/catbase", b.version)
b.Send(Message, channel, msg)
b.Send(conn, Message, channel, msg)
}
// Send our own musings to the plugins
func (b *bot) selfSaid(channel, message string, action bool) {
func (b *bot) selfSaid(conn Connector, channel, message string, action bool) {
msg := msg.Message{
User: &b.me, // hack
Channel: channel,
@ -212,7 +212,7 @@ func (b *bot) selfSaid(channel, message string, action bool) {
}
for _, name := range b.pluginOrdering {
if b.runCallback(b.plugins[name], SelfMessage, msg) {
if b.runCallback(conn, b.plugins[name], SelfMessage, msg) {
return
}
}

View File

@ -36,7 +36,7 @@ type ImageAttachment struct {
}
type Kind int
type Callback func(Kind, msg.Message, ...interface{}) bool
type Callback func(Connector, Kind, msg.Message, ...interface{}) bool
type CallbackMap map[string]map[Kind][]Callback
// Bot interface serves to allow mocking of the actual bot
@ -47,12 +47,14 @@ type Bot interface {
DB() *sqlx.DB
// Who lists users in a particular channel
Who(string) []user.User
// WhoAmI gives a nick for the bot
WhoAmI() string
// AddPlugin registers a new plugin handler
AddPlugin(Plugin)
// First arg should be one of bot.Message/Reply/Action/etc
Send(Kind, ...interface{}) (string, error)
Send(Connector, Kind, ...interface{}) (string, error)
// First arg should be one of bot.Message/Reply/Action/etc
Receive(Kind, msg.Message, ...interface{}) bool
Receive(Connector, Kind, msg.Message, ...interface{}) bool
// Register a callback
Register(Plugin, Kind, Callback)
@ -63,6 +65,7 @@ type Bot interface {
GetEmojiList() map[string]string
RegisterFilter(string, func(string) string)
RegisterWeb(string, string)
DefaultConnector() Connector
}
// Connector represents a server connection to a chat service

View File

@ -30,7 +30,9 @@ type MockBot struct {
func (mb *MockBot) Config() *config.Config { return mb.Cfg }
func (mb *MockBot) DB() *sqlx.DB { return mb.Cfg.DB }
func (mb *MockBot) Who(string) []user.User { return []user.User{} }
func (mb *MockBot) Send(kind Kind, args ...interface{}) (string, error) {
func (mb *MockBot) WhoAmI() string { return "tester" }
func (mb *MockBot) DefaultConnector() Connector { return nil }
func (mb *MockBot) Send(c Connector, kind Kind, args ...interface{}) (string, error) {
switch kind {
case Message:
mb.Messages = append(mb.Messages, args[1].(string))
@ -40,27 +42,29 @@ func (mb *MockBot) Send(kind Kind, args ...interface{}) (string, error) {
return fmt.Sprintf("a-%d", len(mb.Actions)-1), nil
case Edit:
ch, m, id := args[0].(string), args[1].(string), args[2].(string)
return mb.edit(ch, m, id)
return mb.edit(c, ch, m, id)
case Reaction:
ch, re, msg := args[0].(string), args[1].(string), args[2].(msg.Message)
return mb.react(ch, re, msg)
return mb.react(c, ch, re, msg)
}
return "ERR", fmt.Errorf("Mesasge type unhandled")
}
func (mb *MockBot) AddPlugin(f Plugin) {}
func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {}
func (mb *MockBot) RegisterWeb(_, _ string) {}
func (mb *MockBot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool { return false }
func (mb *MockBot) Receive(c Connector, kind Kind, msg msg.Message, args ...interface{}) bool {
return false
}
func (mb *MockBot) Filter(msg msg.Message, s string) string { return s }
func (mb *MockBot) LastMessage(ch string) (msg.Message, error) { return msg.Message{}, nil }
func (mb *MockBot) CheckAdmin(nick string) bool { return false }
func (mb *MockBot) react(channel, reaction string, message msg.Message) (string, error) {
func (mb *MockBot) react(c Connector, channel, reaction string, message msg.Message) (string, error) {
mb.Reactions = append(mb.Reactions, reaction)
return "", nil
}
func (mb *MockBot) edit(channel, newMessage, identifier string) (string, error) {
func (mb *MockBot) edit(c Connector, channel, newMessage, identifier string) (string, error) {
isMessage := identifier[0] == 'm'
if !isMessage && identifier[0] != 'a' {
err := fmt.Errorf("failed to parse identifier: %s", identifier)

View File

@ -11,7 +11,7 @@ import (
"strings"
"github.com/jmoiron/sqlx"
sqlite3 "github.com/mattn/go-sqlite3"
"github.com/mattn/go-sqlite3"
"github.com/rs/zerolog/log"
)
@ -98,8 +98,8 @@ func (c *Config) GetArray(key string, fallback []string) []string {
// Note, this is always a string. Use the SetArray for an array helper
func (c *Config) Set(key, value string) error {
key = strings.ToLower(key)
q := (`insert into config (key,value) values (?, ?)
on conflict(key) do update set value=?;`)
q := `insert into config (key,value) values (?, ?)
on conflict(key) do update set value=?;`
tx, err := c.Begin()
if err != nil {
return err

View File

@ -248,10 +248,10 @@ func (i *Irc) handleMsg(msg irc.Msg) {
fallthrough
case irc.RPL_ENDOFWHO:
i.event(bot.Event, botMsg)
i.event(i, bot.Event, botMsg)
case irc.PRIVMSG:
i.event(bot.Message, botMsg)
i.event(i, bot.Message, botMsg)
case irc.QUIT:
os.Exit(1)

View File

@ -455,11 +455,11 @@ func (s *Slack) Serve() error {
log.Debug().Msgf("Ignoring message: %+v\nlastRecieved: %v msg: %v", msg.ID, s.lastRecieved, m.Time)
} else {
s.lastRecieved = m.Time
s.event(bot.Message, m)
s.event(s, bot.Message, m)
}
} else if msg.ThreadTs != "" {
//we're throwing away some information here by not parsing the correct reply object type, but that's okay
s.event(bot.Reply, s.buildLightReplyMessage(msg), msg.ThreadTs)
s.event(s, bot.Reply, s.buildLightReplyMessage(msg), msg.ThreadTs)
} else {
log.Debug().Msgf("THAT MESSAGE WAS HIDDEN: %+v", msg.ID)
}

View File

@ -167,11 +167,11 @@ func (s *SlackApp) msgReceivd(msg *slackevents.MessageEvent) {
Msg("Ignoring message")
} else {
s.lastRecieved = m.Time
s.event(bot.Message, m)
s.event(s, bot.Message, m)
}
} else if msg.ThreadTimeStamp != "" {
//we're throwing away some information here by not parsing the correct reply object type, but that's okay
s.event(bot.Reply, s.buildMessage(msg), msg.ThreadTimeStamp)
s.event(s, bot.Reply, s.buildMessage(msg), msg.ThreadTimeStamp)
} else {
log.Debug().
Str("text", msg.Text).

View File

@ -4,6 +4,7 @@ package main
import (
"flag"
"github.com/velour/catbase/plugins/cli"
"math/rand"
"net/http"
"os"
@ -121,6 +122,7 @@ func main() {
b.AddPlugin(couldashouldawoulda.New(b))
b.AddPlugin(nerdepedia.New(b))
b.AddPlugin(tldr.New(b))
b.AddPlugin(cli.New(b))
// catches anything left, will always return true
b.AddPlugin(fact.New(b))

View File

@ -47,7 +47,7 @@ var forbiddenKeys = map[string]bool{
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *AdminPlugin) message(conn bot.Connector, k bot.Kind, message msg.Message, args ...interface{}) bool {
body := message.Body
if p.quiet {
@ -55,7 +55,7 @@ func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface
}
if len(body) > 0 && body[0] == '$' {
return p.handleVariables(message)
return p.handleVariables(conn, message)
}
if !message.Command {
@ -65,7 +65,7 @@ func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface
if strings.ToLower(body) == "shut up" {
dur := time.Duration(p.cfg.GetInt("quietDuration", 5)) * time.Minute
log.Info().Msgf("Going to sleep for %v, %v", dur, time.Now().Add(dur))
p.Bot.Send(bot.Message, message.Channel, "Okay. I'll be back later.")
p.Bot.Send(conn, bot.Message, message.Channel, "Okay. I'll be back later.")
p.quiet = true
go func() {
select {
@ -79,36 +79,36 @@ func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface
parts := strings.Split(body, " ")
if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] {
p.Bot.Send(bot.Message, message.Channel, "You cannot access that key")
p.Bot.Send(conn, bot.Message, message.Channel, "You cannot access that key")
return true
} else if parts[0] == "set" && len(parts) > 2 {
p.cfg.Set(parts[1], strings.Join(parts[2:], " "))
p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("Set %s", parts[1]))
p.Bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("Set %s", parts[1]))
return true
}
if parts[0] == "get" && len(parts) == 2 && forbiddenKeys[parts[1]] {
p.Bot.Send(bot.Message, message.Channel, "You cannot access that key")
p.Bot.Send(conn, bot.Message, message.Channel, "You cannot access that key")
return true
} else if parts[0] == "get" && len(parts) == 2 {
v := p.cfg.Get(parts[1], "<unknown>")
p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("%s: %s", parts[1], v))
p.Bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("%s: %s", parts[1], v))
return true
}
return false
}
func (p *AdminPlugin) handleVariables(message msg.Message) bool {
func (p *AdminPlugin) handleVariables(conn bot.Connector, message msg.Message) bool {
if parts := strings.SplitN(message.Body, "!=", 2); len(parts) == 2 {
variable := strings.ToLower(strings.TrimSpace(parts[0]))
value := strings.TrimSpace(parts[1])
_, err := p.db.Exec(`delete from variables where name=? and value=?`, variable, value)
if err != nil {
p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
p.Bot.Send(conn, bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
log.Error().Err(err)
} else {
p.Bot.Send(bot.Message, message.Channel, "Removed.")
p.Bot.Send(conn, bot.Message, message.Channel, "Removed.")
}
return true
@ -126,27 +126,27 @@ func (p *AdminPlugin) handleVariables(message msg.Message) bool {
row := p.db.QueryRow(`select count(*) from variables where value = ?`, variable, value)
err := row.Scan(&count)
if err != nil {
p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
p.Bot.Send(conn, bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
log.Error().Err(err)
return true
}
if count > 0 {
p.Bot.Send(bot.Message, message.Channel, "I've already got that one.")
p.Bot.Send(conn, bot.Message, message.Channel, "I've already got that one.")
} else {
_, err := p.db.Exec(`INSERT INTO variables (name, value) VALUES (?, ?)`, variable, value)
if err != nil {
p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
p.Bot.Send(conn, bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
log.Error().Err(err)
return true
}
p.Bot.Send(bot.Message, message.Channel, "Added.")
p.Bot.Send(conn, bot.Message, message.Channel, "Added.")
}
return true
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *AdminPlugin) help(kind bot.Kind, m msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, m.Channel, "This does super secret things that you're not allowed to know about.")
func (p *AdminPlugin) help(conn bot.Connector, kind bot.Kind, m msg.Message, args ...interface{}) bool {
p.Bot.Send(conn, bot.Message, m.Channel, "This does super secret things that you're not allowed to know about.")
return true
}

View File

@ -1,6 +1,7 @@
package admin
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -22,12 +23,13 @@ func setup(t *testing.T) (*AdminPlugin, *bot.MockBot) {
return a, mb
}
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
c := cli.CliPlugin{}
return &c, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -101,7 +101,7 @@ func New(b bot.Bot) *BabblerPlugin {
return plugin
}
func (p *BabblerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *BabblerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
lowercase := strings.ToLower(message.Body)
tokens := strings.Fields(lowercase)
numTokens := len(tokens)
@ -143,12 +143,12 @@ func (p *BabblerPlugin) message(kind bot.Kind, message msg.Message, args ...inte
}
if saidSomething {
p.Bot.Send(bot.Message, message.Channel, saidWhat)
p.Bot.Send(c, bot.Message, message.Channel, saidWhat)
}
return saidSomething
}
func (p *BabblerPlugin) help(kind bot.Kind, msg msg.Message, args ...interface{}) bool {
func (p *BabblerPlugin) help(c bot.Connector, kind bot.Kind, msg msg.Message, args ...interface{}) bool {
commands := []string{
"initialize babbler for seabass",
"merge babbler drseabass into seabass",
@ -157,7 +157,7 @@ func (p *BabblerPlugin) help(kind bot.Kind, msg msg.Message, args ...interface{}
"seabass says-middle-out ...",
"seabass says-bridge ... | ...",
}
p.Bot.Send(bot.Message, msg.Channel, strings.Join(commands, "\n\n"))
p.Bot.Send(c, bot.Message, msg.Channel, strings.Join(commands, "\n\n"))
return true
}
@ -851,7 +851,7 @@ func (p *BabblerPlugin) babbleSeedBookends(babblerName string, start, end []stri
previous *searchNode
}
open := []*searchNode{&searchNode{startWordNode.NodeId, nil}}
open := []*searchNode{{startWordNode.NodeId, nil}}
closed := map[int64]*searchNode{startWordNode.NodeId: open[0]}
goalNodeId := int64(-1)

View File

@ -3,6 +3,7 @@
package babbler
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,13 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
c := &cli.CliPlugin{}
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return c, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,
@ -64,13 +66,13 @@ func TestBabbler(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is a message")
c, k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
seabass.Body = "This is another message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "This is a long message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -82,13 +84,13 @@ func TestBabblerSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is a message")
c, k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
seabass.Body = "This is another message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "This is a long message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says long"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -99,13 +101,13 @@ func TestBabblerMultiSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is a message")
c, k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
seabass.Body = "This is another message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "This is a long message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says This is a long"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -116,13 +118,13 @@ func TestBabblerMultiSeed2(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is a message")
c, k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
seabass.Body = "This is another message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "This is a long message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says is a long"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -133,13 +135,13 @@ func TestBabblerBadSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is a message")
c, k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"}
bp.message(k, seabass)
bp.message(c, k, seabass)
seabass.Body = "This is another message"
bp.message(k, seabass)
bp.message(c, k, seabass)
seabass.Body = "This is a long message"
bp.message(k, seabass)
bp.message(c, k, seabass)
bp.message(makeMessage("!seabass says noooo this is bad"))
assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "seabass never said 'noooo this is bad'")
@ -149,13 +151,13 @@ func TestBabblerBadSeed2(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is a message")
c, k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"}
bp.message(k, seabass)
bp.message(c, k, seabass)
seabass.Body = "This is another message"
bp.message(k, seabass)
bp.message(c, k, seabass)
seabass.Body = "This is a long message"
bp.message(k, seabass)
bp.message(c, k, seabass)
bp.message(makeMessage("!seabass says This is a really"))
assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "seabass never said 'this is a really'")
@ -165,13 +167,13 @@ func TestBabblerSuffixSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is message one")
c, k, seabass := makeMessage("This is message one")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
seabass.Body = "It's easier to test with unique messages"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "hi there"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-tail message one"))
res = bp.message(makeMessage("!seabass says-tail with unique"))
assert.Len(t, mb.Messages, 2)
@ -184,13 +186,13 @@ func TestBabblerBadSuffixSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("This is message one")
c, k, seabass := makeMessage("This is message one")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
seabass.Body = "It's easier to test with unique messages"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "hi there"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-tail anything true"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -201,9 +203,9 @@ func TestBabblerBookendSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("It's easier to test with unique messages")
c, k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-bridge It's easier | unique messages"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -214,9 +216,9 @@ func TestBabblerBookendSeedShort(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("It's easier to test with unique messages")
c, k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-bridge It's easier to test with | unique messages"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -227,9 +229,9 @@ func TestBabblerBadBookendSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("It's easier to test with unique messages")
c, k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-bridge It's easier | not unique messages"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -240,9 +242,9 @@ func TestBabblerMiddleOutSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("It's easier to test with unique messages")
c, k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-middle-out test with"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -253,9 +255,9 @@ func TestBabblerBadMiddleOutSeed(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("It's easier to test with unique messages")
c, k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
res = bp.message(makeMessage("!seabass says-middle-out anything true"))
assert.Len(t, mb.Messages, 1)
assert.True(t, res)
@ -266,8 +268,8 @@ func TestBabblerBatch(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("batch learn for seabass This is a message! This is another message. This is not a long message? This is not a message! This is not another message. This is a long message?")
res := bp.message(k, seabass)
c, k, seabass := makeMessage("batch learn for seabass This is a message! This is another message. This is not a long message? This is not a message! This is not another message. This is a long message?")
res := bp.message(c, k, seabass)
assert.Len(t, mb.Messages, 1)
res = bp.message(makeMessage("!seabass says"))
assert.Len(t, mb.Messages, 2)
@ -281,16 +283,16 @@ func TestBabblerMerge(t *testing.T) {
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
k, seabass := makeMessage("<seabass> This is a message")
c, k, seabass := makeMessage("<seabass> This is a message")
seabass.User = &user.User{Name: "seabass"}
res := bp.message(k, seabass)
res := bp.message(c, k, seabass)
assert.Len(t, mb.Messages, 0)
seabass.Body = "<seabass> This is another message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
seabass.Body = "<seabass> This is a long message"
res = bp.message(k, seabass)
res = bp.message(c, k, seabass)
res = bp.message(makeMessage("!merge babbler seabass into seabass2"))
assert.True(t, res)
@ -309,6 +311,7 @@ func TestHelp(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
bp.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
c := &cli.CliPlugin{}
bp.help(c, bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1)
}

View File

@ -53,7 +53,7 @@ func New(b bot.Bot) *BeersPlugin {
db: b.DB(),
}
for _, channel := range b.Config().GetArray("Untappd.Channels", []string{}) {
go p.untappdLoop(channel)
go p.untappdLoop(b.DefaultConnector(), channel)
}
b.Register(p, bot.Message, p.message)
b.Register(p, bot.Help, p.help)
@ -63,7 +63,7 @@ func New(b bot.Bot) *BeersPlugin {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *BeersPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
parts := strings.Fields(message.Body)
if len(parts) == 0 {
@ -83,49 +83,49 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf
count, err := strconv.Atoi(parts[2])
if err != nil {
// if it's not a number, maybe it's a nick!
p.Bot.Send(bot.Message, channel, "Sorry, that didn't make any sense.")
p.Bot.Send(c, bot.Message, channel, "Sorry, that didn't make any sense.")
}
if count < 0 {
// you can't be negative
msg := fmt.Sprintf("Sorry %s, you can't have negative beers!", nick)
p.Bot.Send(bot.Message, channel, msg)
p.Bot.Send(c, bot.Message, channel, msg)
return true
}
if parts[1] == "+=" {
p.addBeers(nick, count)
p.randomReply(channel)
p.randomReply(c, channel)
} else if parts[1] == "=" {
if count == 0 {
p.puke(nick, channel)
p.puke(c, nick, channel)
} else {
p.setBeers(nick, count)
p.randomReply(channel)
p.randomReply(c, channel)
}
} else {
p.Bot.Send(bot.Message, channel, "I don't know your math.")
p.Bot.Send(c, bot.Message, channel, "I don't know your math.")
}
} else if len(parts) == 2 {
if p.doIKnow(parts[1]) {
p.reportCount(parts[1], channel, false)
p.reportCount(c, parts[1], channel, false)
} else {
msg := fmt.Sprintf("Sorry, I don't know %s.", parts[1])
p.Bot.Send(bot.Message, channel, msg)
p.Bot.Send(c, bot.Message, channel, msg)
}
} else if len(parts) == 1 {
p.reportCount(nick, channel, true)
p.reportCount(c, nick, channel, true)
}
// no matter what, if we're in here, then we've responded
return true
} else if parts[0] == "puke" {
p.puke(nick, channel)
p.puke(c, nick, channel)
return true
}
if message.Command && parts[0] == "imbibe" {
p.addBeers(nick, 1)
p.randomReply(channel)
p.randomReply(c, channel)
return true
}
@ -134,7 +134,7 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf
channel := message.Channel
if len(parts) < 2 {
p.Bot.Send(bot.Message, channel, "You must also provide a user name.")
p.Bot.Send(c, bot.Message, channel, "You must also provide a user name.")
} else if len(parts) == 3 {
chanNick = parts[2]
} else if len(parts) == 4 {
@ -159,7 +159,7 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf
log.Error().Err(err).Msgf("Error registering untappd")
}
if count > 0 {
p.Bot.Send(bot.Message, channel, "I'm already watching you.")
p.Bot.Send(c, bot.Message, channel, "I'm already watching you.")
return true
}
_, err = p.db.Exec(`insert into untappd (
@ -175,13 +175,13 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf
)
if err != nil {
log.Error().Err(err).Msgf("Error registering untappd")
p.Bot.Send(bot.Message, channel, "I can't see.")
p.Bot.Send(c, bot.Message, channel, "I can't see.")
return true
}
p.Bot.Send(bot.Message, channel, "I'll be watching you.")
p.Bot.Send(c, bot.Message, channel, "I'll be watching you.")
p.checkUntappd(channel)
p.checkUntappd(c, channel)
return true
}
@ -190,7 +190,7 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf
log.Info().
Str("user", message.User.Name).
Msgf("Checking untappd at request of user.")
p.checkUntappd(channel)
p.checkUntappd(c, channel)
return true
}
@ -198,11 +198,11 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *BeersPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *BeersPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
msg := "Beers: imbibe by using either beers +=,=,++ or with the !imbibe/drink " +
"commands. I'll keep a count of how many beers you've had and then if you want " +
"to reset, just !puke it all up!"
p.Bot.Send(bot.Message, message.Channel, msg)
p.Bot.Send(c, bot.Message, message.Channel, msg)
return true
}
@ -232,7 +232,7 @@ func (p *BeersPlugin) getBeers(nick string) int {
return ub.Count
}
func (p *BeersPlugin) reportCount(nick, channel string, himself bool) {
func (p *BeersPlugin) reportCount(c bot.Connector, nick, channel string, himself bool) {
beers := p.getBeers(nick)
msg := fmt.Sprintf("%s has had %d beers so far.", nick, beers)
if himself {
@ -242,13 +242,13 @@ func (p *BeersPlugin) reportCount(nick, channel string, himself bool) {
msg = fmt.Sprintf("You've had %d beers so far, %s.", beers, nick)
}
}
p.Bot.Send(bot.Message, channel, msg)
p.Bot.Send(c, bot.Message, channel, msg)
}
func (p *BeersPlugin) puke(user string, channel string) {
func (p *BeersPlugin) puke(c bot.Connector, user string, channel string) {
p.setBeers(user, 0)
msg := fmt.Sprintf("Ohhhhhh, and a reversal of fortune for %s!", user)
p.Bot.Send(bot.Message, channel, msg)
p.Bot.Send(c, bot.Message, channel, msg)
}
func (p *BeersPlugin) doIKnow(nick string) bool {
@ -261,9 +261,9 @@ func (p *BeersPlugin) doIKnow(nick string) bool {
}
// Sends random affirmation to the channel. This could be better (with a datastore for sayings)
func (p *BeersPlugin) randomReply(channel string) {
func (p *BeersPlugin) randomReply(c bot.Connector, channel string) {
replies := []string{"ZIGGY! ZAGGY!", "HIC!", "Stay thirsty, my friend!"}
p.Bot.Send(bot.Message, channel, replies[rand.Intn(len(replies))])
p.Bot.Send(c, bot.Message, channel, replies[rand.Intn(len(replies))])
}
type checkin struct {
@ -343,7 +343,7 @@ func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
return beers.Response.Checkins.Items, nil
}
func (p *BeersPlugin) checkUntappd(channel string) {
func (p *BeersPlugin) checkUntappd(c bot.Connector, channel string) {
token := p.Bot.Config().Get("Untappd.Token", "NONE")
if token == "NONE" {
log.Info().
@ -434,11 +434,11 @@ func (p *BeersPlugin) checkUntappd(channel string) {
Int("checkin_id", checkin.Checkin_id).
Str("msg", msg).
Msg("checkin")
p.Bot.Send(bot.Message, args...)
p.Bot.Send(c, bot.Message, args...)
}
}
func (p *BeersPlugin) untappdLoop(channel string) {
func (p *BeersPlugin) untappdLoop(c bot.Connector, channel string) {
frequency := p.Bot.Config().GetInt("Untappd.Freq", 120)
if frequency == 0 {
return
@ -448,6 +448,6 @@ func (p *BeersPlugin) untappdLoop(channel string) {
for {
time.Sleep(time.Duration(frequency) * time.Second)
p.checkUntappd(channel)
p.checkUntappd(c, channel)
}
}

View File

@ -3,6 +3,7 @@
package beers
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -13,12 +14,13 @@ import (
"github.com/velour/catbase/plugins/counter"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
c := &cli.CliPlugin{}
return c, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,
@ -121,6 +123,6 @@ func TestBeersReport(t *testing.T) {
func TestHelp(t *testing.T) {
b, mb := makeBeersPlugin(t)
b.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
b.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1)
}

107
plugins/cli/cli.go Normal file
View File

@ -0,0 +1,107 @@
// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors.
package cli
import (
"encoding/json"
"fmt"
"github.com/jmoiron/sqlx"
"github.com/rs/zerolog/log"
"github.com/velour/catbase/bot"
"github.com/velour/catbase/bot/msg"
"github.com/velour/catbase/bot/user"
"net/http"
"time"
)
type CliPlugin struct {
bot bot.Bot
db *sqlx.DB
cache string
counter int
}
func New(b bot.Bot) *CliPlugin {
cp := &CliPlugin{
bot: b,
}
cp.registerWeb()
return cp
}
func (p *CliPlugin) registerWeb() {
http.HandleFunc("/cli/api", p.handleWebAPI)
http.HandleFunc("/cli", p.handleWeb)
p.bot.RegisterWeb("/cli", "CLI")
}
func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
fmt.Fprintf(w, "Incorrect HTTP method")
return
}
info := struct {
User string `json:"user"`
Payload string `json:"payload"`
}{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&info)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
log.Debug().
Interface("postbody", info).
Msg("Got a POST")
p.bot.Receive(p, bot.Message, msg.Message{
User: &user.User{
ID: info.User,
Name: info.User,
Admin: false,
},
Channel: "web",
Body: info.Payload,
Raw: info.Payload,
Command: true,
Time: time.Now(),
})
info.User = p.bot.WhoAmI()
info.Payload = p.cache
p.cache = ""
data, err := json.Marshal(info)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
w.Write(data)
}
func (p *CliPlugin) handleWeb(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, indexHTML)
}
// Completing the Connector interface, but will not actually be a connector
func (p *CliPlugin) RegisterEvent(cb bot.Callback) {}
func (p *CliPlugin) Send(kind bot.Kind, args ...interface{}) (string, error) {
switch kind {
case bot.Message:
fallthrough
case bot.Action:
fallthrough
case bot.Reply:
fallthrough
case bot.Reaction:
p.cache += args[1].(string) + "\n"
}
id := fmt.Sprintf("%d", p.counter)
p.counter++
return id, nil
}
func (p *CliPlugin) GetEmojiList() map[string]string { return nil }
func (p *CliPlugin) Serve() error { return nil }
func (p *CliPlugin) Who(s string) []string { return nil }

141
plugins/cli/index.go Normal file
View File

@ -0,0 +1,141 @@
package cli
var indexHTML = `
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CMutationObserver"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue@latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<meta charset="UTF-8">
<title>CLI</title>
</head>
<body>
<div id="app">
<h1>CLI</h1>
<b-alert
dismissable
variant="error"
v-if="err"
@dismissed="err = ''">
{{ err }}
</b-alert>
<b-container>
<b-row>
<b-form-group
:label="humanTest"
label-for="input-1"
label-cols="8"
autofocus>
<b-input v-model="answer" id="input-1" autocomplete="off"></b-input>
</b-form-group>
</b-row>
<b-row>
<b-form-textarea
v-sticky-scroll
disabled
id="textarea"
v-model="text"
placeholder="The bot will respond here..."
rows="10"
max-rows="10"
no-resize
></b-form-textarea>
</b-row>
<b-form
@submit="send">
<b-row>
<b-col>
<b-form-input
type="text"
placeholder="Username"
v-model="user"></b-form-input>
</b-col>
<b-col>
<b-form-input
type="text"
placeholder="Enter something to send to the bot"
v-model="input"
autocomplete="off"
></b-form-input>
</b-col>
<b-col>
<b-button type="submit" :disabled="!authenticated">Send</b-button>
</b-col>
</b-row>
</b-form>
</b-container>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
answer: '',
correct: 0,
textarea: [],
user: '',
input: '',
err: '',
},
computed: {
authenticated: function() {
if (Number(this.answer) === this.correct && this.user !== '')
return true;
return false;
},
humanTest: function() {
const x = Math.floor(Math.random() * 100);
const y = Math.floor(Math.random() * 100);
const z = Math.floor(Math.random() * 100);
const ops = ['+', '-', '*'];
const op1 = ops[Math.floor(Math.random()*3)];
const op2 = ops[Math.floor(Math.random()*3)];
const eq = ""+x+op1+y+op2+z;
this.correct = eval(eq);
return "Human test: What is " + eq + "?";
},
text: function() {
return this.textarea.join('\n');
}
},
methods: {
addText(user, text) {
this.textarea.push(user + ": " + text);
const len = this.textarea.length;
if (this.textarea.length > 10)
this.textarea = this.textarea.slice(len-10, len);
},
send(evt) {
evt.preventDefault();
if (!this.authenticated) {
console.log("User is a bot.");
this.err = "User appears to be a bot.";
return;
}
const payload = {user: this.user, payload: this.input};
console.log("Would have posted to /cli/api:" + JSON.stringify(payload));
this.addText(this.user, this.input);
axios.post('/cli/api', payload)
.then(resp => {
console.log(JSON.stringify(resp.data));
const data = resp.data;
this.addText(data.user, data.payload.trim());
})
.catch(err => (this.err = err));
}
}
})
</script>
</body>
</html>
`

View File

@ -25,7 +25,7 @@ func New(b bot.Bot) *CSWPlugin {
return csw
}
func (p *CSWPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *CSWPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !message.Command {
return false
}
@ -65,7 +65,7 @@ func (p *CSWPlugin) message(kind bot.Kind, message msg.Message, args ...interfac
}
}
p.Bot.Send(bot.Message, message.Channel, responses[rand.Intn(len(responses))])
p.Bot.Send(c, bot.Message, message.Channel, responses[rand.Intn(len(responses))])
return true
}

View File

@ -3,6 +3,7 @@
package couldashouldawoulda
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -225,7 +225,7 @@ func New(b bot.Bot) *CounterPlugin {
// This function returns true if the plugin responds in a meaningful way to the
// users message. Otherwise, the function returns false and the bot continues
// execution of other plugins.
func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
// This bot does not reply to anything
nick := message.User.Name
channel := message.Channel
@ -240,7 +240,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
log.Error().Err(err)
return false
}
p.Bot.Send(bot.Message, channel, fmt.Sprintf("Created alias %s -> %s",
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("Created alias %s -> %s",
parts[1], parts[2]))
return true
} else if strings.ToLower(parts[0]) == "leaderboard" {
@ -270,11 +270,11 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
it.Item,
)
}
p.Bot.Send(bot.Message, channel, out)
p.Bot.Send(c, bot.Message, channel, out)
return true
} else if match := teaMatcher.MatchString(message.Body); match {
// check for tea match TTT
return p.checkMatch(message)
return p.checkMatch(c, message)
} else if message.Command && message.Body == "reset me" {
items, err := GetItems(p.DB, strings.ToLower(nick))
if err != nil {
@ -282,14 +282,14 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
Err(err).
Str("nick", nick).
Msg("Error getting items to reset")
p.Bot.Send(bot.Message, channel, "Something is technically wrong with your counters.")
p.Bot.Send(c, bot.Message, channel, "Something is technically wrong with your counters.")
return true
}
log.Debug().Msgf("Items: %+v", items)
for _, item := range items {
item.Delete()
}
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick))
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick))
return true
} else if message.Command && parts[0] == "inspect" && len(parts) == 2 {
var subject string
@ -310,7 +310,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
Err(err).
Str("subject", subject).
Msg("Error retrieving items")
p.Bot.Send(bot.Message, channel, "Something went wrong finding that counter;")
p.Bot.Send(c, bot.Message, channel, "Something went wrong finding that counter;")
return true
}
@ -330,11 +330,11 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
resp += "."
if count == 0 {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has no counters.", subject))
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has no counters.", subject))
return true
}
p.Bot.Send(bot.Message, channel, resp)
p.Bot.Send(c, bot.Message, channel, resp)
return true
} else if message.Command && len(parts) == 2 && parts[0] == "clear" {
subject := strings.ToLower(nick)
@ -347,7 +347,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
Str("subject", subject).
Str("itemName", itemName).
Msg("Error getting item to remove")
p.Bot.Send(bot.Message, channel, "Something went wrong removing that counter;")
p.Bot.Send(c, bot.Message, channel, "Something went wrong removing that counter;")
return true
}
err = it.Delete()
@ -357,11 +357,11 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
Str("subject", subject).
Str("itemName", itemName).
Msg("Error removing item")
p.Bot.Send(bot.Message, channel, "Something went wrong removing that counter;")
p.Bot.Send(c, bot.Message, channel, "Something went wrong removing that counter;")
return true
}
p.Bot.Send(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))
return true
@ -384,7 +384,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
item, err := GetItem(p.DB, subject, itemName)
switch {
case err == sql.ErrNoRows:
p.Bot.Send(bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.",
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.",
subject, itemName))
return true
case err != nil:
@ -396,7 +396,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
return true
}
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count,
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count,
itemName))
return true
@ -431,7 +431,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
}
log.Debug().Msgf("About to update item: %#v", item)
item.UpdateDelta(1)
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item))
return true
} else if strings.HasSuffix(parts[0], "--") {
@ -447,7 +447,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
return false
}
item.UpdateDelta(-1)
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item))
return true
}
@ -480,7 +480,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
n, _ := strconv.Atoi(parts[2])
log.Debug().Msgf("About to update item by %d: %#v", n, item)
item.UpdateDelta(n)
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item))
return true
} else if parts[1] == "-=" {
@ -498,7 +498,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
n, _ := strconv.Atoi(parts[2])
log.Debug().Msgf("About to update item by -%d: %#v", n, item)
item.UpdateDelta(-n)
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item))
return true
}
@ -508,15 +508,15 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *CounterPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "You can set counters incrementally by using "+
func (p *CounterPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(c, bot.Message, message.Channel, "You can set counters incrementally by using "+
"<noun>++ and <noun>--. You can see all of your counters using "+
"\"inspect\", erase them with \"clear\", and view single counters with "+
"\"count\".")
return true
}
func (p *CounterPlugin) checkMatch(message msg.Message) bool {
func (p *CounterPlugin) checkMatch(c bot.Connector, message msg.Message) bool {
nick := message.User.Name
channel := message.Channel
@ -538,7 +538,7 @@ func (p *CounterPlugin) checkMatch(message msg.Message) bool {
}
log.Debug().Msgf("About to update item: %#v", item)
item.UpdateDelta(1)
p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s... %s has %d %s",
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s... %s has %d %s",
strings.Join(everyDayImShuffling([]string{"bleep", "bloop", "blop"}), "-"), nick, item.Count, itemName))
return true
}

View File

@ -4,6 +4,7 @@ package counter
import (
"fmt"
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -22,12 +23,12 @@ func setup(t *testing.T) (*bot.MockBot, *CounterPlugin) {
return mb, c
}
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,
@ -250,6 +251,6 @@ func TestInspectMe(t *testing.T) {
func TestHelp(t *testing.T) {
mb, c := setup(t)
assert.NotNil(t, c)
c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1)
}

View File

@ -1,46 +0,0 @@
package db
import (
"fmt"
"net/http"
"os"
"time"
"github.com/rs/zerolog/log"
"github.com/velour/catbase/bot"
"github.com/velour/catbase/bot/msg"
"github.com/velour/catbase/config"
)
type DBPlugin struct {
bot bot.Bot
config *config.Config
}
func New(b bot.Bot) *DBPlugin {
p := &DBPlugin{b, b.Config()}
p.registerWeb()
return p
}
func (p *DBPlugin) Message(message msg.Message) bool { return false }
func (p *DBPlugin) Event(kind string, message msg.Message) bool { return false }
func (p *DBPlugin) ReplyMessage(msg.Message, string) bool { return false }
func (p *DBPlugin) BotMessage(message msg.Message) bool { return false }
func (p *DBPlugin) Help(channel string, parts []string) {}
func (p *DBPlugin) registerWeb() {
http.HandleFunc("/db/catbase.db", p.serveQuery)
}
func (p *DBPlugin) serveQuery(w http.ResponseWriter, r *http.Request) {
f, err := os.Open(p.bot.Config().DBFile)
defer f.Close()
if err != nil {
log.Error().Err(err).Msg("Error opening DB for web service")
fmt.Fprintf(w, "Error opening DB")
return
}
http.ServeContent(w, r, "catbase.db", time.Now(), f)
}

View File

@ -35,7 +35,7 @@ func rollDie(sides int) int {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *DicePlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !message.Command {
return false
}
@ -49,7 +49,7 @@ func (p *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interfa
}
if sides < 2 || nDice < 1 || nDice > 20 {
p.Bot.Send(bot.Message, channel, "You're a dick.")
p.Bot.Send(c, bot.Message, channel, "You're a dick.")
return true
}
@ -64,13 +64,13 @@ func (p *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interfa
}
}
p.Bot.Send(bot.Message, channel, rolls)
p.Bot.Send(c, bot.Message, channel, rolls)
return true
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *DicePlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Roll dice using notation XdY. Try \"3d20\".")
func (p *DicePlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(c, bot.Message, message.Channel, "Roll dice using notation XdY. Try \"3d20\".")
return true
}

View File

@ -3,6 +3,7 @@
package dice
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,
@ -86,6 +87,6 @@ func TestHelp(t *testing.T) {
mb := bot.NewMockBot()
c := New(mb)
assert.NotNil(t, c)
c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1)
}

View File

@ -58,7 +58,7 @@ func New(b bot.Bot) *EmojifyMePlugin {
return ep
}
func (p *EmojifyMePlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *EmojifyMePlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !p.GotBotEmoji {
p.GotBotEmoji = true
emojiMap := p.Bot.GetEmojiList()
@ -93,7 +93,7 @@ func (p *EmojifyMePlugin) message(kind bot.Kind, message msg.Message, args ...in
if emojied > 0 && rand.Float64() <= p.Bot.Config().GetFloat64("Emojify.Chance", 0.02)*emojied {
for _, e := range emojys {
p.Bot.Send(bot.Reaction, message.Channel, e, message)
p.Bot.Send(c, bot.Reaction, message.Channel, e, message)
}
return false
}

View File

@ -1,6 +1,7 @@
package fact
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -10,6 +11,8 @@ import (
"github.com/velour/catbase/bot/user"
)
var c = &cli.CliPlugin{}
func makeMessage(nick, payload string) msg.Message {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
@ -37,7 +40,7 @@ func TestReact(t *testing.T) {
p, mb := makePlugin(t)
for _, m := range msgs {
p.message(bot.Message, m)
p.message(c, bot.Message, m)
}
assert.Len(t, mb.Reactions, 1)
assert.Contains(t, mb.Reactions[0], "jesus")
@ -50,7 +53,7 @@ func TestReactCantLearnSpaces(t *testing.T) {
p, mb := makePlugin(t)
for _, m := range msgs {
p.message(bot.Message, m)
p.message(c, bot.Message, m)
}
assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "not a valid")

View File

@ -277,6 +277,8 @@ func New(botInst bot.Bot) *FactoidPlugin {
db: botInst.DB(),
}
c := botInst.DefaultConnector()
if _, err := p.db.Exec(`create table if not exists factoid (
id integer primary key,
fact string,
@ -299,13 +301,13 @@ func New(botInst bot.Bot) *FactoidPlugin {
}
for _, channel := range botInst.Config().GetArray("channels", []string{}) {
go p.factTimer(channel)
go p.factTimer(c, channel)
go func(ch string) {
// Some random time to start up
time.Sleep(time.Duration(15) * time.Second)
if ok, fact := p.findTrigger(p.Bot.Config().Get("Factoid.StartupFact", "speed test")); ok {
p.sayFact(msg.Message{
p.sayFact(c, msg.Message{
Channel: ch,
Body: "speed test", // BUG: This is defined in the config too
Command: true,
@ -399,7 +401,7 @@ func (p *FactoidPlugin) findTrigger(fact string) (bool, *Factoid) {
// sayFact spits out a fact to the channel and updates the fact in the database
// with new time and count information
func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) {
func (p *FactoidPlugin) sayFact(c bot.Connector, message msg.Message, fact Factoid) {
msg := p.Bot.Filter(message, fact.Tidbit)
full := p.Bot.Filter(message, fmt.Sprintf("%s %s %s",
fact.Fact, fact.Verb, fact.Tidbit,
@ -411,13 +413,13 @@ func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) {
}
if fact.Verb == "action" {
p.Bot.Send(bot.Action, message.Channel, msg)
p.Bot.Send(c, bot.Action, message.Channel, msg)
} else if fact.Verb == "react" {
p.Bot.Send(bot.Reaction, message.Channel, msg, message)
p.Bot.Send(c, bot.Reaction, message.Channel, msg, message)
} else if fact.Verb == "reply" {
p.Bot.Send(bot.Message, message.Channel, msg)
p.Bot.Send(c, bot.Message, message.Channel, msg)
} else {
p.Bot.Send(bot.Message, message.Channel, full)
p.Bot.Send(c, bot.Message, message.Channel, full)
}
}
@ -436,17 +438,17 @@ func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) {
// trigger checks the message for its fitness to be a factoid and then hauls
// the message off to sayFact for processing if it is in fact a trigger
func (p *FactoidPlugin) trigger(message msg.Message) bool {
func (p *FactoidPlugin) trigger(c bot.Connector, message msg.Message) bool {
minLen := p.Bot.Config().GetInt("Factoid.MinLen", 4)
if len(message.Body) > minLen || message.Command || message.Body == "..." {
if ok, fact := p.findTrigger(message.Body); ok {
p.sayFact(message, *fact)
p.sayFact(c, message, *fact)
return true
}
r := strings.NewReplacer("'", "", "\"", "", ",", "", ".", "", ":", "",
"?", "", "!", "")
if ok, fact := p.findTrigger(r.Replace(message.Body)); ok {
p.sayFact(message, *fact)
p.sayFact(c, message, *fact)
return true
}
}
@ -455,7 +457,7 @@ func (p *FactoidPlugin) trigger(message msg.Message) bool {
}
// tellThemWhatThatWas is a hilarious name for a function.
func (p *FactoidPlugin) tellThemWhatThatWas(message msg.Message) bool {
func (p *FactoidPlugin) tellThemWhatThatWas(c bot.Connector, message msg.Message) bool {
fact := p.LastFact
var msg string
if fact == nil {
@ -464,11 +466,11 @@ func (p *FactoidPlugin) tellThemWhatThatWas(message msg.Message) bool {
msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'",
fact.ID.Int64, fact.Fact, fact.Verb, fact.Tidbit)
}
p.Bot.Send(bot.Message, message.Channel, msg)
p.Bot.Send(c, bot.Message, message.Channel, msg)
return true
}
func (p *FactoidPlugin) learnAction(message msg.Message, action string) bool {
func (p *FactoidPlugin) learnAction(c bot.Connector, message msg.Message, action string) bool {
body := message.Body
parts := strings.SplitN(body, action, 2)
@ -482,21 +484,21 @@ func (p *FactoidPlugin) learnAction(message msg.Message, action string) bool {
action = strings.TrimSpace(action)
if len(trigger) == 0 || len(fact) == 0 || len(action) == 0 {
p.Bot.Send(bot.Message, message.Channel, "I don't want to learn that.")
p.Bot.Send(c, bot.Message, message.Channel, "I don't want to learn that.")
return true
}
if len(strings.Split(fact, "$and")) > 4 {
p.Bot.Send(bot.Message, message.Channel, "You can't use more than 4 $and operators.")
p.Bot.Send(c, bot.Message, message.Channel, "You can't use more than 4 $and operators.")
return true
}
strippedaction := strings.Replace(strings.Replace(action, "<", "", 1), ">", "", 1)
if err := p.learnFact(message, trigger, strippedaction, fact); err != nil {
p.Bot.Send(bot.Message, message.Channel, err.Error())
p.Bot.Send(c, bot.Message, message.Channel, err.Error())
} else {
p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name))
p.Bot.Send(c, bot.Message, message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name))
}
return true
@ -514,9 +516,9 @@ func changeOperator(body string) string {
// If the user requesting forget is either the owner of the last learned fact or
// an admin, it may be deleted
func (p *FactoidPlugin) forgetLastFact(message msg.Message) bool {
func (p *FactoidPlugin) forgetLastFact(c bot.Connector, message msg.Message) bool {
if p.LastFact == nil {
p.Bot.Send(bot.Message, message.Channel, "I refuse.")
p.Bot.Send(c, bot.Message, message.Channel, "I refuse.")
return true
}
@ -529,14 +531,14 @@ func (p *FactoidPlugin) forgetLastFact(message msg.Message) bool {
}
fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.ID.Int64, p.LastFact.Fact,
p.LastFact.Verb, p.LastFact.Tidbit)
p.Bot.Send(bot.Action, message.Channel, "hits himself over the head with a skillet")
p.Bot.Send(c, bot.Action, message.Channel, "hits himself over the head with a skillet")
p.LastFact = nil
return true
}
// Allow users to change facts with a simple regexp
func (p *FactoidPlugin) changeFact(message msg.Message) bool {
func (p *FactoidPlugin) changeFact(c bot.Connector, message msg.Message) bool {
oper := changeOperator(message.Body)
parts := strings.SplitN(message.Body, oper, 2)
userexp := strings.TrimSpace(parts[1])
@ -553,7 +555,7 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool {
if len(parts) == 4 {
// replacement
if parts[0] != "s" {
p.Bot.Send(bot.Message, message.Channel, "Nah.")
p.Bot.Send(c, bot.Message, message.Channel, "Nah.")
}
find := parts[1]
replace := parts[2]
@ -571,10 +573,10 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool {
}
// make the changes
msg := fmt.Sprintf("Changing %d facts.", len(result))
p.Bot.Send(bot.Message, message.Channel, msg)
p.Bot.Send(c, bot.Message, message.Channel, msg)
reg, err := regexp.Compile(find)
if err != nil {
p.Bot.Send(bot.Message, message.Channel, "I don't really want to.")
p.Bot.Send(c, bot.Message, message.Channel, "I don't really want to.")
return false
}
for _, fact := range result {
@ -594,19 +596,19 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool {
Err(err).
Str("trigger", trigger).
Msg("Error getting facts")
p.Bot.Send(bot.Message, message.Channel, "bzzzt")
p.Bot.Send(c, bot.Message, message.Channel, "bzzzt")
return true
}
count := len(result)
if count == 0 {
p.Bot.Send(bot.Message, message.Channel, "I didn't find any facts like that.")
p.Bot.Send(c, bot.Message, message.Channel, "I didn't find any facts like that.")
return true
}
if parts[2] == "g" && len(result) > 4 {
// summarize
result = result[:4]
} else {
p.sayFact(message, *result[0])
p.sayFact(c, message, *result[0])
return true
}
msg := fmt.Sprintf("%s ", trigger)
@ -619,9 +621,9 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool {
if count > 4 {
msg = fmt.Sprintf("%s | ...and %d others", msg, count)
}
p.Bot.Send(bot.Message, message.Channel, msg)
p.Bot.Send(c, bot.Message, message.Channel, msg)
} else {
p.Bot.Send(bot.Message, message.Channel, "I don't know what you mean.")
p.Bot.Send(c, bot.Message, message.Channel, "I don't know what you mean.")
}
return true
}
@ -629,15 +631,15 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *FactoidPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *FactoidPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "what was that?" {
return p.tellThemWhatThatWas(message)
return p.tellThemWhatThatWas(c, message)
}
// This plugin has no business with normal messages
if !message.Command {
// look for any triggers in the db matching this message
return p.trigger(message)
return p.trigger(c, message)
}
if strings.HasPrefix(strings.ToLower(message.Body), "alias") {
@ -647,53 +649,53 @@ func (p *FactoidPlugin) message(kind bot.Kind, message msg.Message, args ...inte
m := strings.TrimPrefix(message.Body, "alias ")
parts := strings.SplitN(m, "->", 2)
if len(parts) != 2 {
p.Bot.Send(bot.Message, message.Channel, "If you want to alias something, use: `alias this -> that`")
p.Bot.Send(c, bot.Message, message.Channel, "If you want to alias something, use: `alias this -> that`")
return true
}
a := aliasFromStrings(strings.TrimSpace(parts[1]), strings.TrimSpace(parts[0]))
if err := a.save(p.db); err != nil {
p.Bot.Send(bot.Message, message.Channel, err.Error())
p.Bot.Send(c, bot.Message, message.Channel, err.Error())
} else {
p.Bot.Send(bot.Action, message.Channel, "learns a new synonym")
p.Bot.Send(c, bot.Action, message.Channel, "learns a new synonym")
}
return true
}
if strings.ToLower(message.Body) == "factoid" {
if fact := p.randomFact(); fact != nil {
p.sayFact(message, *fact)
p.sayFact(c, message, *fact)
return true
}
log.Debug().Msg("Got a nil fact.")
}
if strings.ToLower(message.Body) == "forget that" {
return p.forgetLastFact(message)
return p.forgetLastFact(c, message)
}
if changeOperator(message.Body) != "" {
return p.changeFact(message)
return p.changeFact(c, message)
}
action := findAction(message.Body)
if action != "" {
return p.learnAction(message, action)
return p.learnAction(c, message, action)
}
// look for any triggers in the db matching this message
if p.trigger(message) {
if p.trigger(c, message) {
return true
}
// We didn't find anything, panic!
p.Bot.Send(bot.Message, message.Channel, p.NotFound[rand.Intn(len(p.NotFound))])
p.Bot.Send(c, bot.Message, message.Channel, p.NotFound[rand.Intn(len(p.NotFound))])
return true
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *FactoidPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he <has> $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.")
p.Bot.Send(bot.Message, message.Channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.")
func (p *FactoidPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(c, bot.Message, message.Channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he <has> $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.")
p.Bot.Send(c, bot.Message, message.Channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.")
return true
}
@ -708,7 +710,7 @@ func (p *FactoidPlugin) randomFact() *Factoid {
}
// factTimer spits out a fact at a given interval and with given probability
func (p *FactoidPlugin) factTimer(channel string) {
func (p *FactoidPlugin) factTimer(c bot.Connector, channel string) {
quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime", 30)
if quoteTime == 0 {
quoteTime = 30
@ -749,7 +751,7 @@ func (p *FactoidPlugin) factTimer(channel string) {
User: &users[rand.Intn(len(users))],
Channel: channel,
}
p.sayFact(message, *fact)
p.sayFact(c, message, *fact)
myLastMsg = time.Now()
}
}

View File

@ -7,7 +7,7 @@ package fact
// 2016-01-15 Later note, why are these in plugins and the server is in bot?
var factoidIndex string = `
var factoidIndex = `
<!DOCTYPE html>
<html>
<head>

View File

@ -132,14 +132,14 @@ func isToday(t time.Time) bool {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *FirstPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
// This bot does not reply to anything
if p.First == nil && p.allowed(message) {
log.Debug().
Str("body", message.Body).
Msg("No previous first. Recording new first")
p.recordFirst(message)
p.recordFirst(c, message)
return false
} else if p.First != nil {
if isToday(p.First.time) && p.allowed(message) {
@ -148,7 +148,7 @@ func (p *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interf
Time("t0", p.First.time).
Time("t1", time.Now()).
Msg("Recording first")
p.recordFirst(message)
p.recordFirst(c, message)
return false
}
}
@ -157,7 +157,7 @@ func (p *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interf
"?", "", "!", "")
msg := strings.ToLower(message.Body)
if r.Replace(msg) == "whos on first" {
p.announceFirst(message)
p.announceFirst(c, message)
return true
}
@ -199,7 +199,7 @@ func (p *FirstPlugin) allowed(message msg.Message) bool {
return true
}
func (p *FirstPlugin) recordFirst(message msg.Message) {
func (p *FirstPlugin) recordFirst(c bot.Connector, message msg.Message) {
log.Info().
Str("user", message.User.Name).
Str("body", message.Body).
@ -216,13 +216,13 @@ func (p *FirstPlugin) recordFirst(message msg.Message) {
log.Error().Err(err).Msg("Error saving first entry")
return
}
p.announceFirst(message)
p.announceFirst(c, message)
}
func (p *FirstPlugin) announceFirst(message msg.Message) {
c := message.Channel
func (p *FirstPlugin) announceFirst(c bot.Connector, message msg.Message) {
ch := message.Channel
if p.First != nil {
p.Bot.Send(bot.Message, c, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
p.Bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
p.First.nick, p.First.time.Format("15:04"), p.First.body))
}
}
@ -235,7 +235,7 @@ func (p *FirstPlugin) LoadData() {
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *FirstPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.")
func (p *FirstPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(c, bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.")
return true
}

View File

@ -78,7 +78,7 @@ func (p *InventoryPlugin) itemFilter(input string) string {
return input
}
func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *InventoryPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
m := message.Body
log.Debug().Msgf("inventory trying to read %+v", message)
if message.Command {
@ -89,7 +89,7 @@ func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...in
log.Debug().Msgf("I think I have more than 0 items: %+v, len(items)=%d", items, len(items))
say = fmt.Sprintf("I'm currently holding %s", strings.Join(items, ", "))
}
p.bot.Send(bot.Message, message.Channel, say)
p.bot.Send(c, bot.Message, message.Channel, say)
return true
}
@ -97,11 +97,11 @@ func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...in
// <Randall> Bucket[:,] have a (.+)
if matches := p.r1.FindStringSubmatch(m); len(matches) > 0 {
log.Debug().Msgf("Found item to add: %s", matches[1])
return p.addItem(message, matches[1])
return p.addItem(c, message, matches[1])
}
if matches := p.r2.FindStringSubmatch(m); len(matches) > 0 {
log.Debug().Msgf("Found item to add: %s", matches[1])
return p.addItem(message, matches[1])
return p.addItem(c, message, matches[1])
}
}
if message.Action {
@ -112,15 +112,15 @@ func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...in
if matches := p.r3.FindStringSubmatch(m); len(matches) > 0 {
log.Debug().Msgf("Found item to add: %s", matches[1])
return p.addItem(message, matches[1])
return p.addItem(c, message, matches[1])
}
if matches := p.r4.FindStringSubmatch(m); len(matches) > 0 {
log.Debug().Msgf("Found item to add: %s", matches[1])
return p.addItem(message, matches[1])
return p.addItem(c, message, matches[1])
}
if matches := p.r5.FindStringSubmatch(m); len(matches) > 0 {
log.Debug().Msgf("Found item to add: %s", matches[1])
return p.addItem(message, matches[1])
return p.addItem(c, message, matches[1])
}
}
return false
@ -198,9 +198,9 @@ func (p *InventoryPlugin) remove(i string) {
}
}
func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
func (p *InventoryPlugin) addItem(c bot.Connector, m msg.Message, i string) bool {
if p.exists(i) {
p.bot.Send(bot.Message, m.Channel, fmt.Sprintf("I already have %s.", i))
p.bot.Send(c, bot.Message, m.Channel, fmt.Sprintf("I already have %s.", i))
return true
}
var removed string
@ -213,9 +213,9 @@ func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
log.Error().Err(err).Msg("Error inserting new inventory item")
}
if removed != "" {
p.bot.Send(bot.Action, m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name))
p.bot.Send(c, bot.Action, m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name))
} else {
p.bot.Send(bot.Action, m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name))
p.bot.Send(c, bot.Action, m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name))
}
return true
}

View File

@ -33,7 +33,7 @@ type leftpadResp struct {
Str string
}
func (p *LeftpadPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *LeftpadPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !message.Command {
return false
}
@ -43,20 +43,20 @@ func (p *LeftpadPlugin) message(kind bot.Kind, message msg.Message, args ...inte
padchar := parts[1]
length, err := strconv.Atoi(parts[2])
if err != nil {
p.bot.Send(bot.Message, message.Channel, "Invalid padding number")
p.bot.Send(c, bot.Message, message.Channel, "Invalid padding number")
return true
}
maxLen, who := p.config.GetInt("LeftPad.MaxLen", 50), p.config.Get("LeftPad.Who", "Putin")
if length > maxLen && maxLen > 0 {
msg := fmt.Sprintf("%s would kill me if I did that.", who)
p.bot.Send(bot.Message, message.Channel, msg)
p.bot.Send(c, bot.Message, message.Channel, msg)
return true
}
text := strings.Join(parts[3:], " ")
res := leftpad.LeftPad(text, length, padchar)
p.bot.Send(bot.Message, message.Channel, res)
p.bot.Send(c, bot.Message, message.Channel, res)
return true
}

View File

@ -3,6 +3,7 @@
package leftpad
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -13,12 +14,12 @@ import (
"github.com/velour/catbase/plugins/counter"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -40,7 +40,7 @@ func New(b bot.Bot) *NerdepediaPlugin {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *NerdepediaPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
lowerCase := strings.ToLower(message.Body)
query := ""
if lowerCase == "may the force be with you" || lowerCase == "help me obi-wan" {
@ -81,7 +81,7 @@ func (p *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...i
}
if description != "" && link != "" {
p.bot.Send(bot.Message, message.Channel, fmt.Sprintf("%s (%s)", description, link))
p.bot.Send(c, bot.Message, message.Channel, fmt.Sprintf("%s (%s)", description, link))
return true
}
}
@ -90,7 +90,7 @@ func (p *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...i
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *NerdepediaPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(bot.Message, message.Channel, "nerd stuff")
func (p *NerdepediaPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "nerd stuff")
return true
}

View File

@ -3,6 +3,7 @@
package nerdepedia
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -16,13 +16,13 @@ import (
)
type PickerPlugin struct {
Bot bot.Bot
bot bot.Bot
}
// NewPickerPlugin creates a new PickerPlugin with the Plugin interface
func New(b bot.Bot) *PickerPlugin {
pp := &PickerPlugin{
Bot: b,
bot: b,
}
b.Register(pp, bot.Message, pp.message)
b.Register(pp, bot.Help, pp.help)
@ -32,21 +32,21 @@ func New(b bot.Bot) *PickerPlugin {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *PickerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *PickerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !strings.HasPrefix(message.Body, "pick") {
return false
}
n, items, err := p.parse(message.Body)
if err != nil {
p.Bot.Send(bot.Message, message.Channel, err.Error())
p.bot.Send(c, bot.Message, message.Channel, err.Error())
return true
}
if n == 1 {
item := items[rand.Intn(len(items))]
out := fmt.Sprintf("I've chosen %q for you.", strings.TrimSpace(item))
p.Bot.Send(bot.Message, message.Channel, out)
p.bot.Send(c, bot.Message, message.Channel, out)
return true
}
@ -62,7 +62,7 @@ func (p *PickerPlugin) message(kind bot.Kind, message msg.Message, args ...inter
fmt.Fprintf(&b, ", %q", item)
}
b.WriteString(" }")
p.Bot.Send(bot.Message, message.Channel, b.String())
p.bot.Send(c, bot.Message, message.Channel, b.String())
return true
}
@ -111,7 +111,7 @@ func (p *PickerPlugin) parse(body string) (int, []string, error) {
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *PickerPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Choose from a list of options. Try \"pick {a,b,c}\".")
func (p *PickerPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "Choose from a list of options. Try \"pick {a,b,c}\".")
return true
}

View File

@ -3,6 +3,7 @@
package picker
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -11,38 +11,38 @@ import (
)
type ReactionPlugin struct {
Bot bot.Bot
Config *config.Config
bot bot.Bot
config *config.Config
}
func New(b bot.Bot) *ReactionPlugin {
rp := &ReactionPlugin{
Bot: b,
Config: b.Config(),
bot: b,
config: b.Config(),
}
b.Register(rp, bot.Message, rp.message)
return rp
}
func (p *ReactionPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *ReactionPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
harrass := false
for _, nick := range p.Config.GetArray("Reaction.HarrassList", []string{}) {
for _, nick := range p.config.GetArray("Reaction.HarrassList", []string{}) {
if message.User.Name == nick {
harrass = true
break
}
}
chance := p.Config.GetFloat64("Reaction.GeneralChance", 0.01)
chance := p.config.GetFloat64("Reaction.GeneralChance", 0.01)
negativeWeight := 1
if harrass {
chance = p.Config.GetFloat64("Reaction.HarrassChance", 0.05)
negativeWeight = p.Config.GetInt("Reaction.NegativeHarrassmentMultiplier", 2)
chance = p.config.GetFloat64("Reaction.HarrassChance", 0.05)
negativeWeight = p.config.GetInt("Reaction.NegativeHarrassmentMultiplier", 2)
}
if rand.Float64() < chance {
numPositiveReactions := len(p.Config.GetArray("Reaction.PositiveReactions", []string{}))
numNegativeReactions := len(p.Config.GetArray("Reaction.NegativeReactions", []string{}))
numPositiveReactions := len(p.config.GetArray("Reaction.PositiveReactions", []string{}))
numNegativeReactions := len(p.config.GetArray("Reaction.NegativeReactions", []string{}))
maxIndex := numPositiveReactions + numNegativeReactions*negativeWeight
@ -51,14 +51,14 @@ func (p *ReactionPlugin) message(kind bot.Kind, message msg.Message, args ...int
reaction := ""
if index < numPositiveReactions {
reaction = p.Config.GetArray("Reaction.PositiveReactions", []string{})[index]
reaction = p.config.GetArray("Reaction.PositiveReactions", []string{})[index]
} else {
index -= numPositiveReactions
index %= numNegativeReactions
reaction = p.Config.GetArray("Reaction.NegativeReactions", []string{})[index]
reaction = p.config.GetArray("Reaction.NegativeReactions", []string{})[index]
}
p.Bot.Send(bot.Reaction, message.Channel, reaction, message)
p.bot.Send(c, bot.Reaction, message.Channel, reaction, message)
}
return false

View File

@ -32,10 +32,10 @@ func New(b bot.Bot) *RememberPlugin {
return p
}
func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *RememberPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "quote" && message.Command {
q := p.randQuote()
p.bot.Send(bot.Message, message.Channel, q)
p.bot.Send(c, bot.Message, message.Channel, q)
// is it evil not to remember that the user said quote?
return true
@ -82,7 +82,7 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
}
if err := fact.Save(p.db); err != nil {
log.Error().Err(err)
p.bot.Send(bot.Message, message.Channel, "Tell somebody I'm broke.")
p.bot.Send(c, bot.Message, message.Channel, "Tell somebody I'm broke.")
}
log.Info().
@ -92,13 +92,13 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
// sorry, not creative with names so we're reusing msg
msg = fmt.Sprintf("Okay, %s, remembering '%s'.",
message.User.Name, msg)
p.bot.Send(bot.Message, message.Channel, msg)
p.bot.Send(c, bot.Message, message.Channel, msg)
p.recordMsg(message)
return true
}
}
p.bot.Send(bot.Message, message.Channel, "Sorry, I don't know that phrase.")
p.bot.Send(c, bot.Message, message.Channel, "Sorry, I don't know that phrase.")
p.recordMsg(message)
return true
}
@ -107,13 +107,13 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
return false
}
func (p *RememberPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *RememberPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
msg := "remember will let you quote your idiot friends. Just type " +
"!remember <nick> <snippet> to remember what they said. Snippet can " +
"be any part of their message. Later on, you can ask for a random " +
"!quote."
p.bot.Send(bot.Message, message.Channel, msg)
p.bot.Send(c, bot.Message, message.Channel, msg)
return true
}

View File

@ -1,6 +1,7 @@
package remember
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -43,7 +44,7 @@ func TestCornerCaseBug(t *testing.T) {
p, _, mb := makePlugin(t)
for _, m := range msgs {
p.message(bot.Message, m)
p.message(&cli.CliPlugin{}, bot.Message, m)
}
assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "horse dick")

View File

@ -27,7 +27,7 @@ const (
)
type ReminderPlugin struct {
Bot bot.Bot
bot bot.Bot
db *sqlx.DB
mutex *sync.Mutex
timer *time.Timer
@ -65,7 +65,7 @@ func New(b bot.Bot) *ReminderPlugin {
w.Add(common.All...)
plugin := &ReminderPlugin{
Bot: b,
bot: b,
db: b.DB(),
mutex: &sync.Mutex{},
timer: timer,
@ -75,7 +75,7 @@ func New(b bot.Bot) *ReminderPlugin {
plugin.queueUpNextReminder()
go reminderer(plugin)
go reminderer(b.DefaultConnector(), plugin)
b.Register(plugin, bot.Message, plugin.message)
b.Register(plugin, bot.Help, plugin.help)
@ -83,7 +83,7 @@ func New(b bot.Bot) *ReminderPlugin {
return plugin
}
func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *ReminderPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
channel := message.Channel
from := message.User.Name
@ -109,7 +109,7 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int
dur, err = time.ParseDuration(parts[3])
if err != nil {
p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.")
p.bot.Send(c, bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.")
return true
}
@ -137,7 +137,7 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int
dur2, err = time.ParseDuration(parts[5])
if err != nil {
log.Error().Err(err)
p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.")
p.bot.Send(c, bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.")
return true
}
@ -148,7 +148,7 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int
max := p.config.GetInt("Reminder.MaxBatchAdd", 10)
for i := 0; when.Before(endTime); i++ {
if i >= max {
p.Bot.Send(bot.Message, channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.")
p.bot.Send(c, bot.Message, channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.")
doConfirm = false
break
}
@ -165,14 +165,14 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int
when = when.Add(dur)
}
} else {
p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I comprehend what you're asking.")
p.bot.Send(c, bot.Message, channel, "Easy cowboy, not sure I comprehend what you're asking.")
return true
}
if doConfirm && from == who {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("Okay. I'll remind you."))
p.bot.Send(c, bot.Message, channel, fmt.Sprintf("Okay. I'll remind you."))
} else if doConfirm {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("Sure %s, I'll remind %s.", from, who))
p.bot.Send(c, bot.Message, channel, fmt.Sprintf("Sure %s, I'll remind %s.", from, who))
}
p.queueUpNextReminder()
@ -192,22 +192,22 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int
}
}
if err != nil {
p.Bot.Send(bot.Message, channel, "listing failed.")
p.bot.Send(c, bot.Message, channel, "listing failed.")
} else {
p.Bot.Send(bot.Message, channel, response)
p.bot.Send(c, bot.Message, channel, response)
}
return true
} else if len(parts) == 3 && strings.ToLower(parts[0]) == "cancel" && strings.ToLower(parts[1]) == "reminder" {
id, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("couldn't parse id: %s", parts[2]))
p.bot.Send(c, bot.Message, channel, fmt.Sprintf("couldn't parse id: %s", parts[2]))
} else {
err := p.deleteReminder(id)
if err == nil {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("successfully canceled reminder: %s", parts[2]))
p.bot.Send(c, bot.Message, channel, fmt.Sprintf("successfully canceled reminder: %s", parts[2]))
} else {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("failed to find and cancel reminder: %s", parts[2]))
p.bot.Send(c, bot.Message, channel, fmt.Sprintf("failed to find and cancel reminder: %s", parts[2]))
}
}
return true
@ -216,8 +216,8 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int
return false
}
func (p *ReminderPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Pester someone with a reminder. Try \"remind <user> in <duration> message\".\n\nUnsure about duration syntax? Check https://golang.org/pkg/time/#ParseDuration")
func (p *ReminderPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "Pester someone with a reminder. Try \"remind <user> in <duration> message\".\n\nUnsure about duration syntax? Check https://golang.org/pkg/time/#ParseDuration")
return true
}
@ -351,7 +351,7 @@ func (p *ReminderPlugin) queueUpNextReminder() {
}
}
func reminderer(p *ReminderPlugin) {
func reminderer(c bot.Connector, p *ReminderPlugin) {
for {
<-p.timer.C
@ -366,7 +366,7 @@ func reminderer(p *ReminderPlugin) {
message = fmt.Sprintf("Hey %s, %s wanted you to be reminded: %s", reminder.who, reminder.from, reminder.what)
}
p.Bot.Send(bot.Message, reminder.channel, message)
p.bot.Send(c, bot.Message, reminder.channel, message)
if err := p.deleteReminder(reminder.id); err != nil {
log.Error().

View File

@ -4,6 +4,7 @@ package reminder
import (
"fmt"
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
"time"
@ -14,16 +15,16 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
return makeMessageBy(payload, "tester")
}
func makeMessageBy(payload, by string) (bot.Kind, msg.Message) {
func makeMessageBy(payload, by string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: by},
Channel: "test",
Body: payload,
@ -223,6 +224,6 @@ func TestLimitList(t *testing.T) {
func TestHelp(t *testing.T) {
c, mb := setup(t)
assert.NotNil(t, c)
c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1)
}

View File

@ -20,7 +20,7 @@ const (
)
type RPGPlugin struct {
Bot bot.Bot
bot bot.Bot
listenFor map[string]*board
}
@ -99,7 +99,7 @@ func (b *board) checkAndMove(dx, dy int) int {
func New(b bot.Bot) *RPGPlugin {
rpg := &RPGPlugin{
Bot: b,
bot: b,
listenFor: map[string]*board{},
}
b.Register(rpg, bot.Message, rpg.message)
@ -108,25 +108,25 @@ func New(b bot.Bot) *RPGPlugin {
return rpg
}
func (p *RPGPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *RPGPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "start rpg" {
b := NewRandomBoard()
ts, _ := p.Bot.Send(bot.Message, message.Channel, b.toMessageString())
ts, _ := p.bot.Send(c, bot.Message, message.Channel, b.toMessageString())
p.listenFor[ts] = b
p.Bot.Send(bot.Reply, message.Channel, "Over here.", ts)
p.bot.Send(c, bot.Reply, message.Channel, "Over here.", ts)
return true
}
return false
}
func (p *RPGPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Go find a walkthrough or something.")
func (p *RPGPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "Go find a walkthrough or something.")
return true
}
func (p *RPGPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *RPGPlugin) replyMessage(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
identifier := args[0].(string)
if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) {
if strings.ToLower(message.User.Name) != strings.ToLower(p.bot.Config().Get("Nick", "bot")) {
if b, ok := p.listenFor[identifier]; ok {
var res int
@ -145,12 +145,12 @@ func (p *RPGPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...int
switch res {
case OK:
p.Bot.Send(bot.Edit, message.Channel, b.toMessageString(), identifier)
p.bot.Send(c, bot.Edit, message.Channel, b.toMessageString(), identifier)
case WIN:
p.Bot.Send(bot.Edit, message.Channel, b.toMessageString(), identifier)
p.Bot.Send(bot.Reply, message.Channel, "congratulations, you beat the easiest level imaginable.", identifier)
p.bot.Send(c, bot.Edit, message.Channel, b.toMessageString(), identifier)
p.bot.Send(c, bot.Reply, message.Channel, "congratulations, you beat the easiest level imaginable.", identifier)
case INVALID:
p.Bot.Send(bot.Reply, message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier)
p.bot.Send(c, bot.Reply, message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier)
}
return true
}

View File

@ -1,3 +1 @@
package rpgORdie
import ()

View File

@ -12,7 +12,7 @@ import (
)
type RSSPlugin struct {
Bot bot.Bot
bot bot.Bot
cache map[string]*cacheItem
shelfLife time.Duration
maxLines int
@ -51,7 +51,7 @@ func (c *cacheItem) getCurrentPage(maxLines int) string {
func New(b bot.Bot) *RSSPlugin {
rss := &RSSPlugin{
Bot: b,
bot: b,
cache: map[string]*cacheItem{},
shelfLife: time.Minute * time.Duration(b.Config().GetInt("rss.shelfLife", 20)),
maxLines: b.Config().GetInt("rss.maxLines", 5),
@ -61,19 +61,19 @@ func New(b bot.Bot) *RSSPlugin {
return rss
}
func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *RSSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
tokens := strings.Fields(message.Body)
numTokens := len(tokens)
if numTokens == 2 && strings.ToLower(tokens[0]) == "rss" {
if item, ok := p.cache[strings.ToLower(tokens[1])]; ok && time.Now().Before(item.expiration) {
p.Bot.Send(bot.Message, message.Channel, item.getCurrentPage(p.maxLines))
p.bot.Send(c, bot.Message, message.Channel, item.getCurrentPage(p.maxLines))
return true
} else {
fp := gofeed.NewParser()
feed, err := fp.ParseURL(tokens[1])
if err != nil {
p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("RSS error: %s", err.Error()))
p.bot.Send(c, bot.Message, message.Channel, fmt.Sprintf("RSS error: %s", err.Error()))
return true
}
item := &cacheItem{
@ -89,7 +89,7 @@ func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interfac
p.cache[strings.ToLower(tokens[1])] = item
p.Bot.Send(bot.Message, message.Channel, item.getCurrentPage(p.maxLines))
p.bot.Send(c, bot.Message, message.Channel, item.getCurrentPage(p.maxLines))
return true
}
}
@ -98,7 +98,7 @@ func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interfac
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *RSSPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "try '!rss http://rss.cnn.com/rss/edition.rss'")
func (p *RSSPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "try '!rss http://rss.cnn.com/rss/edition.rss'")
return true
}

View File

@ -2,6 +2,7 @@ package rss
import (
"fmt"
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -11,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -19,7 +19,7 @@ const (
)
type SisyphusPlugin struct {
Bot bot.Bot
bot bot.Bot
listenFor map[string]*game
}
@ -38,7 +38,7 @@ type game struct {
nextAns int
}
func NewRandomGame(b bot.Bot, channel, who string) *game {
func NewRandomGame(c bot.Connector, b bot.Bot, channel, who string) *game {
size := rand.Intn(9) + 2
g := game{
channel: channel,
@ -48,32 +48,32 @@ func NewRandomGame(b bot.Bot, channel, who string) *game {
size: size,
current: size / 2,
}
g.id, _ = b.Send(bot.Message, channel, g.toMessageString())
g.id, _ = b.Send(c, bot.Message, channel, g.toMessageString())
g.schedulePush()
g.scheduleDecrement()
g.schedulePush(c)
g.scheduleDecrement(c)
return &g
}
func (g *game) scheduleDecrement() {
func (g *game) scheduleDecrement(c bot.Connector) {
if g.timers[0] != nil {
g.timers[0].Stop()
}
minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement", 10)
maxDec := g.bot.Config().GetInt("Sisyphus.MaxDecrement", 30)
g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute)
g.nextDec = time.Now().Add(time.Duration(minDec+rand.Intn(maxDec)) * time.Minute)
go func() {
t := time.NewTimer(g.nextDec.Sub(time.Now()))
g.timers[0] = t
select {
case <-t.C:
g.handleDecrement()
g.handleDecrement(c)
}
}()
}
func (g *game) schedulePush() {
func (g *game) schedulePush(c bot.Connector) {
if g.timers[1] != nil {
g.timers[1].Stop()
}
@ -85,7 +85,7 @@ func (g *game) schedulePush() {
g.timers[1] = t
select {
case <-t.C:
g.handleNotify()
g.handleNotify(c)
}
}()
}
@ -97,21 +97,21 @@ func (g *game) endGame() {
g.ended = true
}
func (g *game) handleDecrement() {
func (g *game) handleDecrement(c bot.Connector) {
g.current++
g.bot.Send(bot.Edit, g.channel, g.toMessageString(), g.id)
g.bot.Send(c, bot.Edit, g.channel, g.toMessageString(), g.id)
if g.current > g.size-2 {
g.bot.Send(bot.Reply, g.channel, "you lose", g.id)
g.bot.Send(c, bot.Reply, g.channel, "you lose", g.id)
msg := fmt.Sprintf("%s just lost the game after %s", g.who, time.Now().Sub(g.start))
g.bot.Send(bot.Message, g.channel, msg)
g.bot.Send(c, bot.Message, g.channel, msg)
g.endGame()
} else {
g.scheduleDecrement()
g.scheduleDecrement(c)
}
}
func (g *game) handleNotify() {
g.bot.Send(bot.Reply, g.channel, "You can push now.\n"+g.generateQuestion(), g.id)
func (g *game) handleNotify(c bot.Connector) {
g.bot.Send(c, bot.Reply, g.channel, "You can push now.\n"+g.generateQuestion(), g.id)
}
func (g *game) generateQuestion() string {
@ -164,7 +164,7 @@ func (g *game) toMessageString() string {
func New(b bot.Bot) *SisyphusPlugin {
sp := &SisyphusPlugin{
Bot: b,
bot: b,
listenFor: map[string]*game{},
}
b.Register(sp, bot.Message, sp.message)
@ -173,24 +173,24 @@ func New(b bot.Bot) *SisyphusPlugin {
return sp
}
func (p *SisyphusPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *SisyphusPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "start sisyphus" {
b := NewRandomGame(p.Bot, message.Channel, message.User.Name)
b := NewRandomGame(c, p.bot, message.Channel, message.User.Name)
p.listenFor[b.id] = b
p.Bot.Send(bot.Reply, message.Channel, "Over here.", b.id)
p.bot.Send(c, bot.Reply, message.Channel, "Over here.", b.id)
return true
}
return false
}
func (p *SisyphusPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "https://en.wikipedia.org/wiki/Sisyphus")
func (p *SisyphusPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "https://en.wikipedia.org/wiki/Sisyphus")
return true
}
func (p *SisyphusPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *SisyphusPlugin) replyMessage(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
identifier := args[0].(string)
if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) {
if strings.ToLower(message.User.Name) != strings.ToLower(p.bot.Config().Get("Nick", "bot")) {
if g, ok := p.listenFor[identifier]; ok {
log.Debug().Msgf("got message on %s: %+v", identifier, message)
@ -206,18 +206,18 @@ func (p *SisyphusPlugin) replyMessage(kind bot.Kind, message msg.Message, args .
if time.Now().After(g.nextPush) {
if g.checkAnswer(message.Body) {
p.Bot.Send(bot.Edit, message.Channel, g.toMessageString(), identifier)
g.schedulePush()
p.bot.Send(c, bot.Edit, message.Channel, g.toMessageString(), identifier)
g.schedulePush(c)
msg := fmt.Sprintf("Ok. You can push again in %s", g.nextPush.Sub(time.Now()))
p.Bot.Send(bot.Reply, message.Channel, msg, identifier)
p.bot.Send(c, bot.Reply, message.Channel, msg, identifier)
} else {
p.Bot.Send(bot.Reply, message.Channel, "you lose", identifier)
p.bot.Send(c, bot.Reply, message.Channel, "you lose", identifier)
msg := fmt.Sprintf("%s just lost the sisyphus game after %s", g.who, time.Now().Sub(g.start))
p.Bot.Send(bot.Message, message.Channel, msg)
p.bot.Send(c, bot.Message, message.Channel, msg)
g.endGame()
}
} else {
p.Bot.Send(bot.Reply, message.Channel, "you cannot push yet", identifier)
p.bot.Send(c, bot.Reply, message.Channel, "you cannot push yet", identifier)
}
return true
}

View File

@ -17,7 +17,7 @@ import (
"github.com/velour/catbase/config"
)
var goatse []string = []string{
var goatse = []string{
"```* g o a t s e x * g o a t s e x * g o a t s e x *",
"g g",
"o / \\ \\ / \\ o",
@ -46,23 +46,23 @@ var goatse []string = []string{
}
type TalkerPlugin struct {
Bot bot.Bot
bot bot.Bot
config *config.Config
sayings []string
}
func New(b bot.Bot) *TalkerPlugin {
tp := &TalkerPlugin{
Bot: b,
bot: b,
config: b.Config(),
}
b.Register(tp, bot.Message, tp.message)
b.Register(tp, bot.Help, tp.help)
tp.registerWeb()
tp.registerWeb(b.DefaultConnector())
return tp
}
func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *TalkerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
channel := message.Channel
body := message.Body
lowermessage := strings.ToLower(body)
@ -70,24 +70,24 @@ func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...inter
if message.Command && strings.HasPrefix(lowermessage, "cowsay") {
msg, err := p.cowSay(strings.TrimPrefix(message.Body, "cowsay "))
if err != nil {
p.Bot.Send(bot.Message, channel, "Error running cowsay: %s", err)
p.bot.Send(c, bot.Message, channel, "Error running cowsay: %s", err)
return true
}
p.Bot.Send(bot.Message, channel, msg)
p.bot.Send(c, bot.Message, channel, msg)
return true
}
if message.Command && strings.HasPrefix(lowermessage, "list cows") {
cows := p.allCows()
m := fmt.Sprintf("Cows: %s", strings.Join(cows, ", "))
p.Bot.Send(bot.Message, channel, m)
p.bot.Send(c, bot.Message, channel, m)
return true
}
// TODO: This ought to be space split afterwards to remove any punctuation
if message.Command && strings.HasPrefix(lowermessage, "say") {
msg := strings.TrimSpace(body[3:])
p.Bot.Send(bot.Message, channel, msg)
p.bot.Send(c, bot.Message, channel, msg)
return true
}
@ -103,15 +103,15 @@ func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...inter
line = strings.Replace(line, "{nick}", nick, 1)
output += line + "\n"
}
p.Bot.Send(bot.Message, channel, output)
p.bot.Send(c, bot.Message, channel, output)
return true
}
return false
}
func (p *TalkerPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Hi, this is talker. I like to talk about FredFelps!")
func (p *TalkerPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "Hi, this is talker. I like to talk about FredFelps!")
return true
}
@ -170,7 +170,7 @@ func (p *TalkerPlugin) allCows() []string {
return cows
}
func (p *TalkerPlugin) registerWeb() {
func (p *TalkerPlugin) registerWeb(c bot.Connector) {
http.HandleFunc("/slash/cowsay", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
log.Debug().Msgf("Cowsay:\n%+v", r.PostForm.Get("text"))
@ -178,10 +178,10 @@ func (p *TalkerPlugin) registerWeb() {
log.Debug().Msgf("channel: %s", channel)
msg, err := p.cowSay(r.PostForm.Get("text"))
if err != nil {
p.Bot.Send(bot.Message, channel, fmt.Sprintf("Error running cowsay: %s", err))
p.bot.Send(c, bot.Message, channel, fmt.Sprintf("Error running cowsay: %s", err))
return
}
p.Bot.Send(bot.Message, channel, msg)
p.bot.Send(c, bot.Message, channel, msg)
w.WriteHeader(200)
})
}

View File

@ -3,6 +3,7 @@
package talker
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,
@ -78,6 +79,6 @@ func TestHelp(t *testing.T) {
mb := bot.NewMockBot()
c := New(mb)
assert.NotNil(t, c)
c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1)
}

View File

@ -21,20 +21,20 @@ func New(b bot.Bot) *TellPlugin {
return tp
}
func (t *TellPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (t *TellPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.HasPrefix(strings.ToLower(message.Body), "tell") {
parts := strings.Split(message.Body, " ")
target := strings.ToLower(parts[1])
newMessage := strings.Join(parts[2:], " ")
newMessage = fmt.Sprintf("Hey, %s. %s said: %s", target, message.User.Name, newMessage)
t.users[target] = append(t.users[target], newMessage)
t.b.Send(bot.Message, message.Channel, fmt.Sprintf("Okay. I'll tell %s.", target))
t.b.Send(c, bot.Message, message.Channel, fmt.Sprintf("Okay. I'll tell %s.", target))
return true
}
uname := strings.ToLower(message.User.Name)
if msg, ok := t.users[uname]; ok && len(msg) > 0 {
for _, m := range msg {
t.b.Send(bot.Message, message.Channel, string(m))
t.b.Send(c, bot.Message, message.Channel, string(m))
}
t.users[uname] = []string{}
return true

View File

@ -38,11 +38,11 @@ func New(b bot.Bot) *TLDRPlugin {
return plugin
}
func (p *TLDRPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *TLDRPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
timeLimit := time.Duration(p.bot.Config().GetInt("TLDR.HourLimit", 1))
lowercaseMessage := strings.ToLower(message.Body)
if lowercaseMessage == "tl;dr" && p.lastRequest.After(time.Now().Add(-timeLimit*time.Hour)) {
p.bot.Send(bot.Message, message.Channel, "Slow down, cowboy. Read that tiny backlog.")
p.bot.Send(c, bot.Message, message.Channel, "Slow down, cowboy. Read that tiny backlog.")
return true
} else if lowercaseMessage == "tl;dr" {
p.lastRequest = time.Now()
@ -114,7 +114,7 @@ func (p *TLDRPlugin) message(kind bot.Kind, message msg.Message, args ...interfa
}
p.bot.Send(bot.Message, message.Channel, response)
p.bot.Send(c, bot.Message, message.Channel, response)
return true
}
@ -162,8 +162,8 @@ func (p *TLDRPlugin) getTopics() []string {
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *TLDRPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(bot.Message, message.Channel, "tl;dr")
func (p *TLDRPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "tl;dr")
return true
}

View File

@ -1,6 +1,7 @@
package tldr
import (
"github.com/velour/catbase/plugins/cli"
"os"
"strconv"
"strings"
@ -19,12 +20,12 @@ func init() {
log.Logger = log.Logger.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}
func makeMessageBy(payload, by string) (bot.Kind, msg.Message) {
func makeMessageBy(payload, by string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: by},
Channel: "test",
Body: payload,
@ -32,7 +33,7 @@ func makeMessageBy(payload, by string) (bot.Kind, msg.Message) {
}
}
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
return makeMessageBy(payload, "tester")
}

View File

@ -24,7 +24,7 @@ const (
)
type TwitchPlugin struct {
Bot bot.Bot
bot bot.Bot
config *config.Config
twitchList map[string]*Twitcher
}
@ -60,7 +60,7 @@ type stream struct {
func New(b bot.Bot) *TwitchPlugin {
p := &TwitchPlugin{
Bot: b,
bot: b,
config: b.Config(),
twitchList: map[string]*Twitcher{},
}
@ -74,7 +74,7 @@ func New(b bot.Bot) *TwitchPlugin {
}
}
}
go p.twitchLoop(ch)
go p.twitchLoop(b.DefaultConnector(), ch)
}
b.Register(p, bot.Message, p.message)
@ -119,14 +119,14 @@ func (p *TwitchPlugin) serveStreaming(w http.ResponseWriter, r *http.Request) {
}
}
func (p *TwitchPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *TwitchPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
body := strings.ToLower(message.Body)
if body == "twitch status" {
channel := message.Channel
if users := p.config.GetArray("Twitch."+channel+".Users", []string{}); len(users) > 0 {
for _, twitcherName := range users {
if _, ok := p.twitchList[twitcherName]; ok {
p.checkTwitch(channel, p.twitchList[twitcherName], true)
p.checkTwitch(c, channel, p.twitchList[twitcherName], true)
}
}
}
@ -140,18 +140,18 @@ func (p *TwitchPlugin) message(kind bot.Kind, message msg.Message, args ...inter
return false
}
func (p *TwitchPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *TwitchPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
msg := "You can set the templates for streams with\n"
msg += fmt.Sprintf("twitch.istpl (default: %s)\n", isStreamingTplFallback)
msg += fmt.Sprintf("twitch.nottpl (default: %s)\n", notStreamingTplFallback)
msg += fmt.Sprintf("twitch.stoppedtpl (default: %s)\n", stoppedStreamingTplFallback)
msg += "You can reset all messages with `!reset twitch`"
msg += "And you can ask who is streaming with `!twitch status`"
p.Bot.Send(bot.Message, message.Channel, msg)
p.bot.Send(c, bot.Message, message.Channel, msg)
return true
}
func (p *TwitchPlugin) twitchLoop(channel string) {
func (p *TwitchPlugin) twitchLoop(c bot.Connector, channel string) {
frequency := p.config.GetInt("Twitch.Freq", 60)
if p.config.Get("twitch.clientid", "") == "" || p.config.Get("twitch.authorization", "") == "" {
log.Info().Msgf("Disabling twitch autochecking.")
@ -164,7 +164,7 @@ func (p *TwitchPlugin) twitchLoop(channel string) {
time.Sleep(time.Duration(frequency) * time.Second)
for _, twitcherName := range p.config.GetArray("Twitch."+channel+".Users", []string{}) {
p.checkTwitch(channel, p.twitchList[twitcherName], false)
p.checkTwitch(c, channel, p.twitchList[twitcherName], false)
}
}
}
@ -197,7 +197,7 @@ errCase:
return []byte{}, false
}
func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPrintStatus bool) {
func (p *TwitchPlugin) checkTwitch(c bot.Connector, channel string, twitcher *Twitcher, alwaysPrintStatus bool) {
baseURL, err := url.Parse("https://api.twitch.tv/helix/streams")
if err != nil {
log.Error().Msg("Error parsing twitch stream URL")
@ -255,31 +255,31 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri
t, err := template.New("notStreaming").Parse(notStreamingTpl)
if err != nil {
log.Error().Err(err)
p.Bot.Send(bot.Message, channel, err)
p.bot.Send(c, bot.Message, channel, err)
t = template.Must(template.New("notStreaming").Parse(notStreamingTplFallback))
}
t.Execute(&buf, info)
p.Bot.Send(bot.Message, channel, buf.String())
p.bot.Send(c, bot.Message, channel, buf.String())
} else {
t, err := template.New("isStreaming").Parse(isStreamingTpl)
if err != nil {
log.Error().Err(err)
p.Bot.Send(bot.Message, channel, err)
p.bot.Send(c, bot.Message, channel, err)
t = template.Must(template.New("isStreaming").Parse(isStreamingTplFallback))
}
t.Execute(&buf, info)
p.Bot.Send(bot.Message, channel, buf.String())
p.bot.Send(c, bot.Message, channel, buf.String())
}
} else if gameID == "" {
if twitcher.gameID != "" {
t, err := template.New("stoppedStreaming").Parse(stoppedStreamingTpl)
if err != nil {
log.Error().Err(err)
p.Bot.Send(bot.Message, channel, err)
p.bot.Send(c, bot.Message, channel, err)
t = template.Must(template.New("stoppedStreaming").Parse(stoppedStreamingTplFallback))
}
t.Execute(&buf, info)
p.Bot.Send(bot.Message, channel, buf.String())
p.bot.Send(c, bot.Message, channel, buf.String())
}
twitcher.gameID = ""
} else {
@ -287,11 +287,11 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri
t, err := template.New("isStreaming").Parse(isStreamingTpl)
if err != nil {
log.Error().Err(err)
p.Bot.Send(bot.Message, channel, err)
p.bot.Send(c, bot.Message, channel, err)
t = template.Must(template.New("isStreaming").Parse(isStreamingTplFallback))
}
t.Execute(&buf, info)
p.Bot.Send(bot.Message, channel, buf.String())
p.bot.Send(c, bot.Message, channel, buf.String())
}
twitcher.gameID = gameID
}

View File

@ -3,6 +3,7 @@
package twitch
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -30,7 +30,7 @@ func New(b bot.Bot) *YourPlugin {
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *YourPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *YourPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
maxLen := p.config.GetInt("your.maxlength", 140)
if len(message.Body) > maxLen {
return false
@ -46,14 +46,14 @@ func (p *YourPlugin) message(kind bot.Kind, message msg.Message, args ...interfa
}
}
if msg != message.Body {
p.bot.Send(bot.Message, message.Channel, msg)
p.bot.Send(c, bot.Message, message.Channel, msg)
return true
}
return false
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *YourPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(bot.Message, message.Channel, "Your corrects people's grammar.")
func (p *YourPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "Your corrects people's grammar.")
return true
}

View File

@ -3,6 +3,7 @@
package your
import (
"github.com/velour/catbase/plugins/cli"
"strings"
"testing"
@ -12,12 +13,12 @@ import (
"github.com/velour/catbase/bot/user"
)
func makeMessage(payload string) (bot.Kind, msg.Message) {
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!")
if isCmd {
payload = payload[1:]
}
return bot.Message, msg.Message{
return &cli.CliPlugin{}, bot.Message, msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,

View File

@ -37,7 +37,7 @@ func New(b bot.Bot) bot.Plugin {
return z
}
func (p *ZorkPlugin) runZork(ch string) error {
func (p *ZorkPlugin) runZork(c bot.Connector, ch string) error {
const importString = "github.com/velour/catbase/plugins/zork"
pkg, err := build.Import(importString, "", build.FindOnly)
if err != nil {
@ -79,7 +79,7 @@ func (p *ZorkPlugin) runZork(ch string) error {
m := strings.Replace(s.Text(), ">", "", -1)
m = strings.Replace(m, "\n", "\n>", -1)
m = ">" + m + "\n"
p.bot.Send(bot.Message, ch, m)
p.bot.Send(c, bot.Message, ch, m)
}
}()
go func() {
@ -95,7 +95,7 @@ func (p *ZorkPlugin) runZork(ch string) error {
return nil
}
func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
func (p *ZorkPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
m := strings.ToLower(message.Body)
log.Debug().Msgf("got message [%s]", m)
if ts := strings.Fields(m); len(ts) < 1 || ts[0] != "zork" {
@ -107,8 +107,8 @@ func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interfa
p.Lock()
defer p.Unlock()
if p.zorks[ch] == nil {
if err := p.runZork(ch); err != nil {
p.bot.Send(bot.Message, ch, "failed to run zork: "+err.Error())
if err := p.runZork(c, ch); err != nil {
p.bot.Send(c, bot.Message, ch, "failed to run zork: "+err.Error())
return true
}
}
@ -117,7 +117,7 @@ func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interfa
return true
}
func (p *ZorkPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(bot.Message, message.Channel, "Play zork using 'zork <zork command>'.")
func (p *ZorkPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(c, bot.Message, message.Channel, "Play zork using 'zork <zork command>'.")
return true
}