diff --git a/bot/msg/message.go b/bot/msg/message.go index 78a40f0..9cb0731 100644 --- a/bot/msg/message.go +++ b/bot/msg/message.go @@ -14,6 +14,7 @@ type Messages []Message type Message struct { User *user.User Channel, Body string + IsIM bool Raw string Command bool Action bool diff --git a/connectors/slackapp/slackApp.go b/connectors/slackapp/slackApp.go index d45708a..f07a6fa 100644 --- a/connectors/slackapp/slackApp.go +++ b/connectors/slackapp/slackApp.go @@ -87,6 +87,11 @@ func (s *SlackApp) Serve() error { buf := new(bytes.Buffer) buf.ReadFrom(r.Body) 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})) if e != nil { log.Error().Err(e) @@ -148,6 +153,7 @@ func (s *SlackApp) msgReceivd(msg *slackevents.MessageEvent) { } log.Debug(). + Interface("event", msg). Str("type", msg.SubType). Msg("accepting a message") @@ -389,6 +395,7 @@ func (s *SlackApp) buildMessage(m *slackevents.MessageEvent) msg.Message { Body: text, Raw: m.Text, Channel: m.Channel, + IsIM: m.ChannelType == "im", Command: isCmd, Action: isAction, Time: tstamp, diff --git a/plugins/first/first.go b/plugins/first/first.go index 7e26b6c..d078926 100644 --- a/plugins/first/first.go +++ b/plugins/first/first.go @@ -18,26 +18,27 @@ import ( // 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 - db *sqlx.DB + Bot bot.Bot + db *sqlx.DB } type FirstEntry struct { - id int64 - day time.Time - time time.Time - body string - nick string - saved bool + id int64 + day time.Time + time time.Time + channel string + body string + nick string + saved bool } // Insert or update the first entry func (fe *FirstEntry) save(db *sqlx.DB) error { - if _, err := db.Exec(`insert into first (day, time, body, nick) - values (?, ?, ?, ?)`, + if _, err := db.Exec(`insert into first (day, time, channel, body, nick) + values (?, ?, ?, ?, ?)`, fe.day.Unix(), fe.time.Unix(), + fe.channel, fe.body, fe.nick, ); err != nil { @@ -52,6 +53,7 @@ func New(b bot.Bot) *FirstPlugin { id integer primary key, day integer, time integer, + channel string, body string, nick string );`) @@ -64,24 +66,16 @@ func New(b bot.Bot) *FirstPlugin { log.Info().Msgf("First plugin initialized with day: %s", midnight(time.Now())) - first, err := getLastFirst(b.DB()) - if err != nil { - log.Fatal(). - Err(err). - Msg("Could not initialize first plugin") - } - fp := &FirstPlugin{ - Bot: b, - db: b.DB(), - First: first, + Bot: b, + db: b.DB(), } b.Register(fp, bot.Message, fp.message) b.Register(fp, bot.Help, fp.help) return fp } -func getLastFirst(db *sqlx.DB) (*FirstEntry, error) { +func getLastFirst(db *sqlx.DB, channel string) (*FirstEntry, error) { // Get last first entry var id sql.NullInt64 var day sql.NullInt64 @@ -91,8 +85,9 @@ func getLastFirst(db *sqlx.DB) (*FirstEntry, error) { err := db.QueryRow(`select id, max(day), time, body, nick from first + where channel = ? limit 1; - `).Scan( + `, channel).Scan( &id, &day, &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", id, day, timeEntered, body, nick) 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, + id: id.Int64, + day: time.Unix(day.Int64, 0), + time: time.Unix(timeEntered.Int64, 0), + channel: channel, + body: body.String, + nick: nick.String, + saved: true, }, nil } @@ -124,7 +120,11 @@ func midnight(t time.Time) time.Time { 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) 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. // 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 { - // 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) { - log.Debug(). - Str("body", message.Body). - Msg("No previous first. Recording new first") - p.recordFirst(c, message) + if message.IsIM { + log.Debug().Msg("Skipping IM") 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) - if r.Replace(msg) == "whos on first" { - p.announceFirst(c, message) + m := strings.ToLower(message.Body) + if r.Replace(m) == "whos on first" && first != nil { + p.announceFirst(c, first) 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 { - for _, msg := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) { - match, err := regexp.MatchString(msg, strings.ToLower(message.Body)) + for _, m := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) { + match, err := regexp.MatchString(m, strings.ToLower(message.Body)) if err != nil { 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) { log.Info(). + Str("channel", message.Channel). Str("user", message.User.Name). Str("body", message.Body). Msg("Recording first") - p.First = &FirstEntry{ - day: midnight(time.Now()), - time: message.Time, - body: message.Body, - nick: message.User.Name, + first := &FirstEntry{ + day: midnight(time.Now()), + time: message.Time, + channel: message.Channel, + body: message.Body, + nick: message.User.Name, } - log.Info().Msgf("recordFirst: %+v", p.First.day) - err := p.First.save(p.db) + log.Info().Msgf("recordFirst: %+v", first.day) + err := first.save(p.db) if err != nil { log.Error().Err(err).Msg("Error saving first entry") return } - p.announceFirst(c, message) + p.announceFirst(c, first) } -func (p *FirstPlugin) announceFirst(c bot.Connector, message msg.Message) { - ch := message.Channel - if p.First != nil { - p.Bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"", - 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 +func (p *FirstPlugin) announceFirst(c bot.Connector, first *FirstEntry) { + ch := first.channel + 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)) } // 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 { - 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 }