mirror of https://github.com/velour/catbase.git
Initial mongo->sqlite move
Tons of bugs, I'm sure. This commit mostly gets the bot moving towards SQLite. It builds, but many plugins have a log.Fatal to prevent their use and it has not been tested.
This commit is contained in:
parent
cdbe9a81d7
commit
1efa7ebcd4
67
bot/bot.go
67
bot/bot.go
|
@ -3,6 +3,7 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
|
@ -11,7 +12,8 @@ import (
|
|||
|
||||
"code.google.com/p/velour/irc"
|
||||
"github.com/chrissexton/alepale/config"
|
||||
"labix.org/v2/mgo"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const actionPrefix = "\x01ACTION"
|
||||
|
@ -35,11 +37,9 @@ type Bot struct {
|
|||
|
||||
Config *config.Config
|
||||
|
||||
// Mongo connection and db allow botwide access to the database
|
||||
DbSession *mgo.Session
|
||||
Db *mgo.Database
|
||||
|
||||
varColl *mgo.Collection
|
||||
// SQL DB
|
||||
DB *sql.DB
|
||||
DBVersion int64
|
||||
|
||||
logIn chan Message
|
||||
logOut chan Messages
|
||||
|
@ -101,13 +101,11 @@ type Variable struct {
|
|||
|
||||
// NewBot creates a Bot for a given connection and set of handlers.
|
||||
func NewBot(config *config.Config, c *irc.Client) *Bot {
|
||||
session, err := mgo.Dial(config.DbServer)
|
||||
sqlDB, err := sql.Open("sqlite3", config.DbFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
db := session.DB(config.DbName)
|
||||
|
||||
logIn := make(chan Message)
|
||||
logOut := make(chan Messages)
|
||||
|
||||
|
@ -126,15 +124,15 @@ func NewBot(config *config.Config, c *irc.Client) *Bot {
|
|||
Users: users,
|
||||
Me: users[0],
|
||||
Client: c,
|
||||
DbSession: session,
|
||||
Db: db,
|
||||
varColl: db.C("variables"),
|
||||
DB: sqlDB,
|
||||
logIn: logIn,
|
||||
logOut: logOut,
|
||||
Version: config.Version,
|
||||
httpEndPoints: make(map[string]string),
|
||||
}
|
||||
|
||||
bot.migrateDB()
|
||||
|
||||
http.HandleFunc("/", bot.serveRoot)
|
||||
if config.HttpAddr == "" {
|
||||
config.HttpAddr = "127.0.0.1:1337"
|
||||
|
@ -144,6 +142,49 @@ func NewBot(config *config.Config, c *irc.Client) *Bot {
|
|||
return bot
|
||||
}
|
||||
|
||||
// Create any tables if necessary based on version of DB
|
||||
// Plugins should create their own tables, these are only for official bot stuff
|
||||
// Note: This does not return an error. Database issues are all fatal at this stage.
|
||||
func (b *Bot) migrateDB() {
|
||||
_, err := b.DB.Exec(`create table if not exists version (version integer);`)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var version int64
|
||||
err = b.DB.QueryRow("select max(version) from version").Scan(&version)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
log.Printf("No versions, we're the first!.")
|
||||
_, err := b.DB.Exec(`insert into version (version) values (1)`)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case err != nil:
|
||||
log.Fatal(err)
|
||||
default:
|
||||
b.DBVersion = version
|
||||
log.Printf("Database version: %d\n", version)
|
||||
}
|
||||
|
||||
if version == 1 {
|
||||
if _, err := b.DB.Exec(`create table if not exists variables (
|
||||
id integer primary key,
|
||||
name string,
|
||||
perms string,
|
||||
type string
|
||||
);`); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := b.DB.Exec(`create table if not exists values (
|
||||
id integer primary key,
|
||||
varId integer,
|
||||
value string
|
||||
);`); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a constructed handler to the bots handlers list
|
||||
func (b *Bot) AddHandler(name string, h Handler) {
|
||||
b.Plugins[strings.ToLower(name)] = h
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"code.google.com/p/velour/irc"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/velour/irc"
|
||||
)
|
||||
|
||||
// Interface used for compatibility with the Plugin interface
|
||||
|
@ -180,28 +182,43 @@ func (b *Bot) Filter(message Message, input string) string {
|
|||
blacklist := make(map[string]bool)
|
||||
blacklist["$and"] = true
|
||||
for len(varname) > 0 && !blacklist[varname] {
|
||||
var result []Variable
|
||||
b.varColl.Find(bson.M{"variable": varname}).All(&result)
|
||||
if len(result) == 0 {
|
||||
text, err := b.getVar(varname)
|
||||
if err != nil {
|
||||
blacklist[varname] = true
|
||||
continue
|
||||
}
|
||||
variable := result[rand.Intn(len(result))]
|
||||
input = strings.Replace(input, varname, variable.Value, 1)
|
||||
input = strings.Replace(input, varname, text, 1)
|
||||
varname = r.FindString(input)
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
func (b *Bot) getVar(varName string) (string, error) {
|
||||
var text string
|
||||
err := b.DB.QueryRow("select v.value from variables as va inner join values as v on va.id = va.id = v.varId order by random() limit 1").Scan(&text)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return "", fmt.Errorf("No factoid found")
|
||||
case err != nil:
|
||||
log.Fatal(err)
|
||||
}
|
||||
return text, nil
|
||||
}
|
||||
|
||||
func (b *Bot) listVars(channel string, parts []string) {
|
||||
var result []string
|
||||
err := b.varColl.Find(bson.M{}).Distinct("variable", &result)
|
||||
rows, err := b.DB.Query(`select name from variables`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
msg := "I know: $who, $someone, $digit, $nonzero"
|
||||
for _, variable := range result {
|
||||
for rows.Next() {
|
||||
var variable string
|
||||
err := rows.Scan(&variable)
|
||||
if err != nil {
|
||||
log.Println("Error scanning variable.")
|
||||
continue
|
||||
}
|
||||
msg = fmt.Sprintf("%s, %s", msg, variable)
|
||||
}
|
||||
b.SendMessage(channel, msg)
|
||||
|
|
90
bot/users.go
90
bot/users.go
|
@ -2,13 +2,6 @@
|
|||
|
||||
package bot
|
||||
|
||||
import (
|
||||
// "labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
)
|
||||
|
||||
// User type stores user history. This is a vehicle that will follow the user for the active
|
||||
// session
|
||||
type User struct {
|
||||
|
@ -26,6 +19,18 @@ type User struct {
|
|||
//bot *Bot
|
||||
}
|
||||
|
||||
var users map[string]*User
|
||||
|
||||
func (b *Bot) GetUser(nick string) *User {
|
||||
if _, ok := users[nick]; !ok {
|
||||
users[nick] = &User{
|
||||
Name: nick,
|
||||
Admin: b.checkAdmin(nick),
|
||||
}
|
||||
}
|
||||
return users[nick]
|
||||
}
|
||||
|
||||
func (b *Bot) NewUser(nick string) *User {
|
||||
return &User{
|
||||
Name: nick,
|
||||
|
@ -33,77 +38,6 @@ func (b *Bot) NewUser(nick string) *User {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *Bot) GetUser(nick string) *User {
|
||||
coll := b.Db.C("users")
|
||||
query := coll.Find(bson.M{"name": nick})
|
||||
var user *User
|
||||
|
||||
count, err := query.Count()
|
||||
|
||||
if err != nil {
|
||||
user = b.NewUser(nick)
|
||||
coll.Insert(*user)
|
||||
} else if count == 1 {
|
||||
err = query.One(&user)
|
||||
if err != nil {
|
||||
log.Printf("ERROR adding user: %s -- %s\n", nick, err)
|
||||
}
|
||||
} else if count == 0 {
|
||||
// create the user
|
||||
log.Printf("Creating new user: %s\n", nick)
|
||||
user = b.NewUser(nick)
|
||||
coll.Insert(user)
|
||||
} else {
|
||||
log.Printf("Error: %s appears to have more than one user?\n", nick)
|
||||
query.One(&user)
|
||||
}
|
||||
|
||||
// grab linked user, if any
|
||||
if user.Parent != "" {
|
||||
query := coll.Find(bson.M{"Name": user.Parent})
|
||||
if count, err := query.Count(); err != nil && count == 1 {
|
||||
query.One(user)
|
||||
} else {
|
||||
log.Printf("Error: bad linkage on %s -> %s.\n",
|
||||
user.Name,
|
||||
user.Parent)
|
||||
}
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, u := range b.Users {
|
||||
if u.Name == user.Name {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
b.Users = append(b.Users, *user)
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
// Modify user entry to be a link to other, return other
|
||||
func (u *User) LinkUser(coll *mgo.Collection, other *User) *User {
|
||||
user := u
|
||||
|
||||
other.Alts = append(other.Alts, user.Alts...)
|
||||
user.Alts = []string{}
|
||||
user.Parent = other.Name
|
||||
|
||||
err := coll.Update(bson.M{"name": u.Name}, u)
|
||||
if err != nil {
|
||||
log.Printf("Error updating user: %s\n", u.Name)
|
||||
}
|
||||
|
||||
err = coll.Update(bson.M{"name": other.Name}, other)
|
||||
if err != nil {
|
||||
log.Printf("Error updating other user: %s\n", other.Name)
|
||||
}
|
||||
|
||||
return other
|
||||
}
|
||||
|
||||
func (b *Bot) checkAdmin(nick string) bool {
|
||||
for _, u := range b.Config.Admins {
|
||||
if nick == u {
|
||||
|
|
|
@ -9,6 +9,7 @@ import "io/ioutil"
|
|||
// Config stores any system-wide startup information that cannot be easily configured via
|
||||
// the database
|
||||
type Config struct {
|
||||
DbFile string
|
||||
DbName string
|
||||
DbServer string
|
||||
Channels []string
|
||||
|
|
|
@ -3,26 +3,28 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
)
|
||||
|
||||
// This is a admin plugin to serve as an example and quick copy/paste for new plugins.
|
||||
|
||||
type AdminPlugin struct {
|
||||
Bot *bot.Bot
|
||||
factC, remC, beerC, varC *mgo.Collection
|
||||
Bot *bot.Bot
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// NewAdminPlugin creates a new AdminPlugin with the Plugin interface
|
||||
func NewAdminPlugin(bot *bot.Bot) *AdminPlugin {
|
||||
p := &AdminPlugin{
|
||||
Bot: bot,
|
||||
DB: bot.DB,
|
||||
}
|
||||
p.LoadData()
|
||||
return p
|
||||
|
@ -56,19 +58,24 @@ func (p *AdminPlugin) handleVariables(message bot.Message) bool {
|
|||
variable := strings.TrimSpace(parts[0])
|
||||
value := parts[1]
|
||||
|
||||
q := p.varC.Find(bson.M{"variable": variable, "value": value})
|
||||
if n, _ := q.Count(); n != 0 {
|
||||
p.Bot.SendMessage(message.Channel, "I've already got that one.")
|
||||
var count int64
|
||||
var varId int64
|
||||
err := p.DB.QueryRow(`select count(*), varId from variables vs inner join values v on vs.id = v.varId where vs.name = ? and v.value = ?`, variable, value).Scan(&count)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
_, err := p.DB.Exec(`insert into values (varId, value) values (?, ?)`, varId, value)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
msg := fmt.Sprintf("Added '%s' to %s.\n", value, variable)
|
||||
p.Bot.SendMessage(message.Channel, msg)
|
||||
return true
|
||||
case err != nil:
|
||||
p.Bot.SendMessage(message.Channel, "I'm broke and need attention in my variable creation code.")
|
||||
log.Println(err)
|
||||
return true
|
||||
}
|
||||
|
||||
p.varC.Insert(bot.Variable{
|
||||
Variable: variable,
|
||||
Value: value,
|
||||
})
|
||||
|
||||
msg := fmt.Sprintf("Added '%s' to %s.\n", value, variable)
|
||||
p.Bot.SendMessage(message.Channel, msg)
|
||||
p.Bot.SendMessage(message.Channel, "I've already got that one.")
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -78,10 +85,6 @@ func (p *AdminPlugin) handleVariables(message bot.Message) bool {
|
|||
func (p *AdminPlugin) LoadData() {
|
||||
// This bot has no data to load
|
||||
rand.Seed(time.Now().Unix())
|
||||
p.factC = p.Bot.Db.C("factoid")
|
||||
p.remC = p.Bot.Db.C("remember")
|
||||
p.beerC = p.Bot.Db.C("beers")
|
||||
p.varC = p.Bot.Db.C("variables")
|
||||
}
|
||||
|
||||
// Help responds to help requests. Every plugin must implement a help function.
|
||||
|
|
178
plugins/beers.go
178
plugins/beers.go
|
@ -3,6 +3,7 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -15,21 +16,56 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
// This is a skeleton plugin to serve as an example and quick copy/paste for new plugins.
|
||||
|
||||
type BeersPlugin struct {
|
||||
Bot *bot.Bot
|
||||
Coll *mgo.Collection
|
||||
Bot *bot.Bot
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
type userBeers struct {
|
||||
id int64
|
||||
nick string
|
||||
count int
|
||||
lastDrunk time.Time
|
||||
saved bool
|
||||
}
|
||||
|
||||
type untappdUser struct {
|
||||
id int64
|
||||
untappdUser string
|
||||
channel string
|
||||
lastCheckin int
|
||||
chanNick string
|
||||
}
|
||||
|
||||
// NewBeersPlugin creates a new BeersPlugin with the Plugin interface
|
||||
func NewBeersPlugin(bot *bot.Bot) *BeersPlugin {
|
||||
if bot.DBVersion == 1 {
|
||||
if _, err := bot.DB.Exec(`create table if not exists beers (
|
||||
id integer primary key,
|
||||
nick string,
|
||||
count integer,
|
||||
lastDrunk integer
|
||||
);`); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := bot.DB.Exec(`create table if not exists untappd (
|
||||
id integer primary key,
|
||||
untappdUser string
|
||||
channel string
|
||||
lastCheckin integer
|
||||
chanNick string
|
||||
);`); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
p := BeersPlugin{
|
||||
Bot: bot,
|
||||
db: bot.DB,
|
||||
}
|
||||
p.LoadData()
|
||||
for _, channel := range bot.Config.UntappdChannels {
|
||||
|
@ -38,31 +74,39 @@ func NewBeersPlugin(bot *bot.Bot) *BeersPlugin {
|
|||
return &p
|
||||
}
|
||||
|
||||
type userBeers struct {
|
||||
Nick string
|
||||
Beercount int
|
||||
Lastdrunk time.Time
|
||||
Momentum float64
|
||||
New bool
|
||||
func (u *userBeers) Save(db *sql.DB) error {
|
||||
if !u.saved {
|
||||
res, err := db.Exec(`insert into beers (
|
||||
nick string,
|
||||
count integer,
|
||||
lastDrunk integer
|
||||
) values (?, ?, ?)`, u.nick, u.count, u.lastDrunk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.id = id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *userBeers) Save(coll *mgo.Collection) {
|
||||
_, err := coll.Upsert(bson.M{"nick": u.Nick}, u)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func getUserBeers(db *sql.DB, nick string) *userBeers {
|
||||
var ub userBeers
|
||||
err := db.QueryRow(`select id, nick, count, lastDrunk from beers
|
||||
where nick = ?`, nick).Scan(
|
||||
&ub.id,
|
||||
&ub.nick,
|
||||
&ub.count,
|
||||
&ub.lastDrunk,
|
||||
)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getUserBeers(coll *mgo.Collection, nick string) *userBeers {
|
||||
ub := userBeers{New: true}
|
||||
coll.Find(bson.M{"nick": nick}).One(&ub)
|
||||
if ub.New == true {
|
||||
ub.New = false
|
||||
ub.Nick = nick
|
||||
ub.Beercount = 0
|
||||
ub.Momentum = 0
|
||||
ub.Save(coll)
|
||||
}
|
||||
return &ub
|
||||
}
|
||||
|
||||
|
@ -160,16 +204,33 @@ func (p *BeersPlugin) Message(message bot.Message) bool {
|
|||
channel = parts[3]
|
||||
}
|
||||
u := untappdUser{
|
||||
UntappdUser: parts[1],
|
||||
ChanNick: chanNick,
|
||||
Channel: channel,
|
||||
untappdUser: parts[1],
|
||||
chanNick: chanNick,
|
||||
channel: channel,
|
||||
}
|
||||
|
||||
log.Println("Creating Untappd user:", u.UntappdUser, "nick:", u.ChanNick)
|
||||
log.Println("Creating Untappd user:", u.untappdUser, "nick:", u.chanNick)
|
||||
|
||||
_, err := p.Coll.Upsert(bson.M{"untappduser": u.UntappdUser}, u)
|
||||
var count int
|
||||
err := p.db.QueryRow(`select count(*) from untappd
|
||||
where untappdUser = ?`, u.untappdUser).Scan(&count)
|
||||
if err != nil {
|
||||
log.Println("ERROR!!!:", err)
|
||||
log.Println("Error registering untappd: ", err)
|
||||
}
|
||||
if count > 0 {
|
||||
p.Bot.SendMessage(channel, "I'm already watching you.")
|
||||
return true
|
||||
}
|
||||
_, err = p.db.Exec(`insert into untappd (
|
||||
untappdUser,
|
||||
channel,
|
||||
lastCheckin,
|
||||
chanNick
|
||||
) values (?, ?, ?, ?);`)
|
||||
if err != nil {
|
||||
log.Println("Error registering untappd: ", err)
|
||||
p.Bot.SendMessage(channel, "I can't see.")
|
||||
return true
|
||||
}
|
||||
|
||||
p.Bot.SendMessage(channel, "I'll be watching you.")
|
||||
|
@ -196,7 +257,6 @@ func (p *BeersPlugin) Event(kind string, message bot.Message) bool {
|
|||
// than the fact that the Plugin interface demands it exist. This may be deprecated at a later
|
||||
// date.
|
||||
func (p *BeersPlugin) LoadData() {
|
||||
p.Coll = p.Bot.Db.C("beers")
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
|
@ -209,10 +269,10 @@ func (p *BeersPlugin) Help(channel string, parts []string) {
|
|||
}
|
||||
|
||||
func (p *BeersPlugin) setBeers(user string, amount int) {
|
||||
ub := getUserBeers(p.Coll, user)
|
||||
ub.Beercount = amount
|
||||
ub.Lastdrunk = time.Now()
|
||||
ub.Save(p.Coll)
|
||||
ub := getUserBeers(p.db, user)
|
||||
ub.count = amount
|
||||
ub.lastDrunk = time.Now()
|
||||
ub.Save(p.db)
|
||||
}
|
||||
|
||||
func (p *BeersPlugin) addBeers(user string) {
|
||||
|
@ -220,9 +280,8 @@ func (p *BeersPlugin) addBeers(user string) {
|
|||
}
|
||||
|
||||
func (p *BeersPlugin) getBeers(nick string) int {
|
||||
ub := getUserBeers(p.Coll, nick)
|
||||
|
||||
return ub.Beercount
|
||||
ub := getUserBeers(p.db, nick)
|
||||
return ub.count
|
||||
}
|
||||
|
||||
func (p *BeersPlugin) reportCount(nick, channel string, himself bool) {
|
||||
|
@ -245,9 +304,10 @@ func (p *BeersPlugin) puke(user string, channel string) {
|
|||
}
|
||||
|
||||
func (p *BeersPlugin) doIKnow(nick string) bool {
|
||||
count, err := p.Coll.Find(bson.M{"nick": nick}).Count()
|
||||
var count int
|
||||
err := p.db.QueryRow(`select count(*) from beers where nick = ?`, nick).Scan(&count)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false
|
||||
}
|
||||
return count > 0
|
||||
}
|
||||
|
@ -288,15 +348,6 @@ type Beers struct {
|
|||
Response resp
|
||||
}
|
||||
|
||||
type untappdUser struct {
|
||||
Id bson.ObjectId `bson:"_id,omitempty"`
|
||||
UntappdUser string
|
||||
Channel string
|
||||
LastCheckin int
|
||||
ChanNick string
|
||||
KnownCheckins [5]int
|
||||
}
|
||||
|
||||
func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
|
||||
access_token := "?access_token=" + p.Bot.Config.UntappdToken
|
||||
baseUrl := "https://api.untappd.com/v4/checkin/recent/"
|
||||
|
@ -331,11 +382,20 @@ func (p *BeersPlugin) checkUntappd(channel string) {
|
|||
}
|
||||
|
||||
var users []untappdUser
|
||||
p.Coll.Find(bson.M{"untappduser": bson.M{"$exists": true}, "channel": channel}).All(&users)
|
||||
rows, err := p.db.Query(`select *from untappd`)
|
||||
if err != nil {
|
||||
log.Println("Error getting untappd users: ", err)
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
u := untappdUser{}
|
||||
rows.Scan(&u.id, &u.untappdUser, &u.channel, &u.lastCheckin, &u.chanNick)
|
||||
users = append(users, u)
|
||||
}
|
||||
|
||||
userMap := make(map[string]untappdUser)
|
||||
for _, u := range users {
|
||||
userMap[u.UntappdUser] = u
|
||||
userMap[u.untappdUser] = u
|
||||
}
|
||||
|
||||
chks, err := p.pullUntappd()
|
||||
|
@ -347,7 +407,7 @@ func (p *BeersPlugin) checkUntappd(channel string) {
|
|||
continue
|
||||
}
|
||||
|
||||
if checkin.Checkin_id <= userMap[checkin.User.User_name].LastCheckin {
|
||||
if checkin.Checkin_id <= userMap[checkin.User.User_name].lastCheckin {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -362,18 +422,20 @@ func (p *BeersPlugin) checkUntappd(channel string) {
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
p.addBeers(user.ChanNick)
|
||||
drunken := p.getBeers(user.ChanNick)
|
||||
p.addBeers(user.chanNick)
|
||||
drunken := p.getBeers(user.chanNick)
|
||||
|
||||
msg := fmt.Sprintf("%s just drank %s by %s%s, bringing his drunkeness to %d",
|
||||
user.ChanNick, beerName, breweryName, venue, drunken)
|
||||
user.chanNick, beerName, breweryName, venue, drunken)
|
||||
if checkin.Checkin_comment != "" {
|
||||
msg = fmt.Sprintf("%s -- %s",
|
||||
msg, checkin.Checkin_comment)
|
||||
}
|
||||
|
||||
user.LastCheckin = checkin.Checkin_id
|
||||
err := p.Coll.Update(bson.M{"_id": user.Id}, user)
|
||||
user.lastCheckin = checkin.Checkin_id
|
||||
_, err := p.db.Exec(`update untappd set
|
||||
lastCheckin = ?
|
||||
where id = ?`, user.lastCheckin, user.id)
|
||||
if err != nil {
|
||||
log.Println("UPDATE ERROR!:", err)
|
||||
}
|
||||
|
|
|
@ -3,21 +3,23 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
)
|
||||
|
||||
// This is a counter plugin to count arbitrary things.
|
||||
|
||||
type CounterPlugin struct {
|
||||
Bot *bot.Bot
|
||||
Coll *mgo.Collection
|
||||
Bot *bot.Bot
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
ID int64
|
||||
Nick string
|
||||
Item string
|
||||
Count int
|
||||
|
@ -25,9 +27,19 @@ type Item struct {
|
|||
|
||||
// NewCounterPlugin creates a new CounterPlugin with the Plugin interface
|
||||
func NewCounterPlugin(bot *bot.Bot) *CounterPlugin {
|
||||
if bot.DBVersion == 1 {
|
||||
if _, err := bot.DB.Exec(`create table if not exists counter (
|
||||
id integer primary key,
|
||||
nick string,
|
||||
item string,
|
||||
count integer
|
||||
);`); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
return &CounterPlugin{
|
||||
Bot: bot,
|
||||
Coll: bot.Db.C("counter"),
|
||||
Bot: bot,
|
||||
DB: bot.DB,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,38 +67,47 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
|
|||
}
|
||||
|
||||
// pull all of the items associated with "subject"
|
||||
var items []Item
|
||||
p.Coll.Find(bson.M{"nick": subject}).All(&items)
|
||||
|
||||
if len(items) == 0 {
|
||||
p.Bot.SendMessage(channel, fmt.Sprintf("%s has no counters.", subject))
|
||||
return true
|
||||
rows, err := p.DB.Query(`select * from counter where nick = ?`, subject)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
resp := fmt.Sprintf("%s has the following counters:", subject)
|
||||
for i, item := range items {
|
||||
if i != 0 {
|
||||
resp = fmt.Sprintf("%s,", resp)
|
||||
count := 0
|
||||
for rows.Next() {
|
||||
count += 1
|
||||
var it Item
|
||||
rows.Scan(&it.Nick, &it.Item, &it.Count)
|
||||
|
||||
if count > 1 {
|
||||
resp = fmt.Sprintf("%s, ", resp)
|
||||
}
|
||||
resp = fmt.Sprintf("%s %s: %d", resp, item.Item, item.Count)
|
||||
if i > 20 {
|
||||
resp = fmt.Sprintf("%s %s: %d", resp, it.Item, it.Count)
|
||||
if count > 20 {
|
||||
fmt.Sprintf("%s, and a few others", resp)
|
||||
break
|
||||
}
|
||||
}
|
||||
resp = fmt.Sprintf("%s.", resp)
|
||||
|
||||
if count == 0 {
|
||||
p.Bot.SendMessage(channel, fmt.Sprintf("%s has no counters.", subject))
|
||||
return true
|
||||
}
|
||||
|
||||
p.Bot.SendMessage(channel, resp)
|
||||
return true
|
||||
} else if message.Command && len(parts) == 2 && parts[0] == "clear" {
|
||||
subject := strings.ToLower(nick)
|
||||
itemName := strings.ToLower(parts[1])
|
||||
|
||||
p.Coll.Remove(bson.M{"nick": subject, "item": itemName})
|
||||
if _, err := p.DB.Exec(`delete from counters where nick = ? and item = ?`, subject, itemName); err != nil {
|
||||
p.Bot.SendMessage(channel, "Something went wrong removing that counter;")
|
||||
return true
|
||||
}
|
||||
|
||||
p.Bot.SendAction(channel, fmt.Sprintf("chops a few %s out of his brain",
|
||||
itemName))
|
||||
|
||||
return true
|
||||
|
||||
} else if message.Command && parts[0] == "count" {
|
||||
|
@ -105,11 +126,18 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
|
|||
}
|
||||
|
||||
var item Item
|
||||
err := p.Coll.Find(bson.M{"nick": subject, "item": itemName}).One(&item)
|
||||
if err != nil {
|
||||
err := p.DB.QueryRow(`select nick, item, count from counters
|
||||
where nick = ? and item = ?`, subject, itemName).Scan(
|
||||
&item.Nick, &item.Item, &item.Count,
|
||||
)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
p.Bot.SendMessage(channel, fmt.Sprintf("I don't think %s has any %s.",
|
||||
subject, itemName))
|
||||
return true
|
||||
case err != nil:
|
||||
log.Println(err)
|
||||
return true
|
||||
}
|
||||
|
||||
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, item.Count,
|
||||
|
@ -149,21 +177,31 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
|
|||
|
||||
func (p *CounterPlugin) update(subject, itemName string, delta int) Item {
|
||||
var item Item
|
||||
err := p.Coll.Find(bson.M{"nick": subject, "item": itemName}).One(&item)
|
||||
if err != nil {
|
||||
err := p.DB.QueryRow(`select id, nick, item, count from counter
|
||||
where nick = ? and item = ?;`, subject, itemName).Scan(
|
||||
&item.ID, &item.Nick, &item.Item, &item.Count,
|
||||
)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
// insert it
|
||||
item = Item{
|
||||
Nick: subject,
|
||||
Item: itemName,
|
||||
Count: delta,
|
||||
res, err := p.DB.Exec(`insert into counter (nick, item, count)
|
||||
values (?, ?, ?)`, subject, itemName, delta)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
p.Coll.Insert(item)
|
||||
} else {
|
||||
// update it
|
||||
id, err := res.LastInsertId()
|
||||
return Item{id, subject, itemName, delta}
|
||||
case err != nil:
|
||||
log.Println(err)
|
||||
return item
|
||||
default:
|
||||
item.Count += delta
|
||||
p.Coll.Update(bson.M{"nick": subject, "item": itemName}, item)
|
||||
_, err := p.DB.Exec(`update counter set count = ? where id = ?`, item.Count, item.ID)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return item
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
// LoadData imports any configuration data into the plugin. This is not
|
||||
|
|
|
@ -6,12 +6,13 @@ import "github.com/chrissexton/alepale/bot"
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
// This is a downtime plugin to monitor how much our users suck
|
||||
|
@ -123,7 +124,9 @@ func (p *DowntimePlugin) remove(user string) {
|
|||
// than the fact that the Plugin interface demands it exist. This may be deprecated at a later
|
||||
// date.
|
||||
func (p *DowntimePlugin) LoadData() {
|
||||
p.Coll = p.Bot.Db.C("downtime")
|
||||
// Mongo is removed, this plugin will crash if started
|
||||
log.Fatal("The Downtime plugin has not been upgraded to SQL yet.")
|
||||
// p.Coll = p.Bot.Db.C("downtime")
|
||||
}
|
||||
|
||||
// Help responds to help requests. Every plugin must implement a help function.
|
||||
|
|
|
@ -420,7 +420,9 @@ func (p *FactoidPlugin) Message(message bot.Message) bool {
|
|||
// than the fact that the Plugin interface demands it exist. This may be deprecated at a later
|
||||
// date.
|
||||
func (p *FactoidPlugin) LoadData() {
|
||||
p.Coll = p.Bot.Db.C("factoid")
|
||||
// Mongo is removed, this plugin will crash if started
|
||||
log.Fatal("The Factoid plugin has not been upgraded to SQL yet.")
|
||||
// p.Coll = p.Bot.Db.C("factoid")
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
|
@ -517,7 +519,7 @@ func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
if e := r.FormValue("entry"); e != "" {
|
||||
var entries []Factoid
|
||||
p.Coll.Find(bson.M{"trigger": bson.M{"$regex": strings.ToLower(e)}}).All(&entries)
|
||||
p.Coll.Find(bson.M{"trigger": bson.M{"$regex": strings.ToLower(e)}}).All(&entries)
|
||||
context["Count"] = fmt.Sprintf("%d", len(entries))
|
||||
context["Entries"] = entries
|
||||
context["Search"] = e
|
||||
|
|
|
@ -23,9 +23,11 @@ type FeedPlugin struct {
|
|||
|
||||
// NewFeedPlugin creates a new FeedPlugin with the Plugin interface
|
||||
func NewFeedPlugin(bot *bot.Bot) *FeedPlugin {
|
||||
// Mongo is removed, this plugin will crash if started
|
||||
log.Fatal("The Feed plugin has not been upgraded to SQL yet.")
|
||||
p := FeedPlugin{
|
||||
Bot: bot,
|
||||
Coll: bot.Db.C("feed"),
|
||||
Bot: bot,
|
||||
// Coll: bot.Db.C("feed"),
|
||||
}
|
||||
go p.pollFeeds()
|
||||
return &p
|
||||
|
|
|
@ -4,13 +4,14 @@ package plugins
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This is a first plugin to serve as an example and quick copy/paste for new plugins.
|
||||
|
@ -30,7 +31,10 @@ type FirstEntry struct {
|
|||
|
||||
// NewFirstPlugin creates a new FirstPlugin with the Plugin interface
|
||||
func NewFirstPlugin(b *bot.Bot) *FirstPlugin {
|
||||
coll := b.Db.C("first")
|
||||
// Mongo is removed, this plugin will crash if started
|
||||
log.Fatal("The First plugin has not been upgraded to SQL yet.")
|
||||
var coll *mgo.Collection
|
||||
// coll := b.Db.C("first")
|
||||
var firsts []FirstEntry
|
||||
query := bson.M{"day": midnight(time.Now())}
|
||||
log.Println("Day:", midnight(time.Now()))
|
||||
|
@ -91,11 +95,11 @@ func (p *FirstPlugin) Message(message bot.Message) bool {
|
|||
|
||||
func (p *FirstPlugin) allowed(message bot.Message) bool {
|
||||
for _, msg := range p.Bot.Config.Bad.Msgs {
|
||||
match, err := regexp.MatchString(msg, strings.ToLower(message.Body))
|
||||
if err != nil {
|
||||
log.Println("Bad regexp: ", err)
|
||||
}
|
||||
if match {
|
||||
match, err := regexp.MatchString(msg, strings.ToLower(message.Body))
|
||||
if err != nil {
|
||||
log.Println("Bad regexp: ", err)
|
||||
}
|
||||
if match {
|
||||
log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -4,17 +4,16 @@ package plugins
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"github.com/chrissexton/kakapo/lisp"
|
||||
"labix.org/v2/mgo"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"github.com/chrissexton/kakapo/lisp"
|
||||
)
|
||||
|
||||
type LispPlugin struct {
|
||||
Bot *bot.Bot
|
||||
Coll *mgo.Collection
|
||||
Bot *bot.Bot
|
||||
}
|
||||
|
||||
type Program struct {
|
||||
|
@ -26,8 +25,7 @@ type Program struct {
|
|||
// NewLispPlugin creates a new LispPlugin with the Plugin interface
|
||||
func NewLispPlugin(bot *bot.Bot) *LispPlugin {
|
||||
return &LispPlugin{
|
||||
Bot: bot,
|
||||
Coll: bot.Db.C("lisp"),
|
||||
Bot: bot,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +41,6 @@ func (p *LispPlugin) Message(message bot.Message) bool {
|
|||
Contents: strings.Replace(message.Body, "lisp:", "", 1),
|
||||
}
|
||||
log.Println("Evaluating:", prog)
|
||||
p.Coll.Insert(prog)
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
|
|
@ -75,8 +75,7 @@ type PluginConfig struct {
|
|||
Values map[string]interface{}
|
||||
}
|
||||
|
||||
// Loads plugin config out of the DB
|
||||
// Stored in db.plugins.find("name": name)
|
||||
// Loads plugin config (could be out of a DB or something)
|
||||
func GetPluginConfig(name string) PluginConfig {
|
||||
return PluginConfig{
|
||||
Name: "TestPlugin",
|
||||
|
|
|
@ -4,13 +4,14 @@ package plugins
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
// This is a skeleton plugin to serve as an example and quick copy/paste for new
|
||||
|
@ -94,14 +95,15 @@ func (p *RememberPlugin) Message(message bot.Message) bool {
|
|||
if len(msgs) == len(snips) {
|
||||
msg := strings.Join(msgs, "$and")
|
||||
var funcres bson.M
|
||||
err := p.Bot.Db.Run(
|
||||
bson.M{"eval": "return counter(\"factoid\");"},
|
||||
&funcres,
|
||||
)
|
||||
// Needs to be upgraded to SQL
|
||||
// err := p.Bot.Db.Run(
|
||||
// bson.M{"eval": "return counter(\"factoid\");"},
|
||||
// &funcres,
|
||||
// )
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
id := int(funcres["retval"].(float64))
|
||||
|
||||
fact := Factoid{
|
||||
|
@ -116,7 +118,7 @@ func (p *RememberPlugin) Message(message bot.Message) bool {
|
|||
LastAccessed: time.Now(),
|
||||
AccessCount: 0,
|
||||
}
|
||||
if err = p.Coll.Insert(fact); err != nil {
|
||||
if err := p.Coll.Insert(fact); err != nil {
|
||||
log.Println("ERROR!!!!:", err)
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,9 @@ func (p *RememberPlugin) Message(message bot.Message) bool {
|
|||
// necessary other than the fact that the Plugin interface demands it exist.
|
||||
// This may be deprecated at a later date.
|
||||
func (p *RememberPlugin) LoadData() {
|
||||
p.Coll = p.Bot.Db.C("factoid")
|
||||
// Mongo is removed, this plugin will crash if started
|
||||
log.Fatal("The Remember plugin has not been upgraded to SQL yet.")
|
||||
// p.Coll = p.Bot.Db.C("factoid")
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
// © 2013 the AlePale Authors under the WTFPL. See AUTHORS for the list of authors.
|
||||
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"bitbucket.org/phlyingpenguin/twitter"
|
||||
"github.com/chrissexton/alepale/bot"
|
||||
"github.com/garyburd/go-oauth/oauth"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Plugin to squak tweets at the channel.
|
||||
|
||||
type TwitterPlugin struct {
|
||||
Bot *bot.Bot
|
||||
Coll *mgo.Collection
|
||||
Client *twitter.Client
|
||||
}
|
||||
|
||||
type twitterUser struct {
|
||||
Id bson.ObjectId `bson:"_id,omitempty"`
|
||||
User string
|
||||
Tweets []string
|
||||
}
|
||||
|
||||
// NewTwitterPlugin creates a new TwitterPlugin with the Plugin interface
|
||||
func NewTwitterPlugin(bot *bot.Bot) *TwitterPlugin {
|
||||
return &TwitterPlugin{
|
||||
Bot: bot,
|
||||
Coll: bot.Db.C("twitter"),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TwitterPlugin) say(message bot.Message, body string) bool {
|
||||
p.Bot.SendMessage(message.Channel, body)
|
||||
return true
|
||||
}
|
||||
|
||||
// Check for commands accepted
|
||||
// follow, unfollow
|
||||
func (p *TwitterPlugin) checkCommand(message bot.Message) bool {
|
||||
parts := strings.Split(message.Body, " ")
|
||||
if parts[0] == "follow" {
|
||||
if len(parts) != 2 {
|
||||
return p.say(message, "I don't get it.")
|
||||
}
|
||||
|
||||
user := parts[1]
|
||||
res := p.Coll.Find(bson.M{"user": user})
|
||||
|
||||
if count, _ := res.Count(); count > 0 {
|
||||
return p.say(message, "I'm already following "+user+"!")
|
||||
}
|
||||
|
||||
p.Coll.Insert(twitterUser{User: user})
|
||||
} else if parts[0] == "unfollow" {
|
||||
if len(parts) != 2 {
|
||||
return p.say(message, "I don't get it.")
|
||||
}
|
||||
|
||||
user := parts[1]
|
||||
|
||||
p.Coll.Remove(bson.M{"user": user})
|
||||
return p.say(message, "Fuck "+user)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 *TwitterPlugin) Message(message bot.Message) bool {
|
||||
|
||||
if message.Command {
|
||||
return p.checkCommand(message)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// LoadData imports any configuration data into the plugin. This is not strictly necessary other
|
||||
// than the fact that the Plugin interface demands it exist. This may be deprecated at a later
|
||||
// date.
|
||||
func (p *TwitterPlugin) LoadData() {
|
||||
// This bot has no data to load
|
||||
p.Client = twitter.New(&oauth.Credentials{
|
||||
Token: p.Bot.Config.TwitterConsumerKey,
|
||||
Secret: p.Bot.Config.TwitterConsumerSecret,
|
||||
})
|
||||
|
||||
p.Client.SetAuth(&oauth.Credentials{
|
||||
Token: p.Bot.Config.TwitterUserKey,
|
||||
Secret: p.Bot.Config.TwitterUserSecret,
|
||||
})
|
||||
|
||||
_, err := p.Client.VerifyCredentials(nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Could not auth with twitter:", err)
|
||||
} else {
|
||||
go p.checkMessages()
|
||||
}
|
||||
}
|
||||
|
||||
// Help responds to help requests. Every plugin must implement a help function.
|
||||
func (p *TwitterPlugin) Help(channel string, parts []string) {
|
||||
p.Bot.SendMessage(channel, "Tell me to follow or unfollow twitter users!")
|
||||
}
|
||||
|
||||
// Empty event handler because this plugin does not do anything on event recv
|
||||
func (p *TwitterPlugin) Event(kind string, message bot.Message) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *TwitterPlugin) checkMessages() {
|
||||
for {
|
||||
time.Sleep(time.Minute * 30)
|
||||
var u url.Values
|
||||
u.Set("screen_name", "phlyingpenguin")
|
||||
data, err := p.Client.UserTimeline(u)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
log.Println(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for bot's own messages
|
||||
func (p *TwitterPlugin) BotMessage(message bot.Message) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Register any web URLs desired
|
||||
func (p *TwitterPlugin) RegisterWeb() *string {
|
||||
return nil
|
||||
}
|
|
@ -5,6 +5,8 @@ package plugins
|
|||
// I hate this, but I'm creating strings of the templates to avoid having to
|
||||
// track where templates reside.
|
||||
|
||||
// 2016-01-15 Later note, why are these in plugins and the server is in bot?
|
||||
|
||||
var factoidIndex string = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
|
Loading…
Reference in New Issue