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:
Chris Sexton 2016-01-15 01:12:26 -05:00
parent cdbe9a81d7
commit 1efa7ebcd4
16 changed files with 361 additions and 395 deletions

View File

@ -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

View File

@ -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)

View File

@ -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 {

View File

@ -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

View File

@ -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.

View File

@ -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)
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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",

View File

@ -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())
}

View File

@ -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
}

View File

@ -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>