mirror of https://github.com/velour/catbase.git
remember: fixed something? It works now.
This commit is contained in:
parent
6fb0990a11
commit
47a824e8da
|
@ -246,7 +246,7 @@ func (b *bot) RegisterFilter(name string, f func(string) string) {
|
|||
|
||||
// Register a 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 {
|
||||
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 {
|
||||
parts := strings.Fields(strings.ToLower(msg.Body))
|
||||
b.checkHelp(msg.Channel, parts)
|
||||
log.Println("Handled a help, returning")
|
||||
goto RET
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,7 @@ RET:
|
|||
}
|
||||
|
||||
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] {
|
||||
if cb(evt, message, args...) {
|
||||
return true
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/velour/catbase/bot/msg"
|
||||
"github.com/velour/catbase/bot/user"
|
||||
|
@ -34,7 +32,7 @@ const (
|
|||
|
||||
type Kind int
|
||||
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
|
||||
type Bot interface {
|
||||
|
|
|
@ -48,7 +48,7 @@ func New(c *config.Config) *SlackApp {
|
|||
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{
|
||||
api: api,
|
||||
|
@ -263,7 +263,7 @@ func (s *SlackApp) populateEmojiList() {
|
|||
log.Println("Cannot get emoji list without slack.usertoken")
|
||||
return
|
||||
}
|
||||
api := slack.New(s.userToken, slack.OptionDebug(true))
|
||||
api := slack.New(s.userToken, slack.OptionDebug(false))
|
||||
|
||||
em, err := api.GetEmoji()
|
||||
if err != nil {
|
||||
|
@ -339,7 +339,7 @@ func (s *SlackApp) Who(id string) []string {
|
|||
log.Println("Cannot get emoji list without slack.usertoken")
|
||||
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)
|
||||
// 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/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
||||
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/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA=
|
||||
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.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
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/mmcdole/gofeed v1.0.0-beta2 h1:CjQ0ADhAwNSb08zknAkGOEYqr8zfZKfrzgk9BxpWP2E=
|
||||
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.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
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/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/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/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/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=
|
||||
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-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/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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/picker"
|
||||
"github.com/velour/catbase/plugins/reaction"
|
||||
"github.com/velour/catbase/plugins/remember"
|
||||
"github.com/velour/catbase/plugins/reminder"
|
||||
"github.com/velour/catbase/plugins/rpgORdie"
|
||||
"github.com/velour/catbase/plugins/rss"
|
||||
|
@ -89,7 +90,7 @@ func main() {
|
|||
b.AddPlugin(dice.New(b))
|
||||
b.AddPlugin(picker.New(b))
|
||||
b.AddPlugin(beers.New(b))
|
||||
b.AddPlugin(fact.NewRemember(b))
|
||||
b.AddPlugin(remember.New(b))
|
||||
b.AddPlugin(your.New(b))
|
||||
b.AddPlugin(counter.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()
|
||||
f := New(mb) // for DB table
|
||||
p := NewRemember(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")
|
||||
return f, mb
|
||||
}
|
||||
|
||||
func TestReact(t *testing.T) {
|
||||
|
@ -56,7 +34,7 @@ func TestReact(t *testing.T) {
|
|||
makeMessage("user1", "!testing123 <react> jesus"),
|
||||
makeMessage("user2", "testing123"),
|
||||
}
|
||||
_, p, mb := makePlugin(t)
|
||||
p, mb := makePlugin(t)
|
||||
|
||||
for _, m := range msgs {
|
||||
p.message(bot.Message, m)
|
||||
|
@ -69,7 +47,7 @@ func TestReactCantLearnSpaces(t *testing.T) {
|
|||
msgs := []msg.Message{
|
||||
makeMessage("user1", "!test <react> jesus christ"),
|
||||
}
|
||||
_, p, mb := makePlugin(t)
|
||||
p, mb := makePlugin(t)
|
||||
|
||||
for _, m := range msgs {
|
||||
p.message(bot.Message, m)
|
|
@ -22,14 +22,14 @@ import (
|
|||
// respond to queries in a way that is unpredictable and fun
|
||||
|
||||
// factoid stores info about our factoid for lookup and later interaction
|
||||
type factoid struct {
|
||||
id sql.NullInt64
|
||||
type Factoid struct {
|
||||
ID sql.NullInt64
|
||||
Fact string
|
||||
Tidbit string
|
||||
Verb string
|
||||
Owner string
|
||||
created time.Time
|
||||
accessed time.Time
|
||||
Created time.Time
|
||||
Accessed time.Time
|
||||
Count int
|
||||
}
|
||||
|
||||
|
@ -38,14 +38,14 @@ type alias struct {
|
|||
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
|
||||
q := `select fact, next from factoid_alias where fact=?`
|
||||
var next alias
|
||||
err := db.Get(&next, q, a.Next)
|
||||
if err != nil {
|
||||
// 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 {
|
||||
err := fmt.Errorf("Error resolvig alias %v: %v", a, err)
|
||||
return nil, err
|
||||
|
@ -55,7 +55,7 @@ func (a *alias) resolve(db *sqlx.DB) (*factoid, error) {
|
|||
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=?`
|
||||
var a alias
|
||||
err := db.Get(&a, q, fact)
|
||||
|
@ -89,9 +89,9 @@ func aliasFromStrings(from, to string) *alias {
|
|||
return &alias{from, to}
|
||||
}
|
||||
|
||||
func (f *factoid) save(db *sqlx.DB) error {
|
||||
func (f *Factoid) Save(db *sqlx.DB) error {
|
||||
var err error
|
||||
if f.id.Valid {
|
||||
if f.ID.Valid {
|
||||
// update
|
||||
_, err = db.Exec(`update factoid set
|
||||
fact=?,
|
||||
|
@ -105,12 +105,12 @@ func (f *factoid) save(db *sqlx.DB) error {
|
|||
f.Tidbit,
|
||||
f.Verb,
|
||||
f.Owner,
|
||||
f.accessed.Unix(),
|
||||
f.Accessed.Unix(),
|
||||
f.Count,
|
||||
f.id.Int64)
|
||||
f.ID.Int64)
|
||||
} else {
|
||||
f.created = time.Now()
|
||||
f.accessed = time.Now()
|
||||
f.Created = time.Now()
|
||||
f.Accessed = time.Now()
|
||||
// insert
|
||||
res, err := db.Exec(`insert into factoid (
|
||||
fact,
|
||||
|
@ -125,8 +125,8 @@ func (f *factoid) save(db *sqlx.DB) error {
|
|||
f.Tidbit,
|
||||
f.Verb,
|
||||
f.Owner,
|
||||
f.created.Unix(),
|
||||
f.accessed.Unix(),
|
||||
f.Created.Unix(),
|
||||
f.Accessed.Unix(),
|
||||
f.Count,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -134,23 +134,23 @@ func (f *factoid) save(db *sqlx.DB) error {
|
|||
}
|
||||
id, err := res.LastInsertId()
|
||||
// hackhackhack?
|
||||
f.id.Int64 = id
|
||||
f.id.Valid = true
|
||||
f.ID.Int64 = id
|
||||
f.ID.Valid = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *factoid) delete(db *sqlx.DB) error {
|
||||
func (f *Factoid) delete(db *sqlx.DB) error {
|
||||
var err error
|
||||
if f.id.Valid {
|
||||
_, err = db.Exec(`delete from factoid where id=?`, f.id)
|
||||
if f.ID.Valid {
|
||||
_, err = db.Exec(`delete from factoid where id=?`, f.ID)
|
||||
}
|
||||
f.id.Valid = false
|
||||
f.ID.Valid = false
|
||||
return err
|
||||
}
|
||||
|
||||
func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*factoid, error) {
|
||||
var fs []*factoid
|
||||
func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*Factoid, error) {
|
||||
var fs []*Factoid
|
||||
query := `select
|
||||
id,
|
||||
fact,
|
||||
|
@ -170,11 +170,11 @@ func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*factoid, error) {
|
|||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
var f factoid
|
||||
var f Factoid
|
||||
var tmpCreated int64
|
||||
var tmpAccessed int64
|
||||
err := rows.Scan(
|
||||
&f.id,
|
||||
&f.ID,
|
||||
&f.Fact,
|
||||
&f.Tidbit,
|
||||
&f.Verb,
|
||||
|
@ -186,15 +186,15 @@ func getFacts(db *sqlx.DB, fact string, tidbit string) ([]*factoid, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.created = time.Unix(tmpCreated, 0)
|
||||
f.accessed = time.Unix(tmpAccessed, 0)
|
||||
f.Created = time.Unix(tmpCreated, 0)
|
||||
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||
fs = append(fs, &f)
|
||||
}
|
||||
return fs, err
|
||||
}
|
||||
|
||||
func getSingle(db *sqlx.DB) (*factoid, error) {
|
||||
var f factoid
|
||||
func GetSingle(db *sqlx.DB) (*Factoid, error) {
|
||||
var f Factoid
|
||||
var tmpCreated int64
|
||||
var tmpAccessed int64
|
||||
err := db.QueryRow(`select
|
||||
|
@ -208,7 +208,7 @@ func getSingle(db *sqlx.DB) (*factoid, error) {
|
|||
count
|
||||
from factoid
|
||||
order by random() limit 1;`).Scan(
|
||||
&f.id,
|
||||
&f.ID,
|
||||
&f.Fact,
|
||||
&f.Tidbit,
|
||||
&f.Verb,
|
||||
|
@ -217,13 +217,13 @@ func getSingle(db *sqlx.DB) (*factoid, error) {
|
|||
&tmpAccessed,
|
||||
&f.Count,
|
||||
)
|
||||
f.created = time.Unix(tmpCreated, 0)
|
||||
f.accessed = time.Unix(tmpAccessed, 0)
|
||||
f.Created = time.Unix(tmpCreated, 0)
|
||||
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||
return &f, err
|
||||
}
|
||||
|
||||
func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
|
||||
var f factoid
|
||||
func GetSingleFact(db *sqlx.DB, fact string) (*Factoid, error) {
|
||||
var f Factoid
|
||||
var tmpCreated int64
|
||||
var tmpAccessed int64
|
||||
err := db.QueryRow(`select
|
||||
|
@ -239,7 +239,7 @@ func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
|
|||
where fact like ?
|
||||
order by random() limit 1;`,
|
||||
fact).Scan(
|
||||
&f.id,
|
||||
&f.ID,
|
||||
&f.Fact,
|
||||
&f.Tidbit,
|
||||
&f.Verb,
|
||||
|
@ -248,22 +248,22 @@ func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
|
|||
&tmpAccessed,
|
||||
&f.Count,
|
||||
)
|
||||
f.created = time.Unix(tmpCreated, 0)
|
||||
f.accessed = time.Unix(tmpAccessed, 0)
|
||||
f.Created = time.Unix(tmpCreated, 0)
|
||||
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||
return &f, err
|
||||
}
|
||||
|
||||
// Factoid provides the necessary plugin-wide needs
|
||||
type Factoid struct {
|
||||
type FactoidPlugin struct {
|
||||
Bot bot.Bot
|
||||
NotFound []string
|
||||
LastFact *factoid
|
||||
LastFact *Factoid
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// NewFactoid creates a new Factoid with the Plugin interface
|
||||
func New(botInst bot.Bot) *Factoid {
|
||||
p := &Factoid{
|
||||
func New(botInst bot.Bot) *FactoidPlugin {
|
||||
p := &FactoidPlugin{
|
||||
Bot: botInst,
|
||||
NotFound: []string{
|
||||
"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
|
||||
// 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)
|
||||
if verb == "react" {
|
||||
// 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.")
|
||||
}
|
||||
|
||||
n := factoid{
|
||||
n := Factoid{
|
||||
Fact: fact,
|
||||
Tidbit: tidbit,
|
||||
Verb: verb,
|
||||
Owner: message.User.Name,
|
||||
created: time.Now(),
|
||||
accessed: time.Now(),
|
||||
Created: time.Now(),
|
||||
Accessed: time.Now(),
|
||||
Count: 0,
|
||||
}
|
||||
p.LastFact = &n
|
||||
err = n.save(p.db)
|
||||
err = n.Save(p.db)
|
||||
if err != nil {
|
||||
log.Println("Error inserting fact: ", err)
|
||||
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
|
||||
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
|
||||
|
||||
f, err := getSingleFact(p.db, fact)
|
||||
f, err := GetSingleFact(p.db, fact)
|
||||
if err != nil {
|
||||
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
|
||||
// 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)
|
||||
full := p.Bot.Filter(message, fmt.Sprintf("%s %s %s",
|
||||
fact.Fact, fact.Verb, fact.Tidbit,
|
||||
|
@ -421,9 +421,9 @@ func (p *Factoid) sayFact(message msg.Message, fact factoid) {
|
|||
}
|
||||
|
||||
// update fact tracking
|
||||
fact.accessed = time.Now()
|
||||
fact.Accessed = time.Now()
|
||||
fact.Count += 1
|
||||
err := fact.save(p.db)
|
||||
err := fact.Save(p.db)
|
||||
if err != nil {
|
||||
log.Printf("Could not update fact.\n")
|
||||
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
|
||||
// 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)
|
||||
if len(message.Body) > minLen || message.Command || message.Body == "..." {
|
||||
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.
|
||||
func (p *Factoid) tellThemWhatThatWas(message msg.Message) bool {
|
||||
func (p *FactoidPlugin) tellThemWhatThatWas(message msg.Message) bool {
|
||||
fact := p.LastFact
|
||||
var msg string
|
||||
if fact == nil {
|
||||
msg = "Nope."
|
||||
} else {
|
||||
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)
|
||||
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
|
||||
|
||||
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
|
||||
// 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 {
|
||||
p.Bot.Send(bot.Message, message.Channel, "I refuse.")
|
||||
return true
|
||||
|
@ -522,7 +522,7 @@ func (p *Factoid) forgetLastFact(message msg.Message) bool {
|
|||
if err != nil {
|
||||
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.Bot.Send(bot.Action, message.Channel, "hits himself over the head with a skillet")
|
||||
p.LastFact = nil
|
||||
|
@ -531,7 +531,7 @@ func (p *Factoid) forgetLastFact(message msg.Message) bool {
|
|||
}
|
||||
|
||||
// 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)
|
||||
parts := strings.SplitN(message.Body, oper, 2)
|
||||
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.Tidbit = reg.ReplaceAllString(fact.Tidbit, replace)
|
||||
fact.Count += 1
|
||||
fact.accessed = time.Now()
|
||||
fact.save(p.db)
|
||||
fact.Accessed = time.Now()
|
||||
fact.Save(p.db)
|
||||
}
|
||||
} else if len(parts) == 3 {
|
||||
// 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.
|
||||
// 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 *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?" {
|
||||
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.
|
||||
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 also figure out some variables including: $nonzero, $digit, $nick, and $someone.")
|
||||
return true
|
||||
}
|
||||
|
||||
// Pull a fact at random from the database
|
||||
func (p *Factoid) randomFact() *factoid {
|
||||
f, err := getSingle(p.db)
|
||||
func (p *FactoidPlugin) randomFact() *Factoid {
|
||||
f, err := GetSingle(p.db)
|
||||
if err != nil {
|
||||
fmt.Println("Error getting a fact: ", err)
|
||||
return nil
|
||||
|
@ -691,7 +691,7 @@ func (p *Factoid) randomFact() *factoid {
|
|||
}
|
||||
|
||||
// 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)
|
||||
if quoteTime == 0 {
|
||||
quoteTime = 30
|
||||
|
@ -739,7 +739,7 @@ func (p *Factoid) factTimer(channel string) {
|
|||
}
|
||||
|
||||
// Register any web URLs desired
|
||||
func (p *Factoid) registerWeb() {
|
||||
func (p *FactoidPlugin) registerWeb() {
|
||||
http.HandleFunc("/factoid/req", p.serveQuery)
|
||||
http.HandleFunc("/factoid", p.serveQuery)
|
||||
p.Bot.RegisterWeb("/factoid", "Factoid")
|
||||
|
@ -755,7 +755,7 @@ func linkify(text string) template.HTML {
|
|||
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{})
|
||||
funcMap := template.FuncMap{
|
||||
// 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 fact
|
||||
package remember
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -11,38 +9,32 @@ import (
|
|||
"github.com/jmoiron/sqlx"
|
||||
"github.com/velour/catbase/bot"
|
||||
"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 {
|
||||
Bot bot.Bot
|
||||
Log map[string][]msg.Message
|
||||
bot bot.Bot
|
||||
log map[string][]msg.Message
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// NewRememberPlugin creates a new RememberPlugin with the Plugin interface
|
||||
func NewRemember(b bot.Bot) *RememberPlugin {
|
||||
p := RememberPlugin{
|
||||
Bot: b,
|
||||
Log: make(map[string][]msg.Message),
|
||||
func New(b bot.Bot) *RememberPlugin {
|
||||
p := &RememberPlugin{
|
||||
bot: b,
|
||||
log: make(map[string][]msg.Message),
|
||||
db: b.DB(),
|
||||
}
|
||||
|
||||
b.Register(p, bot.Message, p.message)
|
||||
b.Register(p, bot.Message, p.help)
|
||||
return &p
|
||||
b.Register(p, bot.Help, p.help)
|
||||
|
||||
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 {
|
||||
|
||||
if strings.ToLower(message.Body) == "quote" && message.Command {
|
||||
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?
|
||||
return true
|
||||
|
@ -50,16 +42,16 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int
|
|||
|
||||
user := message.User
|
||||
parts := strings.Fields(message.Body)
|
||||
|
||||
if message.Command && len(parts) >= 3 &&
|
||||
strings.ToLower(parts[0]) == "remember" {
|
||||
|
||||
// we have a remember!
|
||||
// look through the logs and find parts[1] as a user, if not,
|
||||
// fuck this hoser
|
||||
nick := parts[1]
|
||||
snip := strings.Join(parts[2:], " ")
|
||||
for i := len(p.Log[message.Channel]) - 1; i >= 0; i-- {
|
||||
entry := p.Log[message.Channel][i]
|
||||
for i := len(p.log[message.Channel]) - 1; i >= 0; i-- {
|
||||
entry := p.log[message.Channel][i]
|
||||
log.Printf("Comparing %s:%s with %s:%s",
|
||||
entry.User.Name, entry.Body, nick, snip)
|
||||
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)
|
||||
|
||||
fact := factoid{
|
||||
fact := fact.Factoid{
|
||||
Fact: strings.ToLower(trigger),
|
||||
Verb: "reply",
|
||||
Tidbit: msg,
|
||||
Owner: user.Name,
|
||||
created: time.Now(),
|
||||
accessed: time.Now(),
|
||||
Created: time.Now(),
|
||||
Accessed: time.Now(),
|
||||
Count: 0,
|
||||
}
|
||||
if err := fact.save(p.db); err != nil {
|
||||
if err := fact.Save(p.db); err != nil {
|
||||
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)
|
||||
|
@ -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
|
||||
msg = fmt.Sprintf("Okay, %s, remembering '%s'.",
|
||||
message.User.Name, msg)
|
||||
p.Bot.Send(bot.Message, message.Channel, msg)
|
||||
p.bot.Send(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(bot.Message, message.Channel, "Sorry, I don't know that phrase.")
|
||||
p.recordMsg(message)
|
||||
return true
|
||||
}
|
||||
|
||||
p.recordMsg(message)
|
||||
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 {
|
||||
|
||||
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 " +
|
||||
"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(bot.Message, message.Channel, msg)
|
||||
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
|
||||
func (p *RememberPlugin) randQuote() string {
|
||||
|
||||
var f factoid
|
||||
var f fact.Factoid
|
||||
var tmpCreated int64
|
||||
var tmpAccessed int64
|
||||
err := p.db.QueryRow(`select * from factoid where fact like '%quotes'
|
||||
order by random() limit 1;`).Scan(
|
||||
&f.id,
|
||||
&f.ID,
|
||||
&f.Fact,
|
||||
&f.Tidbit,
|
||||
&f.Verb,
|
||||
|
@ -147,13 +137,13 @@ func (p *RememberPlugin) randQuote() string {
|
|||
log.Println("Error getting quotes: ", err)
|
||||
return "I had a problem getting your quote."
|
||||
}
|
||||
f.created = time.Unix(tmpCreated, 0)
|
||||
f.accessed = time.Unix(tmpAccessed, 0)
|
||||
f.Created = time.Unix(tmpCreated, 0)
|
||||
f.Accessed = time.Unix(tmpAccessed, 0)
|
||||
|
||||
return f.Tidbit
|
||||
}
|
||||
|
||||
func (p *RememberPlugin) recordMsg(message msg.Message) {
|
||||
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