Compare commits

..

2 Commits

Author SHA1 Message Date
Chris Sexton 850f5248ef last: fix schema 2021-04-28 17:15:22 -04:00
Chris Sexton c5d468c723 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
2021-04-28 16:52:07 -04:00
7 changed files with 120 additions and 27 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

@ -43,11 +43,12 @@ func (p *LastPlugin) migrate() error {
return err return err
} }
_, err = tx.Exec(`create table if not exists last ( _, err = tx.Exec(`create table if not exists last (
day integer primary key, day integer,
ts int not null,
channel string not null, channel string not null,
ts int not null,
who string not null, who string not null,
message string not null message string not null,
constraint last_key primary key (day, channel) on conflict replace
)`) )`)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
@ -58,18 +59,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)
} }
@ -114,11 +121,8 @@ func (p *LastPlugin) recordLast(r bot.Request) bool {
} }
_, err := p.db.Exec( _, err := p.db.Exec(
`insert into last values (?, ?, ?, ?, ?) `insert into last values (?, ?, ?, ?, ?)`,
on conflict(day) do update set day.Unix(), ch, time.Now().Unix(), who, r.Msg.Body)
ts=excluded.ts, channel=excluded.channel, who=excluded.who, message=excluded.message
where day=excluded.day`,
day.Unix(), time.Now().Unix(), ch, who, r.Msg.Body)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("Could not record last.") log.Error().Err(err).Msgf("Could not record last.")
} }
@ -133,11 +137,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 +151,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)
} }