catbase/plugins/first/first.go

223 lines
5.5 KiB
Go
Raw Normal View History

2016-01-17 18:00:44 +00:00
// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors.
package first
import (
2016-01-15 16:54:09 +00:00
"database/sql"
"fmt"
"log"
"regexp"
"strings"
"time"
2016-03-19 18:02:46 +00:00
"github.com/jmoiron/sqlx"
2016-01-17 18:00:44 +00:00
"github.com/velour/catbase/bot"
"github.com/velour/catbase/bot/msg"
)
// This is a first plugin to serve as an example and quick copy/paste for new plugins.
type FirstPlugin struct {
First *FirstEntry
Bot bot.Bot
2016-03-19 18:02:46 +00:00
db *sqlx.DB
}
type FirstEntry struct {
2016-01-15 16:54:09 +00:00
id int64
day time.Time
time time.Time
body string
nick string
saved bool
}
// Insert or update the first entry
2016-03-19 18:02:46 +00:00
func (fe *FirstEntry) save(db *sqlx.DB) error {
2016-01-15 16:54:09 +00:00
if _, err := db.Exec(`insert into first (day, time, body, nick)
values (?, ?, ?, ?)`,
2016-01-15 18:37:54 +00:00
fe.day.Unix(),
fe.time.Unix(),
2016-01-15 16:54:09 +00:00
fe.body,
fe.nick,
); err != nil {
return err
}
return nil
}
// NewFirstPlugin creates a new FirstPlugin with the Plugin interface
func New(b bot.Bot) *FirstPlugin {
_, err := b.DB().Exec(`create table if not exists first (
2016-01-15 16:54:09 +00:00
id integer primary key,
2016-01-15 18:37:54 +00:00
day integer,
time integer,
2016-01-15 16:54:09 +00:00
body string,
nick string
);`)
if err != nil {
log.Fatal("Could not create first table: ", err)
2016-01-15 16:54:09 +00:00
}
log.Println("First plugin initialized with day:", midnight(time.Now()))
2018-06-22 18:31:33 +00:00
first, err := getLastFirst(b.DB())
2016-01-15 16:54:09 +00:00
if err != nil {
log.Fatal("Could not initialize first plugin: ", err)
}
fp := &FirstPlugin{
Bot: b,
db: b.DB(),
First: first,
}
b.Register(fp, bot.Message, fp.message)
b.Register(fp, bot.Help, fp.help)
return fp
}
2018-06-22 18:31:33 +00:00
func getLastFirst(db *sqlx.DB) (*FirstEntry, error) {
2016-01-15 16:54:09 +00:00
// Get last first entry
var id sql.NullInt64
var day sql.NullInt64
var timeEntered sql.NullInt64
var body sql.NullString
var nick sql.NullString
err := db.QueryRow(`select
id, max(day), time, body, nick from first
limit 1;
`).Scan(
&id,
&day,
&timeEntered,
&body,
&nick,
)
switch {
case err == sql.ErrNoRows || !id.Valid:
log.Println("No previous first entries")
2018-06-22 18:31:33 +00:00
return nil, nil
2016-01-15 16:54:09 +00:00
case err != nil:
2016-01-15 18:37:54 +00:00
log.Println("Error on first query row: ", err)
2018-06-22 18:31:33 +00:00
return nil, err
2016-01-15 16:54:09 +00:00
}
2016-01-15 18:37:54 +00:00
log.Println(id, day, timeEntered, body, nick)
2018-06-22 18:31:33 +00:00
return &FirstEntry{
2016-01-15 16:54:09 +00:00
id: id.Int64,
day: time.Unix(day.Int64, 0),
time: time.Unix(timeEntered.Int64, 0),
body: body.String,
nick: nick.String,
saved: true,
2018-06-22 18:31:33 +00:00
}, nil
2016-01-15 16:54:09 +00:00
}
func midnight(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
}
func isToday(t time.Time) bool {
t0 := midnight(t)
return t0.Before(midnight(time.Now()))
}
// 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 *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
// This bot does not reply to anything
if p.First == nil && p.allowed(message) {
2017-08-18 09:59:46 +00:00
log.Printf("No previous first. Recording new first: %s", message.Body)
p.recordFirst(message)
return false
} else if p.First != nil {
2016-01-15 16:54:09 +00:00
if isToday(p.First.time) && p.allowed(message) {
2017-08-18 09:59:46 +00:00
log.Printf("Recording first: %s - %v vs %v", message.Body, p.First.time, time.Now())
p.recordFirst(message)
2013-02-10 15:08:01 +00:00
return false
}
}
r := strings.NewReplacer("'", "", "\"", "", ",", "", ".", "", ":", "",
"?", "", "!", "")
msg := strings.ToLower(message.Body)
if r.Replace(msg) == "whos on first" {
2013-02-01 13:41:18 +00:00
p.announceFirst(message)
return true
}
return false
}
func (p *FirstPlugin) allowed(message msg.Message) bool {
2019-01-22 00:16:57 +00:00
for _, msg := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) {
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
}
}
2019-01-22 00:16:57 +00:00
for _, host := range p.Bot.Config().GetArray("Bad.Hosts", []string{}) {
2013-04-21 20:49:00 +00:00
if host == message.Host {
log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
return false
}
}
2019-01-22 00:16:57 +00:00
for _, nick := range p.Bot.Config().GetArray("Bad.Nicks", []string{}) {
2013-04-21 20:49:00 +00:00
if nick == message.User.Name {
log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
return false
}
}
return true
}
func (p *FirstPlugin) recordFirst(message msg.Message) {
log.Println("Recording first: ", message.User.Name, ":", message.Body)
p.First = &FirstEntry{
2016-01-15 16:54:09 +00:00
day: midnight(time.Now()),
time: message.Time,
body: message.Body,
nick: message.User.Name,
}
2017-08-18 09:59:46 +00:00
log.Printf("recordFirst: %+v", p.First.day)
2016-01-15 16:54:09 +00:00
err := p.First.save(p.db)
if err != nil {
log.Println("Error saving first entry: ", err)
return
}
2013-02-01 13:41:18 +00:00
p.announceFirst(message)
}
func (p *FirstPlugin) announceFirst(message msg.Message) {
2013-02-01 13:41:18 +00:00
c := message.Channel
if p.First != nil {
p.Bot.Send(bot.Message, c, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
2018-03-28 07:29:42 +00:00
p.First.nick, p.First.time.Format("15:04"), p.First.body))
2013-02-01 13:41:18 +00:00
}
}
// 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 *FirstPlugin) LoadData() {
// This bot has no data to load
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *FirstPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.Send(bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.")
return true
}
2013-06-01 17:10:15 +00:00
// Register any web URLs desired
func (p *FirstPlugin) RegisterWeb() *string {
return nil
}