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
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

View File

@ -232,3 +232,26 @@ func (d *Discord) Emojy(name string) string {
func (d *Discord) URLFormat(title, url string) string {
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
}
// 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
import (
// "sync/atomic"
"context"
"encoding/json"
"errors"
"fmt"
@ -15,9 +17,6 @@ import (
"regexp"
"strconv"
"strings"
// "sync/atomic"
"context"
"time"
"github.com/rs/zerolog/log"
@ -735,6 +734,28 @@ func (s *Slack) Profile(string) (user.User, error) {
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 {
e := s.config.GetMap("slack.emojy", map[string]string{})
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
}
// 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 {
if 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 {
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
}
_, err = tx.Exec(`create table if not exists last (
day integer primary key,
ts int not null,
day integer,
channel string not null,
ts int 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 {
tx.Rollback()
@ -58,18 +59,24 @@ func (p *LastPlugin) migrate() error {
func (p *LastPlugin) register() {
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,
Regex: regexp.MustCompile(`(?i)^who killed the channel\??$`),
HelpText: "Find out who had last yesterday",
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)
}
@ -114,11 +121,8 @@ func (p *LastPlugin) recordLast(r bot.Request) bool {
}
_, err := p.db.Exec(
`insert into last values (?, ?, ?, ?, ?)
on conflict(day) do update set
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)
`insert into last values (?, ?, ?, ?, ?)`,
day.Unix(), ch, time.Now().Unix(), who, r.Msg.Body)
if err != nil {
log.Error().Err(err).Msgf("Could not record last.")
}
@ -133,11 +137,12 @@ type last struct {
Message string
}
func (p *LastPlugin) yesterdaysLast() (last, error) {
func (p *LastPlugin) yesterdaysLast(ch string) (last, error) {
l := last{}
midnight := first.Midnight(time.Now())
q := `select * from last where day < ? order by day limit 1`
err := p.db.Get(&l, q, midnight)
q := `select * from last where channel = ? and day < ? and day >= ? order by day limit 1`
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 {
return l, err
}
@ -146,27 +151,33 @@ func (p *LastPlugin) yesterdaysLast() (last, error) {
func (p *LastPlugin) reportLast(ch string) func() {
return func() {
p.sayLast(p.b.DefaultConnector(), ch)
p.sayLast(p.b.DefaultConnector(), ch, ch)
time.AfterFunc(24*time.Hour, p.reportLast(ch))
}
}
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
}
func (p *LastPlugin) sayLast(c bot.Connector, ch string) {
l, err := p.yesterdaysLast()
func (p *LastPlugin) whoKilledChannel(r bot.Request) bool {
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 {
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
}
if l.Day == 0 {
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)
p.b.Send(c, bot.Message, ch, msg)
p.b.Send(c, bot.Message, chTo, msg)
}