mirror of https://github.com/velour/catbase.git
Merge pull request #180 from velour/firstperchannel
first: change to per channel
This commit is contained in:
commit
50dfc71269
|
@ -14,6 +14,7 @@ type Messages []Message
|
||||||
type Message struct {
|
type Message struct {
|
||||||
User *user.User
|
User *user.User
|
||||||
Channel, Body string
|
Channel, Body string
|
||||||
|
IsIM bool
|
||||||
Raw string
|
Raw string
|
||||||
Command bool
|
Command bool
|
||||||
Action bool
|
Action bool
|
||||||
|
|
|
@ -87,6 +87,11 @@ func (s *SlackApp) Serve() error {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.ReadFrom(r.Body)
|
buf.ReadFrom(r.Body)
|
||||||
body := buf.String()
|
body := buf.String()
|
||||||
|
var raw interface{}
|
||||||
|
json.Unmarshal(json.RawMessage(body), &raw)
|
||||||
|
log.Debug().
|
||||||
|
Interface("raw", raw).
|
||||||
|
Msg("Slack event")
|
||||||
eventsAPIEvent, e := slackevents.ParseEvent(json.RawMessage(body), slackevents.OptionVerifyToken(&slackevents.TokenComparator{VerificationToken: s.verification}))
|
eventsAPIEvent, e := slackevents.ParseEvent(json.RawMessage(body), slackevents.OptionVerifyToken(&slackevents.TokenComparator{VerificationToken: s.verification}))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Error().Err(e)
|
log.Error().Err(e)
|
||||||
|
@ -148,6 +153,7 @@ func (s *SlackApp) msgReceivd(msg *slackevents.MessageEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().
|
log.Debug().
|
||||||
|
Interface("event", msg).
|
||||||
Str("type", msg.SubType).
|
Str("type", msg.SubType).
|
||||||
Msg("accepting a message")
|
Msg("accepting a message")
|
||||||
|
|
||||||
|
@ -389,6 +395,7 @@ func (s *SlackApp) buildMessage(m *slackevents.MessageEvent) msg.Message {
|
||||||
Body: text,
|
Body: text,
|
||||||
Raw: m.Text,
|
Raw: m.Text,
|
||||||
Channel: m.Channel,
|
Channel: m.Channel,
|
||||||
|
IsIM: m.ChannelType == "im",
|
||||||
Command: isCmd,
|
Command: isCmd,
|
||||||
Action: isAction,
|
Action: isAction,
|
||||||
Time: tstamp,
|
Time: tstamp,
|
||||||
|
|
|
@ -18,26 +18,27 @@ import (
|
||||||
// This is a first plugin to serve as an example and quick copy/paste for new plugins.
|
// This is a first plugin to serve as an example and quick copy/paste for new plugins.
|
||||||
|
|
||||||
type FirstPlugin struct {
|
type FirstPlugin struct {
|
||||||
First *FirstEntry
|
Bot bot.Bot
|
||||||
Bot bot.Bot
|
db *sqlx.DB
|
||||||
db *sqlx.DB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FirstEntry struct {
|
type FirstEntry struct {
|
||||||
id int64
|
id int64
|
||||||
day time.Time
|
day time.Time
|
||||||
time time.Time
|
time time.Time
|
||||||
body string
|
channel string
|
||||||
nick string
|
body string
|
||||||
saved bool
|
nick string
|
||||||
|
saved bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert or update the first entry
|
// Insert or update the first entry
|
||||||
func (fe *FirstEntry) save(db *sqlx.DB) error {
|
func (fe *FirstEntry) save(db *sqlx.DB) error {
|
||||||
if _, err := db.Exec(`insert into first (day, time, body, nick)
|
if _, err := db.Exec(`insert into first (day, time, channel, body, nick)
|
||||||
values (?, ?, ?, ?)`,
|
values (?, ?, ?, ?, ?)`,
|
||||||
fe.day.Unix(),
|
fe.day.Unix(),
|
||||||
fe.time.Unix(),
|
fe.time.Unix(),
|
||||||
|
fe.channel,
|
||||||
fe.body,
|
fe.body,
|
||||||
fe.nick,
|
fe.nick,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
@ -52,6 +53,7 @@ func New(b bot.Bot) *FirstPlugin {
|
||||||
id integer primary key,
|
id integer primary key,
|
||||||
day integer,
|
day integer,
|
||||||
time integer,
|
time integer,
|
||||||
|
channel string,
|
||||||
body string,
|
body string,
|
||||||
nick string
|
nick string
|
||||||
);`)
|
);`)
|
||||||
|
@ -64,24 +66,16 @@ func New(b bot.Bot) *FirstPlugin {
|
||||||
log.Info().Msgf("First plugin initialized with day: %s",
|
log.Info().Msgf("First plugin initialized with day: %s",
|
||||||
midnight(time.Now()))
|
midnight(time.Now()))
|
||||||
|
|
||||||
first, err := getLastFirst(b.DB())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().
|
|
||||||
Err(err).
|
|
||||||
Msg("Could not initialize first plugin")
|
|
||||||
}
|
|
||||||
|
|
||||||
fp := &FirstPlugin{
|
fp := &FirstPlugin{
|
||||||
Bot: b,
|
Bot: b,
|
||||||
db: b.DB(),
|
db: b.DB(),
|
||||||
First: first,
|
|
||||||
}
|
}
|
||||||
b.Register(fp, bot.Message, fp.message)
|
b.Register(fp, bot.Message, fp.message)
|
||||||
b.Register(fp, bot.Help, fp.help)
|
b.Register(fp, bot.Help, fp.help)
|
||||||
return fp
|
return fp
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastFirst(db *sqlx.DB) (*FirstEntry, error) {
|
func getLastFirst(db *sqlx.DB, channel string) (*FirstEntry, error) {
|
||||||
// Get last first entry
|
// Get last first entry
|
||||||
var id sql.NullInt64
|
var id sql.NullInt64
|
||||||
var day sql.NullInt64
|
var day sql.NullInt64
|
||||||
|
@ -91,8 +85,9 @@ func getLastFirst(db *sqlx.DB) (*FirstEntry, error) {
|
||||||
|
|
||||||
err := db.QueryRow(`select
|
err := db.QueryRow(`select
|
||||||
id, max(day), time, body, nick from first
|
id, max(day), time, body, nick from first
|
||||||
|
where channel = ?
|
||||||
limit 1;
|
limit 1;
|
||||||
`).Scan(
|
`, channel).Scan(
|
||||||
&id,
|
&id,
|
||||||
&day,
|
&day,
|
||||||
&timeEntered,
|
&timeEntered,
|
||||||
|
@ -110,12 +105,13 @@ func getLastFirst(db *sqlx.DB) (*FirstEntry, error) {
|
||||||
log.Debug().Msgf("id: %v day %v time %v body %v nick %v",
|
log.Debug().Msgf("id: %v day %v time %v body %v nick %v",
|
||||||
id, day, timeEntered, body, nick)
|
id, day, timeEntered, body, nick)
|
||||||
return &FirstEntry{
|
return &FirstEntry{
|
||||||
id: id.Int64,
|
id: id.Int64,
|
||||||
day: time.Unix(day.Int64, 0),
|
day: time.Unix(day.Int64, 0),
|
||||||
time: time.Unix(timeEntered.Int64, 0),
|
time: time.Unix(timeEntered.Int64, 0),
|
||||||
body: body.String,
|
channel: channel,
|
||||||
nick: nick.String,
|
body: body.String,
|
||||||
saved: true,
|
nick: nick.String,
|
||||||
|
saved: true,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +120,11 @@ func midnight(t time.Time) time.Time {
|
||||||
return time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
|
return time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isToday(t time.Time) bool {
|
func isNotToday(f *FirstEntry) bool {
|
||||||
|
if f == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
t := f.time
|
||||||
t0 := midnight(t)
|
t0 := midnight(t)
|
||||||
return t0.Before(midnight(time.Now()))
|
return t0.Before(midnight(time.Now()))
|
||||||
}
|
}
|
||||||
|
@ -133,31 +133,41 @@ func isToday(t time.Time) bool {
|
||||||
// This function returns true if the plugin responds in a meaningful way to the users message.
|
// 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.
|
// Otherwise, the function returns false and the bot continues execution of other plugins.
|
||||||
func (p *FirstPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *FirstPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
// This bot does not reply to anything
|
log.Debug().
|
||||||
|
Interface("msg", message).
|
||||||
|
Msg("First is looking at a message")
|
||||||
|
|
||||||
if p.First == nil && p.allowed(message) {
|
if message.IsIM {
|
||||||
log.Debug().
|
log.Debug().Msg("Skipping IM")
|
||||||
Str("body", message.Body).
|
|
||||||
Msg("No previous first. Recording new first")
|
|
||||||
p.recordFirst(c, message)
|
|
||||||
return false
|
return false
|
||||||
} else if p.First != nil {
|
|
||||||
if isToday(p.First.time) && p.allowed(message) {
|
|
||||||
log.Debug().
|
|
||||||
Str("body", message.Body).
|
|
||||||
Time("t0", p.First.time).
|
|
||||||
Time("t1", time.Now()).
|
|
||||||
Msg("Recording first")
|
|
||||||
p.recordFirst(c, message)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r := strings.NewReplacer("'", "", "\"", "", ",", "", ".", "", ":", "",
|
first, err := getLastFirst(p.db, message.Channel)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Err(err).
|
||||||
|
Msg("Error getting last first")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Bool("first == nil", first == nil).Msg("Is first nil?")
|
||||||
|
log.Debug().Bool("first == nil || isNotToday()", isNotToday(first)).Msg("Is it today?")
|
||||||
|
log.Debug().Bool("p.allowed", p.allowed(message)).Msg("Allowed?")
|
||||||
|
|
||||||
|
if (first == nil || isNotToday(first)) && p.allowed(message) {
|
||||||
|
log.Debug().
|
||||||
|
Str("body", message.Body).
|
||||||
|
Interface("t0", first).
|
||||||
|
Time("t1", time.Now()).
|
||||||
|
Msg("Recording first")
|
||||||
|
p.recordFirst(c, message)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
r := strings.NewReplacer("’", "", "'", "", "\"", "", ",", "", ".", "", ":", "",
|
||||||
"?", "", "!", "")
|
"?", "", "!", "")
|
||||||
msg := strings.ToLower(message.Body)
|
m := strings.ToLower(message.Body)
|
||||||
if r.Replace(msg) == "whos on first" {
|
if r.Replace(m) == "whos on first" && first != nil {
|
||||||
p.announceFirst(c, message)
|
p.announceFirst(c, first)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +175,8 @@ func (p *FirstPlugin) message(c bot.Connector, kind bot.Kind, message msg.Messag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *FirstPlugin) allowed(message msg.Message) bool {
|
func (p *FirstPlugin) allowed(message msg.Message) bool {
|
||||||
for _, msg := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) {
|
for _, m := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) {
|
||||||
match, err := regexp.MatchString(msg, strings.ToLower(message.Body))
|
match, err := regexp.MatchString(m, strings.ToLower(message.Body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Bad regexp")
|
log.Error().Err(err).Msg("Bad regexp")
|
||||||
}
|
}
|
||||||
|
@ -201,41 +211,34 @@ func (p *FirstPlugin) allowed(message msg.Message) bool {
|
||||||
|
|
||||||
func (p *FirstPlugin) recordFirst(c bot.Connector, message msg.Message) {
|
func (p *FirstPlugin) recordFirst(c bot.Connector, message msg.Message) {
|
||||||
log.Info().
|
log.Info().
|
||||||
|
Str("channel", message.Channel).
|
||||||
Str("user", message.User.Name).
|
Str("user", message.User.Name).
|
||||||
Str("body", message.Body).
|
Str("body", message.Body).
|
||||||
Msg("Recording first")
|
Msg("Recording first")
|
||||||
p.First = &FirstEntry{
|
first := &FirstEntry{
|
||||||
day: midnight(time.Now()),
|
day: midnight(time.Now()),
|
||||||
time: message.Time,
|
time: message.Time,
|
||||||
body: message.Body,
|
channel: message.Channel,
|
||||||
nick: message.User.Name,
|
body: message.Body,
|
||||||
|
nick: message.User.Name,
|
||||||
}
|
}
|
||||||
log.Info().Msgf("recordFirst: %+v", p.First.day)
|
log.Info().Msgf("recordFirst: %+v", first.day)
|
||||||
err := p.First.save(p.db)
|
err := first.save(p.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Error saving first entry")
|
log.Error().Err(err).Msg("Error saving first entry")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.announceFirst(c, message)
|
p.announceFirst(c, first)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *FirstPlugin) announceFirst(c bot.Connector, message msg.Message) {
|
func (p *FirstPlugin) announceFirst(c bot.Connector, first *FirstEntry) {
|
||||||
ch := message.Channel
|
ch := first.channel
|
||||||
if p.First != nil {
|
p.Bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
|
||||||
p.Bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
|
first.nick, first.time.Format("15:04"), first.body))
|
||||||
p.First.nick, p.First.time.Format("15:04"), p.First.body))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
// Help responds to help requests. Every plugin must implement a help function.
|
||||||
func (p *FirstPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *FirstPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
p.Bot.Send(c, bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.")
|
p.Bot.Send(c, bot.Message, message.Channel, "You can ask 'who's on first?' to find out.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue