last: add multichannel support

This
* ensures the last is between yesterday and yesterday
* adds a channel check to the query
* adds a command to check a specific channel
This commit is contained in:
Chris Sexton 2021-04-28 16:48:02 -04:00 committed by Chris Sexton
parent 802911203f
commit c5d468c723
7 changed files with 114 additions and 19 deletions

View File

@ -189,6 +189,12 @@ type Connector interface {
// Translate emojy to/from services // Translate emojy to/from services
Emojy(string) string Emojy(string) string
// GetChannelName returns the human-friendly name for an ID (if possible)
GetChannelName(id string) string
// GetChannelName returns the channel ID for a human-friendly name (if possible)
GetChannelID(id string) string
} }
// Plugin interface used for compatibility with the Plugin interface // Plugin interface used for compatibility with the Plugin interface

View File

@ -232,3 +232,26 @@ func (d *Discord) Emojy(name string) string {
func (d *Discord) URLFormat(title, url string) string { func (d *Discord) URLFormat(title, url string) string {
return fmt.Sprintf("%s (%s)", title, url) return fmt.Sprintf("%s (%s)", title, url)
} }
// GetChannelName returns the channel ID for a human-friendly name (if possible)
func (d *Discord) GetChannelID(name string) string {
chs, err := d.client.UserChannels()
if err != nil {
return name
}
for _, ch := range chs {
if ch.Name == name {
return ch.ID
}
}
return name
}
// GetChannelName returns the human-friendly name for an ID (if possible)
func (d *Discord) GetChannelName(id string) string {
ch, err := d.client.Channel(id)
if err != nil {
return id
}
return ch.Name
}

View File

@ -326,3 +326,13 @@ func (i Irc) Emojy(name string) string {
} }
return name return name
} }
// GetChannelName returns the channel ID for a human-friendly name (if possible)
func (i Irc) GetChannelID(name string) string {
return name
}
// GetChannelName returns the human-friendly name for an ID (if possible)
func (i Irc) GetChannelName(id string) string {
return id
}

View File

@ -4,6 +4,8 @@
package slack package slack
import ( import (
// "sync/atomic"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -15,9 +17,6 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
// "sync/atomic"
"context"
"time" "time"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -735,6 +734,28 @@ func (s *Slack) Profile(string) (user.User, error) {
return user.User{}, fmt.Errorf("unimplemented") return user.User{}, fmt.Errorf("unimplemented")
} }
// GetChannelName returns the channel ID for a human-friendly name (if possible)
func (s *Slack) GetChannelID(name string) string {
chs := s.getAllChannels()
for _, ch := range chs {
if ch.Name == name {
return ch.ID
}
}
return name
}
// GetChannelName returns the human-friendly name for an ID (if possible)
func (s *Slack) GetChannelName(id string) string {
chs := s.getAllChannels()
for _, ch := range chs {
if ch.ID == id {
return ch.Name
}
}
return id
}
func (s *Slack) Emojy(name string) string { func (s *Slack) Emojy(name string) string {
e := s.config.GetMap("slack.emojy", map[string]string{}) e := s.config.GetMap("slack.emojy", map[string]string{})
if emojy, ok := e[name]; ok { if emojy, ok := e[name]; ok {

View File

@ -499,6 +499,26 @@ func (s *SlackApp) getChannel(id string) (*slack.Channel, error) {
return s.channels[id], nil return s.channels[id], nil
} }
// GetChannelName returns the channel ID for a human-friendly name (if possible)
func (s *SlackApp) GetChannelID(name string) string {
for _, ch := range s.channels {
if ch.Name == name {
return ch.ID
}
}
return name
}
// GetChannelName returns the human-friendly name for an ID (if possible)
func (s *SlackApp) GetChannelName(id string) string {
ch, err := s.getChannel(id)
if err != nil {
log.Error().Err(err).Msgf("Could not get channel name for %s", id)
return id
}
return ch.Name
}
func stringForUser(user *slack.User) string { func stringForUser(user *slack.User) string {
if user.Profile.DisplayName != "" { if user.Profile.DisplayName != "" {
return user.Profile.DisplayName return user.Profile.DisplayName

View File

@ -121,3 +121,5 @@ func (p *CliPlugin) Emojy(name string) string { return name }
func (p *CliPlugin) URLFormat(title, url string) string { func (p *CliPlugin) URLFormat(title, url string) string {
return fmt.Sprintf("%s (%s)", title, url) return fmt.Sprintf("%s (%s)", title, url)
} }
func (p *CliPlugin) GetChannelName(id string) string { return id }
func (p *CliPlugin) GetChannelID(name string) string { return name }

View File

@ -58,18 +58,24 @@ func (p *LastPlugin) migrate() error {
func (p *LastPlugin) register() { func (p *LastPlugin) register() {
p.handlers = bot.HandlerTable{ p.handlers = bot.HandlerTable{
{
Kind: bot.Message, IsCmd: false,
Regex: regexp.MustCompile(`.*`),
HelpText: "Last does secret stuff you don't need to know about.",
Handler: p.recordLast,
},
{ {
Kind: bot.Message, IsCmd: true, Kind: bot.Message, IsCmd: true,
Regex: regexp.MustCompile(`(?i)^who killed the channel\??$`), Regex: regexp.MustCompile(`(?i)^who killed the channel\??$`),
HelpText: "Find out who had last yesterday", HelpText: "Find out who had last yesterday",
Handler: p.whoKilled, Handler: p.whoKilled,
}, },
{
Kind: bot.Message, IsCmd: true,
Regex: regexp.MustCompile(`(?i)^who killed #?(?P<channel>\S+)\??$`),
HelpText: "Find out who had last yesterday in a channel",
Handler: p.whoKilledChannel,
},
{
Kind: bot.Message, IsCmd: false,
Regex: regexp.MustCompile(`.*`),
HelpText: "Last does secret stuff you don't need to know about.",
Handler: p.recordLast,
},
} }
p.b.RegisterTable(p, p.handlers) p.b.RegisterTable(p, p.handlers)
} }
@ -133,11 +139,12 @@ type last struct {
Message string Message string
} }
func (p *LastPlugin) yesterdaysLast() (last, error) { func (p *LastPlugin) yesterdaysLast(ch string) (last, error) {
l := last{} l := last{}
midnight := first.Midnight(time.Now()) midnight := first.Midnight(time.Now())
q := `select * from last where day < ? order by day limit 1` q := `select * from last where channel = ? and day < ? and day >= ? order by day limit 1`
err := p.db.Get(&l, q, midnight) log.Debug().Str("q", q).Msgf("yesterdaysLast: %d to %d", midnight.Unix(), midnight.Add(-24*time.Hour).Unix())
err := p.db.Get(&l, q, ch, midnight.Unix(), midnight.Add(-24*time.Hour).Unix())
if err != nil { if err != nil {
return l, err return l, err
} }
@ -146,27 +153,33 @@ func (p *LastPlugin) yesterdaysLast() (last, error) {
func (p *LastPlugin) reportLast(ch string) func() { func (p *LastPlugin) reportLast(ch string) func() {
return func() { return func() {
p.sayLast(p.b.DefaultConnector(), ch) p.sayLast(p.b.DefaultConnector(), ch, ch)
time.AfterFunc(24*time.Hour, p.reportLast(ch)) time.AfterFunc(24*time.Hour, p.reportLast(ch))
} }
} }
func (p *LastPlugin) whoKilled(r bot.Request) bool { func (p *LastPlugin) whoKilled(r bot.Request) bool {
p.sayLast(r.Conn, r.Msg.Channel) p.sayLast(r.Conn, r.Msg.Channel, r.Msg.Channel)
return true return true
} }
func (p *LastPlugin) sayLast(c bot.Connector, ch string) { func (p *LastPlugin) whoKilledChannel(r bot.Request) bool {
l, err := p.yesterdaysLast() ch := r.Values["channel"]
p.sayLast(r.Conn, r.Conn.GetChannelID(ch), r.Msg.Channel)
return true
}
func (p *LastPlugin) sayLast(c bot.Connector, chFrom, chTo string) {
l, err := p.yesterdaysLast(chFrom)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("Couldn't find last") log.Error().Err(err).Msgf("Couldn't find last")
p.b.Send(c, bot.Message, ch, "I couldn't find a last.") p.b.Send(c, bot.Message, chTo, "I couldn't find a last.")
return return
} }
if l.Day == 0 { if l.Day == 0 {
log.Error().Interface("l", l).Msgf("Couldn't find last") log.Error().Interface("l", l).Msgf("Couldn't find last")
p.b.Send(c, bot.Message, ch, "I couldn't find a last.") p.b.Send(c, bot.Message, chTo, "I couldn't find a last.")
} }
msg := fmt.Sprintf(`%s killed the channel last night by saying "%s"`, l.Who, l.Message) msg := fmt.Sprintf(`%s killed the channel last night by saying "%s"`, l.Who, l.Message)
p.b.Send(c, bot.Message, ch, msg) p.b.Send(c, bot.Message, chTo, msg)
} }