2013-12-10 23:37:07 +00:00
|
|
|
// © 2013 the AlePale Authors under the WTFPL. See AUTHORS for the list of authors.
|
|
|
|
|
2013-01-25 21:33:41 +00:00
|
|
|
package plugins
|
|
|
|
|
|
|
|
import (
|
2016-01-15 16:54:09 +00:00
|
|
|
"database/sql"
|
2013-01-25 21:33:41 +00:00
|
|
|
"fmt"
|
|
|
|
"log"
|
2016-01-15 06:12:26 +00:00
|
|
|
"regexp"
|
2013-01-25 21:33:41 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
2016-01-15 06:12:26 +00:00
|
|
|
|
|
|
|
"github.com/chrissexton/alepale/bot"
|
2013-01-25 21:33:41 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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-01-15 16:54:09 +00:00
|
|
|
db *sql.DB
|
2013-01-25 21:33:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
func (fe *FirstEntry) save(db *sql.DB) error {
|
|
|
|
if _, err := db.Exec(`insert into first (day, time, body, nick)
|
|
|
|
values (?, ?, ?, ?)`,
|
|
|
|
fe.day,
|
|
|
|
fe.time,
|
|
|
|
fe.body,
|
|
|
|
fe.nick,
|
|
|
|
); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2013-01-25 21:33:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewFirstPlugin creates a new FirstPlugin with the Plugin interface
|
|
|
|
func NewFirstPlugin(b *bot.Bot) *FirstPlugin {
|
2016-01-15 16:54:09 +00:00
|
|
|
if b.DBVersion == 1 {
|
|
|
|
_, err := b.DB.Exec(`create table if not exists first (
|
|
|
|
id integer primary key,
|
|
|
|
day datetime,
|
|
|
|
time datetime,
|
|
|
|
body string,
|
|
|
|
nick string
|
|
|
|
);`)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Could not create first table: ", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println("First plugin initialized with day:", midnight(time.Now()))
|
|
|
|
|
|
|
|
first, err := getLastFirst(b.DB)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Could not initialize first plugin: ", err)
|
2013-01-25 21:36:19 +00:00
|
|
|
}
|
|
|
|
|
2013-01-25 21:33:41 +00:00
|
|
|
return &FirstPlugin{
|
|
|
|
Bot: b,
|
2016-01-15 16:54:09 +00:00
|
|
|
db: b.DB,
|
2013-01-25 21:36:19 +00:00
|
|
|
First: first,
|
2013-01-25 21:33:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 16:54:09 +00:00
|
|
|
func getLastFirst(db *sql.DB) (*FirstEntry, error) {
|
|
|
|
// 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")
|
|
|
|
return nil, nil
|
|
|
|
case err != nil:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &FirstEntry{
|
|
|
|
id: id.Int64,
|
|
|
|
day: time.Unix(day.Int64, 0),
|
|
|
|
time: time.Unix(timeEntered.Int64, 0),
|
|
|
|
body: body.String,
|
|
|
|
nick: nick.String,
|
|
|
|
saved: true,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2013-01-25 21:33:41 +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(message bot.Message) bool {
|
|
|
|
// This bot does not reply to anything
|
|
|
|
|
2013-03-30 11:12:27 +00:00
|
|
|
if p.First == nil && p.allowed(message) {
|
2013-01-25 21:33:41 +00:00
|
|
|
p.recordFirst(message)
|
2013-03-30 11:12:27 +00:00
|
|
|
return false
|
|
|
|
} else if p.First != nil {
|
2016-01-15 16:54:09 +00:00
|
|
|
if isToday(p.First.time) && p.allowed(message) {
|
2013-01-25 21:33:41 +00:00
|
|
|
p.recordFirst(message)
|
2013-02-10 15:08:01 +00:00
|
|
|
return false
|
2013-01-25 21:33:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2013-03-30 11:12:27 +00:00
|
|
|
log.Printf("Disallowing %s: %s from first.",
|
|
|
|
message.User.Name, message.Body)
|
2013-02-01 13:41:18 +00:00
|
|
|
return true
|
2013-01-25 21:33:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2013-03-30 11:12:27 +00:00
|
|
|
func (p *FirstPlugin) allowed(message bot.Message) bool {
|
2013-04-21 16:37:04 +00:00
|
|
|
for _, msg := range p.Bot.Config.Bad.Msgs {
|
2016-01-15 06:12:26 +00:00
|
|
|
match, err := regexp.MatchString(msg, strings.ToLower(message.Body))
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Bad regexp: ", err)
|
|
|
|
}
|
|
|
|
if match {
|
2013-03-30 11:12:27 +00:00
|
|
|
log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2013-04-21 20:49:00 +00:00
|
|
|
for _, host := range p.Bot.Config.Bad.Hosts {
|
|
|
|
if host == message.Host {
|
|
|
|
log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, nick := range p.Bot.Config.Bad.Nicks {
|
|
|
|
if nick == message.User.Name {
|
|
|
|
log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2013-03-30 11:12:27 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2013-01-25 21:33:41 +00:00
|
|
|
func (p *FirstPlugin) recordFirst(message bot.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,
|
|
|
|
}
|
|
|
|
err := p.First.save(p.db)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Error saving first entry: ", err)
|
|
|
|
return
|
2013-01-25 21:33:41 +00:00
|
|
|
}
|
2013-02-01 13:41:18 +00:00
|
|
|
p.announceFirst(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *FirstPlugin) announceFirst(message bot.Message) {
|
|
|
|
c := message.Channel
|
|
|
|
if p.First != nil {
|
|
|
|
p.Bot.SendMessage(c, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
|
2016-01-15 16:54:09 +00:00
|
|
|
p.First.nick, p.First.time.Format(time.Kitchen), p.First.body))
|
2013-02-01 13:41:18 +00:00
|
|
|
}
|
2013-01-25 21:33:41 +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(channel string, parts []string) {
|
|
|
|
p.Bot.SendMessage(channel, "Sorry, First does not do a goddamn thing.")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Empty event handler because this plugin does not do anything on event recv
|
|
|
|
func (p *FirstPlugin) Event(kind string, message bot.Message) bool {
|
|
|
|
return false
|
|
|
|
}
|
2013-05-08 00:08:18 +00:00
|
|
|
|
|
|
|
// Handler for bot's own messages
|
|
|
|
func (p *FirstPlugin) BotMessage(message bot.Message) bool {
|
|
|
|
return false
|
|
|
|
}
|
2013-06-01 17:10:15 +00:00
|
|
|
|
|
|
|
// Register any web URLs desired
|
|
|
|
func (p *FirstPlugin) RegisterWeb() *string {
|
|
|
|
return nil
|
|
|
|
}
|