From b6d63f64323f41a67140c36014b84a32da95a9f2 Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Sat, 19 Mar 2016 11:38:18 -0400 Subject: [PATCH 1/4] Fix a few minor govet issues --- plugins/counter.go | 2 +- plugins/factoid.go | 10 +++++----- slack/slack.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/counter.go b/plugins/counter.go index 5c49f35..f1915ce 100644 --- a/plugins/counter.go +++ b/plugins/counter.go @@ -84,7 +84,7 @@ func (p *CounterPlugin) Message(message bot.Message) bool { } resp = fmt.Sprintf("%s %s: %d", resp, it.Item, it.Count) if count > 20 { - fmt.Sprintf("%s, and a few others", resp) + resp = fmt.Sprintf("%s, and a few others", resp) break } } diff --git a/plugins/factoid.go b/plugins/factoid.go index dbf5da0..1d66f86 100644 --- a/plugins/factoid.go +++ b/plugins/factoid.go @@ -229,18 +229,18 @@ func NewFactoidPlugin(botInst *bot.Bot) *FactoidPlugin { for _, channel := range botInst.Config.Channels { go p.factTimer(channel) - go func() { + go func(ch) { // Some random time to start up time.Sleep(time.Duration(15) * time.Second) if ok, fact := p.findTrigger(p.Bot.Config.StartupFact); ok { p.sayFact(bot.Message{ - Channel: channel, + Channel: ch, Body: "speed test", // BUG: This is defined in the config too Command: true, Action: false, }, *fact) } - }() + }(channel) } return p @@ -373,7 +373,7 @@ func (p *FactoidPlugin) tellThemWhatThatWas(message bot.Message) bool { msg = "Nope." } else { msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'", - fact.id, fact.fact, fact.verb, fact.tidbit) + fact.id.Int64, fact.fact, fact.verb, fact.tidbit) } p.Bot.SendMessage(message.Channel, msg) return true @@ -435,7 +435,7 @@ func (p *FactoidPlugin) forgetLastFact(message bot.Message) bool { if err != nil { log.Println("Error removing fact: ", p.LastFact, err) } - fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.id, 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.SendAction(message.Channel, "hits himself over the head with a skillet") p.LastFact = nil diff --git a/slack/slack.go b/slack/slack.go index 29440d8..eb05d0a 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -1,4 +1,4 @@ -// Package to connect to slack service +// Package slack connects to slack service package slack import ( @@ -113,7 +113,7 @@ func (s *Slack) Serve() { for { msg, err := s.receiveMessage() if err != nil { - log.Printf("Slack API error: ", err) + log.Fatalf("Slack API error: %s", err) } switch msg.Type { case "message": @@ -134,7 +134,7 @@ func (s *Slack) Serve() { // Convert a slackMessage to a bot.Message func (s *Slack) buildMessage(msg slackMessage) bot.Message { - log.Println("DEBUG: msg: %%#v", msg) + log.Printf("DEBUG: msg: %#v", msg) text := html.UnescapeString(msg.Text) isCmd, text := bot.IsCmd(s.config, text) From 28ccc4f0c2e062011c69a75b91c04d98ce5b12ca Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Sat, 19 Mar 2016 11:44:27 -0400 Subject: [PATCH 2/4] Move counter to its own package --- plugins/{ => counter}/counter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename plugins/{ => counter}/counter.go (99%) diff --git a/plugins/counter.go b/plugins/counter/counter.go similarity index 99% rename from plugins/counter.go rename to plugins/counter/counter.go index f1915ce..c67168c 100644 --- a/plugins/counter.go +++ b/plugins/counter/counter.go @@ -1,6 +1,6 @@ // © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors. -package plugins +package counter import ( "database/sql" From ae5d7dec2e3c28bee1cffb2392a95b1848bcefbe Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Sat, 19 Mar 2016 14:02:46 -0400 Subject: [PATCH 3/4] Migrate to sqlx; modularize counters --- bot/bot.go | 5 +- main.go | 3 +- plugins/admin.go | 3 +- plugins/beers.go | 10 ++- plugins/counter/counter.go | 151 +++++++++++++++++++++++++------------ plugins/downtime.go | 9 ++- plugins/factoid.go | 15 ++-- plugins/first.go | 7 +- plugins/remember.go | 4 +- 9 files changed, 134 insertions(+), 73 deletions(-) diff --git a/bot/bot.go b/bot/bot.go index 6e2a974..c1c8832 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/config" _ "github.com/mattn/go-sqlite3" @@ -35,7 +36,7 @@ type Bot struct { // TODO: I think it'd be nice to use https://github.com/jmoiron/sqlx so that // the select/update/etc statements could be simplified with struct // marshalling. - DB *sql.DB + DB *sqlx.DB DBVersion int64 logIn chan Message @@ -98,7 +99,7 @@ type Variable struct { // NewBot creates a Bot for a given connection and set of handlers. func NewBot(config *config.Config, connector Connector) *Bot { - sqlDB, err := sql.Open("sqlite3", config.DB.File) + sqlDB, err := sqlx.Open("sqlite3", config.DB.File) if err != nil { log.Fatal(err) } diff --git a/main.go b/main.go index 8f9e96d..a383f83 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "github.com/velour/catbase/config" "github.com/velour/catbase/irc" "github.com/velour/catbase/plugins" + "github.com/velour/catbase/plugins/counter" "github.com/velour/catbase/slack" ) @@ -39,7 +40,7 @@ func main() { b.AddHandler("talker", plugins.NewTalkerPlugin(b)) b.AddHandler("dice", plugins.NewDicePlugin(b)) b.AddHandler("beers", plugins.NewBeersPlugin(b)) - b.AddHandler("counter", plugins.NewCounterPlugin(b)) + b.AddHandler("counter", counter.NewCounterPlugin(b)) b.AddHandler("remember", plugins.NewRememberPlugin(b)) b.AddHandler("skeleton", plugins.NewSkeletonPlugin(b)) b.AddHandler("your", plugins.NewYourPlugin(b)) diff --git a/plugins/admin.go b/plugins/admin.go index 9472949..9ef3227 100644 --- a/plugins/admin.go +++ b/plugins/admin.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -17,7 +18,7 @@ import ( type AdminPlugin struct { Bot *bot.Bot - DB *sql.DB + DB *sqlx.DB } // NewAdminPlugin creates a new AdminPlugin with the Plugin interface diff --git a/plugins/beers.go b/plugins/beers.go index f16b76d..0550e7e 100644 --- a/plugins/beers.go +++ b/plugins/beers.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -22,7 +23,7 @@ import ( type BeersPlugin struct { Bot *bot.Bot - db *sql.DB + db *sqlx.DB } type userBeers struct { @@ -74,7 +75,7 @@ func NewBeersPlugin(bot *bot.Bot) *BeersPlugin { return &p } -func (u *userBeers) Save(db *sql.DB) error { +func (u *userBeers) Save(db *sqlx.DB) error { if !u.saved { res, err := db.Exec(`insert into beers ( nick, @@ -102,7 +103,7 @@ func (u *userBeers) Save(db *sql.DB) error { return nil } -func getUserBeers(db *sql.DB, nick string) *userBeers { +func getUserBeers(db *sqlx.DB, nick string) *userBeers { ub := userBeers{saved: true} err := db.QueryRow(`select id, nick, count, lastDrunk from beers where nick = ?`, nick).Scan( @@ -401,7 +402,8 @@ func (p *BeersPlugin) pullUntappd() ([]checkin, error) { } func (p *BeersPlugin) checkUntappd(channel string) { - if p.Bot.Config.Untappd.Token == "" { + token := p.Bot.Config.Untappd.Token + if token == "" || token == "" { log.Println("No Untappd token, cannot enable plugin.") return } diff --git a/plugins/counter/counter.go b/plugins/counter/counter.go index c67168c..f1be7dd 100644 --- a/plugins/counter/counter.go +++ b/plugins/counter/counter.go @@ -8,6 +8,7 @@ import ( "log" "strings" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -15,16 +16,78 @@ import ( type CounterPlugin struct { Bot *bot.Bot - DB *sql.DB + DB *sqlx.DB } type Item struct { + *sqlx.DB + ID int64 Nick string Item string Count int } +func GetItems(db *sqlx.DB, nick string) ([]Item, error) { + var items []Item + err := db.Select(&items, `select * from counter where nick = ?`, nick) + if err != nil { + return nil, err + } + // Don't forget to embed the DB into all of that shiz + for _, i := range items { + i.DB = db + } + return items, nil +} + +func GetItem(db *sqlx.DB, nick, itemName string) (Item, error) { + var item Item + item.DB = db + log.Printf("GetItem db: %#v", db) + err := db.Get(&item, `select * from counter where nick = ? and item= ?`, + nick, itemName) + switch err { + case sql.ErrNoRows: + item.ID = -1 + item.Nick = nick + item.Item = itemName + case nil: + default: + return Item{}, err + } + log.Printf("Got item %s.%s: %#v", nick, itemName, item) + return item, nil +} + +func (i *Item) Create() error { + res, err := i.Exec(`insert into counter (nick, item, count) values (?, ?, ?);`, + i.Nick, i.Item, i.Count) + id, _ := res.LastInsertId() + // hackhackhack? + i.ID = id + return err +} + +func (i *Item) Update(delta int) error { + i.Count += delta + if i.Count == 0 && i.ID != -1 { + return i.Delete() + } + if i.ID == -1 { + i.Create() + } + log.Printf("Updating item: %#v, delta: %d", i, delta) + _, err := i.Exec(`update counter set count = ? where id = ?`, i.Count, i.ID) + return err +} + +func (i *Item) Delete() error { + _, err := i.Exec(`delete from counter where id = ?`, i.ID) + i.ID = -1 + return err +} + // NewCounterPlugin creates a new CounterPlugin with the Plugin interface func NewCounterPlugin(bot *bot.Bot) *CounterPlugin { if bot.DBVersion == 1 { @@ -63,32 +126,31 @@ func (p *CounterPlugin) Message(message bot.Message) bool { if parts[1] == "me" { subject = strings.ToLower(nick) } else { - subject = parts[1] + subject = strings.ToLower(parts[1]) } // pull all of the items associated with "subject" - rows, err := p.DB.Query(`select * from counter where nick = ?`, subject) + items, err := GetItems(p.DB, subject) if err != nil { - log.Fatal(err) + log.Fatalf("Error retrieving items for %s: %s", subject, err) + p.Bot.SendMessage(channel, "Something went wrong finding that counter;") + return true } resp := fmt.Sprintf("%s has the following counters:", subject) count := 0 - for rows.Next() { + for _, it := range items { count += 1 - var it Item - rows.Scan(&it.Nick, &it.Item, &it.Count) - if count > 1 { - resp = fmt.Sprintf("%s, ", resp) + resp += ", " } - resp = fmt.Sprintf("%s %s: %d", resp, it.Item, it.Count) + resp += fmt.Sprintf(" %s: %d", it.Item, it.Count) if count > 20 { - resp = fmt.Sprintf("%s, and a few others", resp) + resp += ", and a few others" break } } - resp = fmt.Sprintf("%s.", resp) + resp += "." if count == 0 { p.Bot.SendMessage(channel, fmt.Sprintf("%s has no counters.", subject)) @@ -101,7 +163,15 @@ func (p *CounterPlugin) Message(message bot.Message) bool { subject := strings.ToLower(nick) itemName := strings.ToLower(parts[1]) - if _, err := p.DB.Exec(`delete from counter where nick = ? and item = ?`, subject, itemName); err != nil { + it, err := GetItem(p.DB, subject, itemName) + if err != nil { + log.Printf("Error getting item to remove %s.%s: %s", subject, itemName, err) + p.Bot.SendMessage(channel, "Something went wrong removing that counter;") + return true + } + err = it.Delete() + if err != nil { + log.Printf("Error removing item %s.%s: %s", subject, itemName, err) p.Bot.SendMessage(channel, "Something went wrong removing that counter;") return true } @@ -126,17 +196,15 @@ func (p *CounterPlugin) Message(message bot.Message) bool { } var item Item - err := p.DB.QueryRow(`select nick, item, count from counter - where nick = ? and item = ?`, subject, itemName).Scan( - &item.Nick, &item.Item, &item.Count, - ) + item, err := GetItem(p.DB, subject, itemName) 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) + log.Printf("Error retrieving item count for %s.%s: %s", + subject, itemName, err) return true } @@ -145,6 +213,7 @@ func (p *CounterPlugin) Message(message bot.Message) bool { return true } else if len(parts) == 1 { + // Need to have at least 3 characters to ++ or -- if len(parts[0]) < 3 { return false } @@ -159,13 +228,26 @@ func (p *CounterPlugin) Message(message bot.Message) bool { if strings.HasSuffix(parts[0], "++") { // ++ those fuckers - item := p.update(subject, itemName, 1) + item, err := GetItem(p.DB, subject, itemName) + if err != nil { + log.Printf("Error finding item %s.%s: %s.", subject, itemName, err) + // Item ain't there, I guess + return false + } + log.Printf("About to update item: %#v", item) + item.Update(1) p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true } else if strings.HasSuffix(parts[0], "--") { // -- those fuckers - item := p.update(subject, itemName, -1) + item, err := GetItem(p.DB, subject, itemName) + if err != nil { + log.Printf("Error finding item %s.%s: %s.", subject, itemName, err) + // Item ain't there, I guess + return false + } + item.Update(-1) p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true @@ -175,35 +257,6 @@ func (p *CounterPlugin) Message(message bot.Message) bool { return false } -func (p *CounterPlugin) update(subject, itemName string, delta int) Item { - var item Item - 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 - res, err := p.DB.Exec(`insert into counter (nick, item, count) - values (?, ?, ?)`, subject, itemName, delta) - if err != nil { - log.Println(err) - } - id, err := res.LastInsertId() - return Item{id, subject, itemName, delta} - case err != nil: - log.Println(err) - return item - default: - item.Count += delta - _, err := p.DB.Exec(`update counter set count = ? where id = ?`, item.Count, item.ID) - if err != nil { - log.Println(err) - } - return item - } -} - // 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. diff --git a/plugins/downtime.go b/plugins/downtime.go index a240dab..3fe5b24 100644 --- a/plugins/downtime.go +++ b/plugins/downtime.go @@ -5,6 +5,7 @@ package plugins import ( "database/sql" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -20,7 +21,7 @@ import ( type DowntimePlugin struct { Bot *bot.Bot - db *sql.DB + db *sqlx.DB } type idleEntry struct { @@ -29,7 +30,7 @@ type idleEntry struct { lastSeen time.Time } -func (entry idleEntry) saveIdleEntry(db *sql.DB) error { +func (entry idleEntry) saveIdleEntry(db *sqlx.DB) error { var err error if entry.id.Valid { log.Println("Updating downtime for: ", entry) @@ -44,7 +45,7 @@ func (entry idleEntry) saveIdleEntry(db *sql.DB) error { return err } -func getIdleEntryByNick(db *sql.DB, nick string) (idleEntry, error) { +func getIdleEntryByNick(db *sqlx.DB, nick string) (idleEntry, error) { var id sql.NullInt64 var lastSeen sql.NullInt64 err := db.QueryRow(`select id, max(lastSeen) from downtime @@ -66,7 +67,7 @@ func getIdleEntryByNick(db *sql.DB, nick string) (idleEntry, error) { }, nil } -func getAllIdleEntries(db *sql.DB) (idleEntries, error) { +func getAllIdleEntries(db *sqlx.DB) (idleEntries, error) { rows, err := db.Query(`select id, nick, max(lastSeen) from downtime group by nick`) if err != nil { diff --git a/plugins/factoid.go b/plugins/factoid.go index 1d66f86..b45e3fa 100644 --- a/plugins/factoid.go +++ b/plugins/factoid.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -31,7 +32,7 @@ type factoid struct { count int } -func (f *factoid) save(db *sql.DB) error { +func (f *factoid) save(db *sqlx.DB) error { var err error if f.id.Valid { // update @@ -82,7 +83,7 @@ func (f *factoid) save(db *sql.DB) error { return err } -func (f *factoid) delete(db *sql.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) @@ -91,7 +92,7 @@ func (f *factoid) delete(db *sql.DB) error { return err } -func getFacts(db *sql.DB, fact string) ([]*factoid, error) { +func getFacts(db *sqlx.DB, fact string) ([]*factoid, error) { var fs []*factoid rows, err := db.Query(`select id, @@ -129,7 +130,7 @@ func getFacts(db *sql.DB, fact string) ([]*factoid, error) { return fs, err } -func getSingle(db *sql.DB) (*factoid, error) { +func getSingle(db *sqlx.DB) (*factoid, error) { var f factoid var tmpCreated int64 var tmpAccessed int64 @@ -158,7 +159,7 @@ func getSingle(db *sql.DB) (*factoid, error) { return &f, err } -func getSingleFact(db *sql.DB, fact string) (*factoid, error) { +func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) { var f factoid var tmpCreated int64 var tmpAccessed int64 @@ -194,7 +195,7 @@ type FactoidPlugin struct { Bot *bot.Bot NotFound []string LastFact *factoid - db *sql.DB + db *sqlx.DB } // NewFactoidPlugin creates a new FactoidPlugin with the Plugin interface @@ -229,7 +230,7 @@ func NewFactoidPlugin(botInst *bot.Bot) *FactoidPlugin { for _, channel := range botInst.Config.Channels { go p.factTimer(channel) - go func(ch) { + go func(ch string) { // Some random time to start up time.Sleep(time.Duration(15) * time.Second) if ok, fact := p.findTrigger(p.Bot.Config.StartupFact); ok { diff --git a/plugins/first.go b/plugins/first.go index 88daed6..15ad9b0 100644 --- a/plugins/first.go +++ b/plugins/first.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -18,7 +19,7 @@ import ( type FirstPlugin struct { First *FirstEntry Bot *bot.Bot - db *sql.DB + db *sqlx.DB } type FirstEntry struct { @@ -31,7 +32,7 @@ type FirstEntry struct { } // Insert or update the first entry -func (fe *FirstEntry) save(db *sql.DB) error { +func (fe *FirstEntry) save(db *sqlx.DB) error { if _, err := db.Exec(`insert into first (day, time, body, nick) values (?, ?, ?, ?)`, fe.day.Unix(), @@ -73,7 +74,7 @@ func NewFirstPlugin(b *bot.Bot) *FirstPlugin { } } -func getLastFirst(db *sql.DB) (*FirstEntry, error) { +func getLastFirst(db *sqlx.DB) (*FirstEntry, error) { // Get last first entry var id sql.NullInt64 var day sql.NullInt64 diff --git a/plugins/remember.go b/plugins/remember.go index bbd2248..ed6e43f 100644 --- a/plugins/remember.go +++ b/plugins/remember.go @@ -3,13 +3,13 @@ package plugins import ( - "database/sql" "fmt" "log" "math/rand" "strings" "time" + "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" ) @@ -19,7 +19,7 @@ import ( type RememberPlugin struct { Bot *bot.Bot Log map[string][]bot.Message - db *sql.DB + db *sqlx.DB } // NewRememberPlugin creates a new RememberPlugin with the Plugin interface From 6938efc430ad3a17fe0e753e0f9eef2e64148e60 Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Sat, 19 Mar 2016 14:27:02 -0400 Subject: [PATCH 4/4] Fix #19: Merge beers and counters --- plugins/beers.go | 95 +++++++++----------------------------- plugins/counter/counter.go | 23 +++++++-- 2 files changed, 39 insertions(+), 79 deletions(-) diff --git a/plugins/beers.go b/plugins/beers.go index 0550e7e..b4e524e 100644 --- a/plugins/beers.go +++ b/plugins/beers.go @@ -3,7 +3,6 @@ package plugins import ( - "database/sql" "encoding/json" "errors" "fmt" @@ -17,6 +16,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/velour/catbase/bot" + "github.com/velour/catbase/plugins/counter" ) // This is a skeleton plugin to serve as an example and quick copy/paste for new plugins. @@ -26,14 +26,6 @@ type BeersPlugin struct { db *sqlx.DB } -type userBeers struct { - id int64 - nick string - count int - lastDrunk time.Time - saved bool -} - type untappdUser struct { id int64 untappdUser string @@ -75,58 +67,6 @@ func NewBeersPlugin(bot *bot.Bot) *BeersPlugin { return &p } -func (u *userBeers) Save(db *sqlx.DB) error { - if !u.saved { - res, err := db.Exec(`insert into beers ( - nick, - count, - lastDrunk - ) values (?, ?, ?)`, u.nick, u.count, u.lastDrunk) - if err != nil { - return err - } - id, err := res.LastInsertId() - if err != nil { - return err - } - u.id = id - } else { - _, err := db.Exec(`update beers set - count = ?, - lastDrunk = ? - where id = ?;`, u.count, time.Now(), u.id) - if err != nil { - log.Println("Error updating beers: ", err) - return err - } - } - return nil -} - -func getUserBeers(db *sqlx.DB, nick string) *userBeers { - ub := userBeers{saved: true} - err := db.QueryRow(`select id, nick, count, lastDrunk from beers - where nick = ?`, nick).Scan( - &ub.id, - &ub.nick, - &ub.count, - &ub.lastDrunk, - ) - if err == sql.ErrNoRows { - log.Println("DIDN'T FIND THAT USER: ", err) - return &userBeers{ - nick: nick, - count: 0, - } - } - if err != nil && err != sql.ErrNoRows { - log.Println("Error finding beers: ", err) - return nil - } - - return &ub -} - // 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. @@ -160,7 +100,7 @@ func (p *BeersPlugin) Message(message bot.Message) bool { return true } if parts[1] == "+=" { - p.setBeers(nick, p.getBeers(nick)+count) + p.addBeers(nick, count) p.randomReply(channel) } else if parts[1] == "=" { if count == 0 { @@ -186,16 +126,15 @@ func (p *BeersPlugin) Message(message bot.Message) bool { // no matter what, if we're in here, then we've responded return true } else if parts[0] == "beers--" { - p.setBeers(nick, p.getBeers(nick)-1) + p.addBeers(nick, -1) p.Bot.SendAction(channel, "flushes") return true } else if parts[0] == "beers++" { - p.addBeers(nick) + p.addBeers(nick, 1) p.randomReply(channel) return true } else if parts[0] == "bourbon++" { - p.addBeers(nick) - p.addBeers(nick) + p.addBeers(nick, 2) p.randomReply(channel) return true } else if parts[0] == "puke" { @@ -204,7 +143,7 @@ func (p *BeersPlugin) Message(message bot.Message) bool { } if message.Command && parts[0] == "imbibe" { - p.addBeers(nick) + p.addBeers(nick, 1) p.randomReply(channel) return true } @@ -292,22 +231,30 @@ func (p *BeersPlugin) Help(channel string, parts []string) { p.Bot.SendMessage(channel, msg) } +func getUserBeers(db *sqlx.DB, user string) counter.Item { + booze, _ := counter.GetItem(db, user, "booze") + return booze +} + func (p *BeersPlugin) setBeers(user string, amount int) { ub := getUserBeers(p.db, user) - ub.count = amount - ub.lastDrunk = time.Now() - if err := ub.Save(p.db); err != nil { + err := ub.Update(amount) + if err != nil { log.Println("Error saving beers: ", err) } } -func (p *BeersPlugin) addBeers(user string) { - p.setBeers(user, p.getBeers(user)+1) +func (p *BeersPlugin) addBeers(user string, delta int) { + ub := getUserBeers(p.db, user) + err := ub.UpdateDelta(delta) + if err != nil { + log.Println("Error saving beers: ", err) + } } func (p *BeersPlugin) getBeers(nick string) int { ub := getUserBeers(p.db, nick) - return ub.count + return ub.Count } func (p *BeersPlugin) reportCount(nick, channel string, himself bool) { @@ -452,7 +399,7 @@ func (p *BeersPlugin) checkUntappd(channel string) { } log.Printf("user.chanNick: %s, user.untappdUser: %s, checkin.User.User_name: %s", user.chanNick, user.untappdUser, checkin.User.User_name) - p.addBeers(user.chanNick) + p.addBeers(user.chanNick, 1) drunken := p.getBeers(user.chanNick) msg := fmt.Sprintf("%s just drank %s by %s%s, bringing his drunkeness to %d", diff --git a/plugins/counter/counter.go b/plugins/counter/counter.go index f1be7dd..a804ef4 100644 --- a/plugins/counter/counter.go +++ b/plugins/counter/counter.go @@ -28,6 +28,7 @@ type Item struct { Count int } +// GetItems returns all counters for a subject func GetItems(db *sqlx.DB, nick string) ([]Item, error) { var items []Item err := db.Select(&items, `select * from counter where nick = ?`, nick) @@ -41,6 +42,7 @@ func GetItems(db *sqlx.DB, nick string) ([]Item, error) { return items, nil } +// GetItem returns a specific counter for a subject func GetItem(db *sqlx.DB, nick, itemName string) (Item, error) { var item Item item.DB = db @@ -60,6 +62,7 @@ func GetItem(db *sqlx.DB, nick, itemName string) (Item, error) { return item, nil } +// Create saves a counter func (i *Item) Create() error { res, err := i.Exec(`insert into counter (nick, item, count) values (?, ?, ?);`, i.Nick, i.Item, i.Count) @@ -69,19 +72,29 @@ func (i *Item) Create() error { return err } -func (i *Item) Update(delta int) error { - i.Count += delta +// UpdateDelta sets a value +// This will create or delete the item if necessary +func (i *Item) Update(value int) error { + i.Count = value if i.Count == 0 && i.ID != -1 { return i.Delete() } if i.ID == -1 { i.Create() } - log.Printf("Updating item: %#v, delta: %d", i, delta) + log.Printf("Updating item: %#v, value: %d", i, value) _, err := i.Exec(`update counter set count = ? where id = ?`, i.Count, i.ID) return err } +// UpdateDelta changes a value according to some delta +// This will create or delete the item if necessary +func (i *Item) UpdateDelta(delta int) error { + i.Count += delta + return i.Update(i.Count) +} + +// Delete removes a counter from the database func (i *Item) Delete() error { _, err := i.Exec(`delete from counter where id = ?`, i.ID) i.ID = -1 @@ -235,7 +248,7 @@ func (p *CounterPlugin) Message(message bot.Message) bool { return false } log.Printf("About to update item: %#v", item) - item.Update(1) + item.UpdateDelta(1) p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true @@ -247,7 +260,7 @@ func (p *CounterPlugin) Message(message bot.Message) bool { // Item ain't there, I guess return false } - item.Update(-1) + item.UpdateDelta(-1) p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true