mirror of https://github.com/velour/catbase.git
commit
120a9474de
|
@ -246,7 +246,7 @@ func (b *bot) RegisterFilter(name string, f func(string) string) {
|
||||||
|
|
||||||
// Register a callback
|
// Register a callback
|
||||||
func (b *bot) Register(p Plugin, kind Kind, cb Callback) {
|
func (b *bot) Register(p Plugin, kind Kind, cb Callback) {
|
||||||
t := reflect.TypeOf(p)
|
t := reflect.TypeOf(p).String()
|
||||||
if _, ok := b.callbacks[t]; !ok {
|
if _, ok := b.callbacks[t]; !ok {
|
||||||
b.callbacks[t] = make(map[Kind][]Callback)
|
b.callbacks[t] = make(map[Kind][]Callback)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool {
|
||||||
if kind == Message && strings.HasPrefix(msg.Body, "help") && msg.Command {
|
if kind == Message && strings.HasPrefix(msg.Body, "help") && msg.Command {
|
||||||
parts := strings.Fields(strings.ToLower(msg.Body))
|
parts := strings.Fields(strings.ToLower(msg.Body))
|
||||||
b.checkHelp(msg.Channel, parts)
|
b.checkHelp(msg.Channel, parts)
|
||||||
|
log.Println("Handled a help, returning")
|
||||||
goto RET
|
goto RET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ RET:
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
|
func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
|
||||||
t := reflect.TypeOf(plugin)
|
t := reflect.TypeOf(plugin).String()
|
||||||
for _, cb := range b.callbacks[t][evt] {
|
for _, cb := range b.callbacks[t][evt] {
|
||||||
if cb(evt, message, args...) {
|
if cb(evt, message, args...) {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
package bot
|
package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/velour/catbase/bot/msg"
|
"github.com/velour/catbase/bot/msg"
|
||||||
"github.com/velour/catbase/bot/user"
|
"github.com/velour/catbase/bot/user"
|
||||||
|
@ -34,7 +32,7 @@ const (
|
||||||
|
|
||||||
type Kind int
|
type Kind int
|
||||||
type Callback func(Kind, msg.Message, ...interface{}) bool
|
type Callback func(Kind, msg.Message, ...interface{}) bool
|
||||||
type CallbackMap map[reflect.Type]map[Kind][]Callback
|
type CallbackMap map[string]map[Kind][]Callback
|
||||||
|
|
||||||
// Bot interface serves to allow mocking of the actual bot
|
// Bot interface serves to allow mocking of the actual bot
|
||||||
type Bot interface {
|
type Bot interface {
|
||||||
|
|
|
@ -48,7 +48,7 @@ func New(c *config.Config) *SlackApp {
|
||||||
log.Fatalf("No slack token found. Set SLACKTOKEN env.")
|
log.Fatalf("No slack token found. Set SLACKTOKEN env.")
|
||||||
}
|
}
|
||||||
|
|
||||||
api := slack.New(token, slack.OptionDebug(true))
|
api := slack.New(token, slack.OptionDebug(false))
|
||||||
|
|
||||||
return &SlackApp{
|
return &SlackApp{
|
||||||
api: api,
|
api: api,
|
||||||
|
@ -263,7 +263,7 @@ func (s *SlackApp) populateEmojiList() {
|
||||||
log.Println("Cannot get emoji list without slack.usertoken")
|
log.Println("Cannot get emoji list without slack.usertoken")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
api := slack.New(s.userToken, slack.OptionDebug(true))
|
api := slack.New(s.userToken, slack.OptionDebug(false))
|
||||||
|
|
||||||
em, err := api.GetEmoji()
|
em, err := api.GetEmoji()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -339,7 +339,7 @@ func (s *SlackApp) Who(id string) []string {
|
||||||
log.Println("Cannot get emoji list without slack.usertoken")
|
log.Println("Cannot get emoji list without slack.usertoken")
|
||||||
return []string{s.config.Get("nick", "bot")}
|
return []string{s.config.Get("nick", "bot")}
|
||||||
}
|
}
|
||||||
api := slack.New(s.userToken, slack.OptionDebug(true))
|
api := slack.New(s.userToken, slack.OptionDebug(false))
|
||||||
|
|
||||||
log.Println("Who is queried for ", id)
|
log.Println("Who is queried for ", id)
|
||||||
// Not super sure this is the correct call
|
// Not super sure this is the correct call
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -2,7 +2,6 @@ github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP
|
||||||
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
|
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
|
||||||
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
||||||
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
|
||||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA=
|
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA=
|
||||||
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff/go.mod h1:QCRjR0b4qiJiNjuP7RFM89bh4UExGJalcWmYeSvlnRc=
|
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff/go.mod h1:QCRjR0b4qiJiNjuP7RFM89bh4UExGJalcWmYeSvlnRc=
|
||||||
|
@ -20,7 +19,6 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mmcdole/gofeed v1.0.0-beta2 h1:CjQ0ADhAwNSb08zknAkGOEYqr8zfZKfrzgk9BxpWP2E=
|
github.com/mmcdole/gofeed v1.0.0-beta2 h1:CjQ0ADhAwNSb08zknAkGOEYqr8zfZKfrzgk9BxpWP2E=
|
||||||
github.com/mmcdole/gofeed v1.0.0-beta2/go.mod h1:/BF9JneEL2/flujm8XHoxUcghdTV6vvb3xx/vKyChFU=
|
github.com/mmcdole/gofeed v1.0.0-beta2/go.mod h1:/BF9JneEL2/flujm8XHoxUcghdTV6vvb3xx/vKyChFU=
|
||||||
|
@ -37,23 +35,16 @@ github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspo
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89 h1:3D3M900hEBJJAqyKl70QuRHi5weX9+ptlQI1v+FNcQ8=
|
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89 h1:3D3M900hEBJJAqyKl70QuRHi5weX9+ptlQI1v+FNcQ8=
|
||||||
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89/go.mod h1:ejwOYCjnDMyO5LXFXRARQJGBZ6xQJZ3rgAHE5drSuMM=
|
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89/go.mod h1:ejwOYCjnDMyO5LXFXRARQJGBZ6xQJZ3rgAHE5drSuMM=
|
||||||
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158 h1:p3rTUXxzuKsBOsHlkly7+rj9wagFBKeIsCDKkDII9sw=
|
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158 h1:p3rTUXxzuKsBOsHlkly7+rj9wagFBKeIsCDKkDII9sw=
|
||||||
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158/go.mod h1:Ojy3BTOiOTwpHpw7/HNi+TVTFppao191PQs+Qc3sqpE=
|
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158/go.mod h1:Ojy3BTOiOTwpHpw7/HNi+TVTFppao191PQs+Qc3sqpE=
|
||||||
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38DwcXWEPldrTjIZ8FPNKx8mYMGnqjs=
|
|
||||||
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8=
|
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec h1:vpF8Kxql6/3OvGH4y2SKtpN3WsB17mvJ8f8H1o2vucQ=
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec/go.mod h1:fFiAh+CowNFr0NK5VASokuwKwkbacRmHsVA7Yb1Tqac=
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190125051437-7b9317363aa9/go.mod h1:fFiAh+CowNFr0NK5VASokuwKwkbacRmHsVA7Yb1Tqac=
|
github.com/yuin/gopher-lua v0.0.0-20190125051437-7b9317363aa9/go.mod h1:fFiAh+CowNFr0NK5VASokuwKwkbacRmHsVA7Yb1Tqac=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181217023233-e147a9138326 h1:iCzOf0xz39Tstp+Tu/WwyGjUXCk34QhQORRxBeXXTA4=
|
|
||||||
golang.org/x/net v0.0.0-20181217023233-e147a9138326/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY=
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY=
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
|
3
main.go
3
main.go
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/velour/catbase/plugins/nerdepedia"
|
"github.com/velour/catbase/plugins/nerdepedia"
|
||||||
"github.com/velour/catbase/plugins/picker"
|
"github.com/velour/catbase/plugins/picker"
|
||||||
"github.com/velour/catbase/plugins/reaction"
|
"github.com/velour/catbase/plugins/reaction"
|
||||||
|
"github.com/velour/catbase/plugins/remember"
|
||||||
"github.com/velour/catbase/plugins/reminder"
|
"github.com/velour/catbase/plugins/reminder"
|
||||||
"github.com/velour/catbase/plugins/rpgORdie"
|
"github.com/velour/catbase/plugins/rpgORdie"
|
||||||
"github.com/velour/catbase/plugins/rss"
|
"github.com/velour/catbase/plugins/rss"
|
||||||
|
@ -90,7 +91,7 @@ func main() {
|
||||||
b.AddPlugin(dice.New(b))
|
b.AddPlugin(dice.New(b))
|
||||||
b.AddPlugin(picker.New(b))
|
b.AddPlugin(picker.New(b))
|
||||||
b.AddPlugin(beers.New(b))
|
b.AddPlugin(beers.New(b))
|
||||||
b.AddPlugin(fact.NewRemember(b))
|
b.AddPlugin(remember.New(b))
|
||||||
b.AddPlugin(your.New(b))
|
b.AddPlugin(your.New(b))
|
||||||
b.AddPlugin(counter.New(b))
|
b.AddPlugin(counter.New(b))
|
||||||
b.AddPlugin(reminder.New(b))
|
b.AddPlugin(reminder.New(b))
|
||||||
|
|
|
@ -23,32 +23,10 @@ func makeMessage(nick, payload string) msg.Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePlugin(t *testing.T) (*RememberPlugin, *Factoid, *bot.MockBot) {
|
func makePlugin(t *testing.T) (*FactoidPlugin, *bot.MockBot) {
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
f := New(mb) // for DB table
|
f := New(mb) // for DB table
|
||||||
p := NewRemember(mb)
|
return f, mb
|
||||||
assert.NotNil(t, p)
|
|
||||||
return p, f, mb
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test case
|
|
||||||
func TestCornerCaseBug(t *testing.T) {
|
|
||||||
msgs := []msg.Message{
|
|
||||||
makeMessage("user1", "I don’t want to personally touch a horse dick."),
|
|
||||||
makeMessage("user3", "idk my bff rose?"),
|
|
||||||
makeMessage("user2", "!remember user1 touch"),
|
|
||||||
}
|
|
||||||
|
|
||||||
p, _, mb := makePlugin(t)
|
|
||||||
|
|
||||||
for _, m := range msgs {
|
|
||||||
p.message(bot.Message, m)
|
|
||||||
}
|
|
||||||
assert.Len(t, mb.Messages, 1)
|
|
||||||
assert.Contains(t, mb.Messages[0], "horse dick")
|
|
||||||
q, err := getSingleFact(mb.DB(), "user1 quotes")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Contains(t, q.Tidbit, "horse dick")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReact(t *testing.T) {
|
func TestReact(t *testing.T) {
|
||||||
|
@ -56,7 +34,7 @@ func TestReact(t *testing.T) {
|
||||||
makeMessage("user1", "!testing123 <react> jesus"),
|
makeMessage("user1", "!testing123 <react> jesus"),
|
||||||
makeMessage("user2", "testing123"),
|
makeMessage("user2", "testing123"),
|
||||||
}
|
}
|
||||||
_, p, mb := makePlugin(t)
|
p, mb := makePlugin(t)
|
||||||
|
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
p.message(bot.Message, m)
|
p.message(bot.Message, m)
|
||||||
|
@ -69,7 +47,7 @@ func TestReactCantLearnSpaces(t *testing.T) {
|
||||||
msgs := []msg.Message{
|
msgs := []msg.Message{
|
||||||
makeMessage("user1", "!test <react> jesus christ"),
|
makeMessage("user1", "!test <react> jesus christ"),
|
||||||
}
|
}
|
||||||
_, p, mb := makePlugin(t)
|
p, mb := makePlugin(t)
|
||||||
|
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
p.message(bot.Message, m)
|
p.message(bot.Message, m)
|
|
@ -22,14 +22,14 @@ import (
|
||||||
// respond to queries in a way that is unpredictable and fun
|
// respond to queries in a way that is unpredictable and fun
|
||||||
|
|
||||||
// factoid stores info about our factoid for lookup and later interaction
|
// factoid stores info about our factoid for lookup and later interaction
|
||||||
type factoid struct {
|
type Factoid struct {
|
||||||
id sql.NullInt64
|
ID sql.NullInt64
|
||||||
Fact string
|
Fact string
|
||||||
Tidbit string
|
Tidbit string
|
||||||
Verb string
|
Verb string
|
||||||
Owner string
|
Owner string
|
||||||
created time.Time
|
Created time.Time
|
||||||
accessed time.Time
|
Accessed time.Time
|
||||||
Count int
|
Count int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,14 +38,14 @@ type alias struct {
|
||||||
Next string
|
Next string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *alias) resolve(db *sqlx.DB) (*factoid, error) {
|
func (a *alias) resolve(db *sqlx.DB) (*Factoid, error) {
|
||||||
// perform DB query to fill the To field
|
// perform DB query to fill the To field
|
||||||
q := `select fact, next from factoid_alias where fact=?`
|
q := `select fact, next from factoid_alias where fact=?`
|
||||||
var next alias
|
var next alias
|
||||||
err := db.Get(&next, q, a.Next)
|
err := db.Get(&next, q, a.Next)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// we hit the end of the chain, get a factoid named Next
|
// we hit the end of the chain, get a factoid named Next
|
||||||
fact, err := getSingleFact(db, a.Next)
|
fact, err := GetSingleFact(db, a.Next)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error resolvig alias %v: %v", a, err)
|
err := fmt.Errorf("Error resolvig alias %v: %v", a, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -55,7 +55,7 @@ func (a *alias) resolve(db *sqlx.DB) (*factoid, error) {
|
||||||
return next.resolve(db)
|
return next.resolve(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAlias(db *sqlx.DB, fact string) (bool, *factoid) {
|
func findAlias(db *sqlx.DB, fact string) (bool, *Factoid) {
|
||||||
q := `select * from factoid_alias where fact=?`
|
q := `select * from factoid_alias where fact=?`
|
||||||
var a alias
|
var a alias
|
||||||
err := db.Get(&a, q, fact)
|
err := db.Get(&a, q, fact)
|
||||||
|
@ -89,9 +89,9 @@ func aliasFromStrings(from, to string) *alias {
|
||||||
return &alias{from, to}
|
return &alias{from, to}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *factoid) save(db *sqlx.DB) error {
|
func (f *Factoid) Save(db *sqlx.DB) error {
|
||||||
var err error
|
var err error
|
||||||
if f.id.Valid {
|
if f.ID.Valid {
|
||||||
// update
|
// update
|
||||||
_, err = db.Exec(`update factoid set
|
_, err = db.Exec(`update factoid set
|
||||||
fact=?,
|
fact=?,
|
||||||
|
@ -105,12 +105,12 @@ func (f *factoid) save(db *sqlx.DB) error {
|
||||||
f.Tidbit,
|
f.Tidbit,
|
||||||
f.Verb,
|
f.Verb,
|
||||||
f.Owner,
|
f.Owner,
|
||||||
f.accessed.Unix(),
|
f.Accessed.Unix(),
|
||||||
f.Count,
|
f.Count,
|
||||||
f.id.Int64)
|
f.ID.Int64)
|
||||||
} else {
|
} else {
|
||||||
f.created = time.Now()
|
f.Created = time.Now()
|
||||||
f.accessed = time.Now()
|
f.Accessed = time.Now()
|
||||||
// insert
|
// insert
|
||||||
res, err := db.Exec(`insert into factoid (
|
res, err := db.Exec(`insert into factoid (
|
||||||
fact,
|
fact,
|
||||||
|
@ -125,8 +125,8 @@ func (f *factoid) save(db *sqlx.DB) error {
|
||||||
f.Tidbit,
|
f.Tidbit,
|
||||||
f.Verb,
|
f.Verb,
|
||||||
f.Owner,
|
f.Owner,
|
||||||
f.created.Unix(),
|
f.Created.Unix(),
|
||||||
f.accessed.Unix(),
|
f.Accessed.Unix(),
|
||||||
f.Count,
|
f.Count,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -134,23 +134,23 @@ func (f *factoid) save(db *sqlx.DB) error {
|
||||||
}
|
}
|
||||||
id, err := res.LastInsertId()
|
id, err := res.LastInsertId()
|
||||||
// hackhackhack?
|
// hackhackhack?
|
||||||
f.id.Int64 = id
|
f.ID.Int64 = id
|
||||||
f.id.Valid = true
|
f.ID.Valid = true
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *factoid) delete(db *sqlx.DB) error {
|
func (f *Factoid) delete(db *sqlx.DB) error {
|
||||||
var err error
|
var err error
|
||||||
if f.id.Valid {
|
if f.ID.Valid {
|
||||||
_, err = db.Exec(`delete from factoid where id=?`, f.id)
|
_, err = db.Exec(`delete from factoid where id=?`, f.ID)
|
||||||
}
|
}
|
||||||
f.id.Valid = false
|
f.ID.Valid = false
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*factoid, error) {
|
func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*Factoid, error) {
|
||||||
var fs []*factoid
|
var fs []*Factoid
|
||||||
query := `select
|
query := `select
|
||||||
id,
|
id,
|
||||||
fact,
|
fact,
|
||||||
|
@ -170,11 +170,11 @@ func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*factoid, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var f factoid
|
var f Factoid
|
||||||
var tmpCreated int64
|
var tmpCreated int64
|
||||||
var tmpAccessed int64
|
var tmpAccessed int64
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&f.id,
|
&f.ID,
|
||||||
&f.Fact,
|
&f.Fact,
|
||||||
&f.Tidbit,
|
&f.Tidbit,
|
||||||
&f.Verb,
|
&f.Verb,
|
||||||
|
@ -186,15 +186,15 @@ func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*factoid, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
f.created = time.Unix(tmpCreated, 0)
|
f.Created = time.Unix(tmpCreated, 0)
|
||||||
f.accessed = time.Unix(tmpAccessed, 0)
|
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||||
fs = append(fs, &f)
|
fs = append(fs, &f)
|
||||||
}
|
}
|
||||||
return fs, err
|
return fs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSingle(db *sqlx.DB) (*factoid, error) {
|
func GetSingle(db *sqlx.DB) (*Factoid, error) {
|
||||||
var f factoid
|
var f Factoid
|
||||||
var tmpCreated int64
|
var tmpCreated int64
|
||||||
var tmpAccessed int64
|
var tmpAccessed int64
|
||||||
err := db.QueryRow(`select
|
err := db.QueryRow(`select
|
||||||
|
@ -208,7 +208,7 @@ func getSingle(db *sqlx.DB) (*factoid, error) {
|
||||||
count
|
count
|
||||||
from factoid
|
from factoid
|
||||||
order by random() limit 1;`).Scan(
|
order by random() limit 1;`).Scan(
|
||||||
&f.id,
|
&f.ID,
|
||||||
&f.Fact,
|
&f.Fact,
|
||||||
&f.Tidbit,
|
&f.Tidbit,
|
||||||
&f.Verb,
|
&f.Verb,
|
||||||
|
@ -217,13 +217,13 @@ func getSingle(db *sqlx.DB) (*factoid, error) {
|
||||||
&tmpAccessed,
|
&tmpAccessed,
|
||||||
&f.Count,
|
&f.Count,
|
||||||
)
|
)
|
||||||
f.created = time.Unix(tmpCreated, 0)
|
f.Created = time.Unix(tmpCreated, 0)
|
||||||
f.accessed = time.Unix(tmpAccessed, 0)
|
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||||
return &f, err
|
return &f, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
|
func GetSingleFact(db *sqlx.DB, fact string) (*Factoid, error) {
|
||||||
var f factoid
|
var f Factoid
|
||||||
var tmpCreated int64
|
var tmpCreated int64
|
||||||
var tmpAccessed int64
|
var tmpAccessed int64
|
||||||
err := db.QueryRow(`select
|
err := db.QueryRow(`select
|
||||||
|
@ -239,7 +239,7 @@ func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
|
||||||
where fact like ?
|
where fact like ?
|
||||||
order by random() limit 1;`,
|
order by random() limit 1;`,
|
||||||
fact).Scan(
|
fact).Scan(
|
||||||
&f.id,
|
&f.ID,
|
||||||
&f.Fact,
|
&f.Fact,
|
||||||
&f.Tidbit,
|
&f.Tidbit,
|
||||||
&f.Verb,
|
&f.Verb,
|
||||||
|
@ -248,22 +248,22 @@ func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
|
||||||
&tmpAccessed,
|
&tmpAccessed,
|
||||||
&f.Count,
|
&f.Count,
|
||||||
)
|
)
|
||||||
f.created = time.Unix(tmpCreated, 0)
|
f.Created = time.Unix(tmpCreated, 0)
|
||||||
f.accessed = time.Unix(tmpAccessed, 0)
|
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||||
return &f, err
|
return &f, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Factoid provides the necessary plugin-wide needs
|
// Factoid provides the necessary plugin-wide needs
|
||||||
type Factoid struct {
|
type FactoidPlugin struct {
|
||||||
Bot bot.Bot
|
Bot bot.Bot
|
||||||
NotFound []string
|
NotFound []string
|
||||||
LastFact *factoid
|
LastFact *Factoid
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFactoid creates a new Factoid with the Plugin interface
|
// NewFactoid creates a new Factoid with the Plugin interface
|
||||||
func New(botInst bot.Bot) *Factoid {
|
func New(botInst bot.Bot) *FactoidPlugin {
|
||||||
p := &Factoid{
|
p := &FactoidPlugin{
|
||||||
Bot: botInst,
|
Bot: botInst,
|
||||||
NotFound: []string{
|
NotFound: []string{
|
||||||
"I don't know.",
|
"I don't know.",
|
||||||
|
@ -343,7 +343,7 @@ func findAction(message string) string {
|
||||||
|
|
||||||
// learnFact assumes we have a learning situation and inserts a new fact
|
// learnFact assumes we have a learning situation and inserts a new fact
|
||||||
// into the database
|
// into the database
|
||||||
func (p *Factoid) learnFact(message msg.Message, fact, verb, tidbit string) error {
|
func (p *FactoidPlugin) learnFact(message msg.Message, fact, verb, tidbit string) error {
|
||||||
verb = strings.ToLower(verb)
|
verb = strings.ToLower(verb)
|
||||||
if verb == "react" {
|
if verb == "react" {
|
||||||
// This would be a great place to check against the API for valid emojy
|
// This would be a great place to check against the API for valid emojy
|
||||||
|
@ -366,17 +366,17 @@ func (p *Factoid) learnFact(message msg.Message, fact, verb, tidbit string) erro
|
||||||
return fmt.Errorf("Look, I already know that.")
|
return fmt.Errorf("Look, I already know that.")
|
||||||
}
|
}
|
||||||
|
|
||||||
n := factoid{
|
n := Factoid{
|
||||||
Fact: fact,
|
Fact: fact,
|
||||||
Tidbit: tidbit,
|
Tidbit: tidbit,
|
||||||
Verb: verb,
|
Verb: verb,
|
||||||
Owner: message.User.Name,
|
Owner: message.User.Name,
|
||||||
created: time.Now(),
|
Created: time.Now(),
|
||||||
accessed: time.Now(),
|
Accessed: time.Now(),
|
||||||
Count: 0,
|
Count: 0,
|
||||||
}
|
}
|
||||||
p.LastFact = &n
|
p.LastFact = &n
|
||||||
err = n.save(p.db)
|
err = n.Save(p.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error inserting fact: ", err)
|
log.Println("Error inserting fact: ", err)
|
||||||
return fmt.Errorf("My brain is overheating.")
|
return fmt.Errorf("My brain is overheating.")
|
||||||
|
@ -386,10 +386,10 @@ func (p *Factoid) learnFact(message msg.Message, fact, verb, tidbit string) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// findTrigger checks to see if a given string is a trigger or not
|
// findTrigger checks to see if a given string is a trigger or not
|
||||||
func (p *Factoid) findTrigger(fact string) (bool, *factoid) {
|
func (p *FactoidPlugin) findTrigger(fact string) (bool, *Factoid) {
|
||||||
fact = strings.ToLower(fact) // TODO: make sure this needs to be lowered here
|
fact = strings.ToLower(fact) // TODO: make sure this needs to be lowered here
|
||||||
|
|
||||||
f, err := getSingleFact(p.db, fact)
|
f, err := GetSingleFact(p.db, fact)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return findAlias(p.db, fact)
|
return findAlias(p.db, fact)
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ func (p *Factoid) findTrigger(fact string) (bool, *factoid) {
|
||||||
|
|
||||||
// sayFact spits out a fact to the channel and updates the fact in the database
|
// sayFact spits out a fact to the channel and updates the fact in the database
|
||||||
// with new time and count information
|
// with new time and count information
|
||||||
func (p *Factoid) sayFact(message msg.Message, fact factoid) {
|
func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) {
|
||||||
msg := p.Bot.Filter(message, fact.Tidbit)
|
msg := p.Bot.Filter(message, fact.Tidbit)
|
||||||
full := p.Bot.Filter(message, fmt.Sprintf("%s %s %s",
|
full := p.Bot.Filter(message, fmt.Sprintf("%s %s %s",
|
||||||
fact.Fact, fact.Verb, fact.Tidbit,
|
fact.Fact, fact.Verb, fact.Tidbit,
|
||||||
|
@ -421,9 +421,9 @@ func (p *Factoid) sayFact(message msg.Message, fact factoid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update fact tracking
|
// update fact tracking
|
||||||
fact.accessed = time.Now()
|
fact.Accessed = time.Now()
|
||||||
fact.Count += 1
|
fact.Count += 1
|
||||||
err := fact.save(p.db)
|
err := fact.Save(p.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Could not update fact.\n")
|
log.Printf("Could not update fact.\n")
|
||||||
log.Printf("%#v\n", fact)
|
log.Printf("%#v\n", fact)
|
||||||
|
@ -434,7 +434,7 @@ func (p *Factoid) sayFact(message msg.Message, fact factoid) {
|
||||||
|
|
||||||
// trigger checks the message for its fitness to be a factoid and then hauls
|
// 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
|
// the message off to sayFact for processing if it is in fact a trigger
|
||||||
func (p *Factoid) trigger(message msg.Message) bool {
|
func (p *FactoidPlugin) trigger(message msg.Message) bool {
|
||||||
minLen := p.Bot.Config().GetInt("Factoid.MinLen", 4)
|
minLen := p.Bot.Config().GetInt("Factoid.MinLen", 4)
|
||||||
if len(message.Body) > minLen || message.Command || message.Body == "..." {
|
if len(message.Body) > minLen || message.Command || message.Body == "..." {
|
||||||
if ok, fact := p.findTrigger(message.Body); ok {
|
if ok, fact := p.findTrigger(message.Body); ok {
|
||||||
|
@ -453,20 +453,20 @@ func (p *Factoid) trigger(message msg.Message) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// tellThemWhatThatWas is a hilarious name for a function.
|
// tellThemWhatThatWas is a hilarious name for a function.
|
||||||
func (p *Factoid) tellThemWhatThatWas(message msg.Message) bool {
|
func (p *FactoidPlugin) tellThemWhatThatWas(message msg.Message) bool {
|
||||||
fact := p.LastFact
|
fact := p.LastFact
|
||||||
var msg string
|
var msg string
|
||||||
if fact == nil {
|
if fact == nil {
|
||||||
msg = "Nope."
|
msg = "Nope."
|
||||||
} else {
|
} else {
|
||||||
msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'",
|
msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'",
|
||||||
fact.id.Int64, fact.Fact, fact.Verb, fact.Tidbit)
|
fact.ID.Int64, fact.Fact, fact.Verb, fact.Tidbit)
|
||||||
}
|
}
|
||||||
p.Bot.Send(bot.Message, message.Channel, msg)
|
p.Bot.Send(bot.Message, message.Channel, msg)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Factoid) learnAction(message msg.Message, action string) bool {
|
func (p *FactoidPlugin) learnAction(message msg.Message, action string) bool {
|
||||||
body := message.Body
|
body := message.Body
|
||||||
|
|
||||||
parts := strings.SplitN(body, action, 2)
|
parts := strings.SplitN(body, action, 2)
|
||||||
|
@ -512,7 +512,7 @@ func changeOperator(body string) string {
|
||||||
|
|
||||||
// If the user requesting forget is either the owner of the last learned fact or
|
// If the user requesting forget is either the owner of the last learned fact or
|
||||||
// an admin, it may be deleted
|
// an admin, it may be deleted
|
||||||
func (p *Factoid) forgetLastFact(message msg.Message) bool {
|
func (p *FactoidPlugin) forgetLastFact(message msg.Message) bool {
|
||||||
if p.LastFact == nil {
|
if p.LastFact == nil {
|
||||||
p.Bot.Send(bot.Message, message.Channel, "I refuse.")
|
p.Bot.Send(bot.Message, message.Channel, "I refuse.")
|
||||||
return true
|
return true
|
||||||
|
@ -522,7 +522,7 @@ func (p *Factoid) forgetLastFact(message msg.Message) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error removing fact: ", p.LastFact, err)
|
log.Println("Error removing fact: ", p.LastFact, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.id.Int64, p.LastFact.Fact,
|
fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.ID.Int64, p.LastFact.Fact,
|
||||||
p.LastFact.Verb, p.LastFact.Tidbit)
|
p.LastFact.Verb, p.LastFact.Tidbit)
|
||||||
p.Bot.Send(bot.Action, message.Channel, "hits himself over the head with a skillet")
|
p.Bot.Send(bot.Action, message.Channel, "hits himself over the head with a skillet")
|
||||||
p.LastFact = nil
|
p.LastFact = nil
|
||||||
|
@ -531,7 +531,7 @@ func (p *Factoid) forgetLastFact(message msg.Message) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow users to change facts with a simple regexp
|
// Allow users to change facts with a simple regexp
|
||||||
func (p *Factoid) changeFact(message msg.Message) bool {
|
func (p *FactoidPlugin) changeFact(message msg.Message) bool {
|
||||||
oper := changeOperator(message.Body)
|
oper := changeOperator(message.Body)
|
||||||
parts := strings.SplitN(message.Body, oper, 2)
|
parts := strings.SplitN(message.Body, oper, 2)
|
||||||
userexp := strings.TrimSpace(parts[1])
|
userexp := strings.TrimSpace(parts[1])
|
||||||
|
@ -571,8 +571,8 @@ func (p *Factoid) changeFact(message msg.Message) bool {
|
||||||
fact.Verb = reg.ReplaceAllString(fact.Verb, replace)
|
fact.Verb = reg.ReplaceAllString(fact.Verb, replace)
|
||||||
fact.Tidbit = reg.ReplaceAllString(fact.Tidbit, replace)
|
fact.Tidbit = reg.ReplaceAllString(fact.Tidbit, replace)
|
||||||
fact.Count += 1
|
fact.Count += 1
|
||||||
fact.accessed = time.Now()
|
fact.Accessed = time.Now()
|
||||||
fact.save(p.db)
|
fact.Save(p.db)
|
||||||
}
|
}
|
||||||
} else if len(parts) == 3 {
|
} else if len(parts) == 3 {
|
||||||
// search for a factoid and print it
|
// search for a factoid and print it
|
||||||
|
@ -614,7 +614,7 @@ func (p *Factoid) changeFact(message msg.Message) bool {
|
||||||
// Message responds to the bot hook on recieving messages.
|
// 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.
|
// 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.
|
// Otherwise, the function returns false and the bot continues execution of other plugins.
|
||||||
func (p *Factoid) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *FactoidPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
if strings.ToLower(message.Body) == "what was that?" {
|
if strings.ToLower(message.Body) == "what was that?" {
|
||||||
return p.tellThemWhatThatWas(message)
|
return p.tellThemWhatThatWas(message)
|
||||||
}
|
}
|
||||||
|
@ -674,15 +674,15 @@ func (p *Factoid) message(kind bot.Kind, message msg.Message, args ...interface{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help responds to help requests. Every plugin must implement a help function.
|
// Help responds to help requests. Every plugin must implement a help function.
|
||||||
func (p *Factoid) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
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 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.")
|
p.Bot.Send(bot.Message, message.Channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull a fact at random from the database
|
// Pull a fact at random from the database
|
||||||
func (p *Factoid) randomFact() *factoid {
|
func (p *FactoidPlugin) randomFact() *Factoid {
|
||||||
f, err := getSingle(p.db)
|
f, err := GetSingle(p.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting a fact: ", err)
|
fmt.Println("Error getting a fact: ", err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -691,7 +691,7 @@ func (p *Factoid) randomFact() *factoid {
|
||||||
}
|
}
|
||||||
|
|
||||||
// factTimer spits out a fact at a given interval and with given probability
|
// factTimer spits out a fact at a given interval and with given probability
|
||||||
func (p *Factoid) factTimer(channel string) {
|
func (p *FactoidPlugin) factTimer(channel string) {
|
||||||
quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime", 30)
|
quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime", 30)
|
||||||
if quoteTime == 0 {
|
if quoteTime == 0 {
|
||||||
quoteTime = 30
|
quoteTime = 30
|
||||||
|
@ -739,7 +739,7 @@ func (p *Factoid) factTimer(channel string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register any web URLs desired
|
// Register any web URLs desired
|
||||||
func (p *Factoid) registerWeb() {
|
func (p *FactoidPlugin) registerWeb() {
|
||||||
http.HandleFunc("/factoid/req", p.serveQuery)
|
http.HandleFunc("/factoid/req", p.serveQuery)
|
||||||
http.HandleFunc("/factoid", p.serveQuery)
|
http.HandleFunc("/factoid", p.serveQuery)
|
||||||
p.Bot.RegisterWeb("/factoid", "Factoid")
|
p.Bot.RegisterWeb("/factoid", "Factoid")
|
||||||
|
@ -755,7 +755,7 @@ func linkify(text string) template.HTML {
|
||||||
return template.HTML(strings.Join(parts, " "))
|
return template.HTML(strings.Join(parts, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Factoid) serveQuery(w http.ResponseWriter, r *http.Request) {
|
func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
context := make(map[string]interface{})
|
context := make(map[string]interface{})
|
||||||
funcMap := template.FuncMap{
|
funcMap := template.FuncMap{
|
||||||
// The name "title" is what the function will be called in the template text.
|
// The name "title" is what the function will be called in the template text.
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors.
|
package remember
|
||||||
|
|
||||||
package fact
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -11,38 +9,32 @@ import (
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/velour/catbase/bot"
|
"github.com/velour/catbase/bot"
|
||||||
"github.com/velour/catbase/bot/msg"
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
"github.com/velour/catbase/plugins/fact"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is a skeleton plugin to serve as an example and quick copy/paste for new
|
|
||||||
// plugins.
|
|
||||||
|
|
||||||
type RememberPlugin struct {
|
type RememberPlugin struct {
|
||||||
Bot bot.Bot
|
bot bot.Bot
|
||||||
Log map[string][]msg.Message
|
log map[string][]msg.Message
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRememberPlugin creates a new RememberPlugin with the Plugin interface
|
func New(b bot.Bot) *RememberPlugin {
|
||||||
func NewRemember(b bot.Bot) *RememberPlugin {
|
p := &RememberPlugin{
|
||||||
p := RememberPlugin{
|
bot: b,
|
||||||
Bot: b,
|
log: make(map[string][]msg.Message),
|
||||||
Log: make(map[string][]msg.Message),
|
|
||||||
db: b.DB(),
|
db: b.DB(),
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Register(p, bot.Message, p.message)
|
b.Register(p, bot.Message, p.message)
|
||||||
b.Register(p, bot.Message, p.help)
|
b.Register(p, bot.Help, p.help)
|
||||||
return &p
|
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
|
|
||||||
if strings.ToLower(message.Body) == "quote" && message.Command {
|
if strings.ToLower(message.Body) == "quote" && message.Command {
|
||||||
q := p.randQuote()
|
q := p.randQuote()
|
||||||
p.Bot.Send(bot.Message, message.Channel, q)
|
p.bot.Send(bot.Message, message.Channel, q)
|
||||||
|
|
||||||
// is it evil not to remember that the user said quote?
|
// is it evil not to remember that the user said quote?
|
||||||
return true
|
return true
|
||||||
|
@ -50,16 +42,16 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
|
||||||
|
|
||||||
user := message.User
|
user := message.User
|
||||||
parts := strings.Fields(message.Body)
|
parts := strings.Fields(message.Body)
|
||||||
|
|
||||||
if message.Command && len(parts) >= 3 &&
|
if message.Command && len(parts) >= 3 &&
|
||||||
strings.ToLower(parts[0]) == "remember" {
|
strings.ToLower(parts[0]) == "remember" {
|
||||||
|
|
||||||
// we have a remember!
|
// we have a remember!
|
||||||
// look through the logs and find parts[1] as a user, if not,
|
// look through the logs and find parts[1] as a user, if not,
|
||||||
// fuck this hoser
|
// fuck this hoser
|
||||||
nick := parts[1]
|
nick := parts[1]
|
||||||
snip := strings.Join(parts[2:], " ")
|
snip := strings.Join(parts[2:], " ")
|
||||||
for i := len(p.Log[message.Channel]) - 1; i >= 0; i-- {
|
for i := len(p.log[message.Channel]) - 1; i >= 0; i-- {
|
||||||
entry := p.Log[message.Channel][i]
|
entry := p.log[message.Channel][i]
|
||||||
log.Printf("Comparing %s:%s with %s:%s",
|
log.Printf("Comparing %s:%s with %s:%s",
|
||||||
entry.User.Name, entry.Body, nick, snip)
|
entry.User.Name, entry.Body, nick, snip)
|
||||||
if strings.ToLower(entry.User.Name) == strings.ToLower(nick) &&
|
if strings.ToLower(entry.User.Name) == strings.ToLower(nick) &&
|
||||||
|
@ -78,18 +70,18 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
|
||||||
|
|
||||||
trigger := fmt.Sprintf("%s quotes", entry.User.Name)
|
trigger := fmt.Sprintf("%s quotes", entry.User.Name)
|
||||||
|
|
||||||
fact := factoid{
|
fact := fact.Factoid{
|
||||||
Fact: strings.ToLower(trigger),
|
Fact: strings.ToLower(trigger),
|
||||||
Verb: "reply",
|
Verb: "reply",
|
||||||
Tidbit: msg,
|
Tidbit: msg,
|
||||||
Owner: user.Name,
|
Owner: user.Name,
|
||||||
created: time.Now(),
|
Created: time.Now(),
|
||||||
accessed: time.Now(),
|
Accessed: time.Now(),
|
||||||
Count: 0,
|
Count: 0,
|
||||||
}
|
}
|
||||||
if err := fact.save(p.db); err != nil {
|
if err := fact.Save(p.db); err != nil {
|
||||||
log.Println("ERROR!!!!:", err)
|
log.Println("ERROR!!!!:", err)
|
||||||
p.Bot.Send(bot.Message, message.Channel, "Tell somebody I'm broke.")
|
p.bot.Send(bot.Message, message.Channel, "Tell somebody I'm broke.")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Remembering factoid:", msg)
|
log.Println("Remembering factoid:", msg)
|
||||||
|
@ -97,30 +89,28 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
|
||||||
// sorry, not creative with names so we're reusing msg
|
// sorry, not creative with names so we're reusing msg
|
||||||
msg = fmt.Sprintf("Okay, %s, remembering '%s'.",
|
msg = fmt.Sprintf("Okay, %s, remembering '%s'.",
|
||||||
message.User.Name, msg)
|
message.User.Name, msg)
|
||||||
p.Bot.Send(bot.Message, message.Channel, msg)
|
p.bot.Send(bot.Message, message.Channel, msg)
|
||||||
p.recordMsg(message)
|
p.recordMsg(message)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p.bot.Send(bot.Message, message.Channel, "Sorry, I don't know that phrase.")
|
||||||
p.Bot.Send(bot.Message, message.Channel, "Sorry, I don't know that phrase.")
|
|
||||||
p.recordMsg(message)
|
p.recordMsg(message)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
p.recordMsg(message)
|
p.recordMsg(message)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help responds to help requests. Every plugin must implement a help function.
|
|
||||||
func (p *RememberPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *RememberPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
|
msg := "remember will let you quote your idiot friends. Just type " +
|
||||||
msg := "!remember will let you quote your idiot friends. Just type " +
|
|
||||||
"!remember <nick> <snippet> to remember what they said. Snippet can " +
|
"!remember <nick> <snippet> to remember what they said. Snippet can " +
|
||||||
"be any part of their message. Later on, you can ask for a random " +
|
"be any part of their message. Later on, you can ask for a random " +
|
||||||
"!quote."
|
"!quote."
|
||||||
|
|
||||||
p.Bot.Send(bot.Message, message.Channel, msg)
|
p.bot.Send(bot.Message, message.Channel, msg)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,12 +119,12 @@ func (p *RememberPlugin) help(kind bot.Kind, message msg.Message, args ...interf
|
||||||
// expanded to have this function execute a quote for a particular channel
|
// expanded to have this function execute a quote for a particular channel
|
||||||
func (p *RememberPlugin) randQuote() string {
|
func (p *RememberPlugin) randQuote() string {
|
||||||
|
|
||||||
var f factoid
|
var f fact.Factoid
|
||||||
var tmpCreated int64
|
var tmpCreated int64
|
||||||
var tmpAccessed int64
|
var tmpAccessed int64
|
||||||
err := p.db.QueryRow(`select * from factoid where fact like '%quotes'
|
err := p.db.QueryRow(`select * from factoid where fact like '%quotes'
|
||||||
order by random() limit 1;`).Scan(
|
order by random() limit 1;`).Scan(
|
||||||
&f.id,
|
&f.ID,
|
||||||
&f.Fact,
|
&f.Fact,
|
||||||
&f.Tidbit,
|
&f.Tidbit,
|
||||||
&f.Verb,
|
&f.Verb,
|
||||||
|
@ -147,13 +137,13 @@ func (p *RememberPlugin) randQuote() string {
|
||||||
log.Println("Error getting quotes: ", err)
|
log.Println("Error getting quotes: ", err)
|
||||||
return "I had a problem getting your quote."
|
return "I had a problem getting your quote."
|
||||||
}
|
}
|
||||||
f.created = time.Unix(tmpCreated, 0)
|
f.Created = time.Unix(tmpCreated, 0)
|
||||||
f.accessed = time.Unix(tmpAccessed, 0)
|
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||||
|
|
||||||
return f.Tidbit
|
return f.Tidbit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RememberPlugin) recordMsg(message msg.Message) {
|
func (p *RememberPlugin) recordMsg(message msg.Message) {
|
||||||
log.Printf("Logging message: %s: %s", message.User.Name, message.Body)
|
log.Printf("Logging message: %s: %s", message.User.Name, message.Body)
|
||||||
p.Log[message.Channel] = append(p.Log[message.Channel], message)
|
p.log[message.Channel] = append(p.log[message.Channel], message)
|
||||||
}
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package remember
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/velour/catbase/bot"
|
||||||
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
"github.com/velour/catbase/bot/user"
|
||||||
|
"github.com/velour/catbase/plugins/fact"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeMessage(nick, payload string) msg.Message {
|
||||||
|
isCmd := strings.HasPrefix(payload, "!")
|
||||||
|
if isCmd {
|
||||||
|
payload = payload[1:]
|
||||||
|
}
|
||||||
|
return msg.Message{
|
||||||
|
User: &user.User{Name: nick},
|
||||||
|
Channel: "test",
|
||||||
|
Body: payload,
|
||||||
|
Command: isCmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makePlugin(t *testing.T) (*RememberPlugin, *fact.FactoidPlugin, *bot.MockBot) {
|
||||||
|
mb := bot.NewMockBot()
|
||||||
|
f := fact.New(mb) // for DB table
|
||||||
|
p := New(mb)
|
||||||
|
assert.NotNil(t, p)
|
||||||
|
return p, f, mb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case
|
||||||
|
func TestCornerCaseBug(t *testing.T) {
|
||||||
|
msgs := []msg.Message{
|
||||||
|
makeMessage("user1", "I don’t want to personally touch a horse dick."),
|
||||||
|
makeMessage("user3", "idk my bff rose?"),
|
||||||
|
makeMessage("user2", "!remember user1 touch"),
|
||||||
|
}
|
||||||
|
|
||||||
|
p, _, mb := makePlugin(t)
|
||||||
|
|
||||||
|
for _, m := range msgs {
|
||||||
|
p.message(bot.Message, m)
|
||||||
|
}
|
||||||
|
assert.Len(t, mb.Messages, 1)
|
||||||
|
assert.Contains(t, mb.Messages[0], "horse dick")
|
||||||
|
q, err := fact.GetSingleFact(mb.DB(), "user1 quotes")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Contains(t, q.Tidbit, "horse dick")
|
||||||
|
}
|
Loading…
Reference in New Issue