mirror of https://github.com/velour/catbase.git
sms: send and receive
This commit is contained in:
parent
3db779567a
commit
e78b22e93e
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/velour/catbase/bot"
|
"github.com/velour/catbase/bot"
|
||||||
"github.com/velour/catbase/bot/msg"
|
"github.com/velour/catbase/bot/msg"
|
||||||
"github.com/velour/catbase/config"
|
"github.com/velour/catbase/config"
|
||||||
|
"github.com/velour/catbase/plugins/sms"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -367,6 +368,10 @@ func reminderer(c bot.Connector, p *ReminderPlugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.bot.Send(c, bot.Message, reminder.channel, message)
|
p.bot.Send(c, bot.Message, reminder.channel, message)
|
||||||
|
smsPlugin := sms.New(p.bot)
|
||||||
|
if err := smsPlugin.Send(reminder.who, message); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("could not send reminder")
|
||||||
|
}
|
||||||
|
|
||||||
if err := p.deleteReminder(reminder.id); err != nil {
|
if err := p.deleteReminder(reminder.id); err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
|
|
|
@ -19,8 +19,6 @@ var plugin *SMSPlugin
|
||||||
type SMSPlugin struct {
|
type SMSPlugin struct {
|
||||||
b bot.Bot
|
b bot.Bot
|
||||||
c *config.Config
|
c *config.Config
|
||||||
|
|
||||||
knownUsers map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(b bot.Bot) *SMSPlugin {
|
func New(b bot.Bot) *SMSPlugin {
|
||||||
|
@ -28,10 +26,11 @@ func New(b bot.Bot) *SMSPlugin {
|
||||||
return plugin
|
return plugin
|
||||||
}
|
}
|
||||||
plugin = &SMSPlugin{
|
plugin = &SMSPlugin{
|
||||||
b: b,
|
b: b,
|
||||||
c: b.Config(),
|
c: b.Config(),
|
||||||
knownUsers: make(map[string]string),
|
|
||||||
}
|
}
|
||||||
|
plugin.setup()
|
||||||
|
plugin.registerWeb()
|
||||||
b.Register(plugin, bot.Message, plugin.message)
|
b.Register(plugin, bot.Message, plugin.message)
|
||||||
b.Register(plugin, bot.Help, plugin.help)
|
b.Register(plugin, bot.Help, plugin.help)
|
||||||
return plugin
|
return plugin
|
||||||
|
@ -47,31 +46,48 @@ func (p *SMSPlugin) checkNumber(num string) (string, error) {
|
||||||
return num, nil
|
return num, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var regRegex = regexp.MustCompile(`^my sms number is (\d+)$`)
|
var regRegex = regexp.MustCompile(`(?i)my sms number is (\d+)`)
|
||||||
|
var sendRegex = regexp.MustCompile(`(?i)send sms to\s(?P<name>\S+)\s(?P<body>.+)`)
|
||||||
|
|
||||||
// Send will send a text to a registered user, who
|
// Send will send a text to a registered user, who
|
||||||
func (p *SMSPlugin) Send(who, message string) error {
|
func (p *SMSPlugin) Send(who, message string) error {
|
||||||
num, ok := p.knownUsers[who]
|
num, err := p.get(who)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return fmt.Errorf("unknown user: %s", who)
|
return fmt.Errorf("unknown user: %s: %w", who, err)
|
||||||
}
|
}
|
||||||
sid := p.c.Get("TWILIOSID", "")
|
sid := p.c.Get("TWILIOSID", "")
|
||||||
token := p.c.Get("TWILIOTOKEN", "")
|
token := p.c.Get("TWILIOTOKEN", "")
|
||||||
myNum := p.c.Get("TWILIONUMBER", "")
|
myNum := p.c.Get("TWILIONUMBER", "")
|
||||||
client := twilio.NewClient(sid, token, nil)
|
client := twilio.NewClient(sid, token, nil)
|
||||||
|
|
||||||
_, err := client.Messages.SendMessage(myNum, num, message, nil)
|
_, err = client.Messages.SendMessage(myNum, num, message, nil)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SMSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *SMSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
ch := message.Channel
|
ch, chName := message.Channel, message.ChannelName
|
||||||
lowerBody := strings.ToLower(strings.TrimSpace(message.Body))
|
body := strings.TrimSpace(message.Body)
|
||||||
|
who := message.User.Name
|
||||||
|
|
||||||
log.Debug().Msgf("lowerBody: %s, match: %v", lowerBody, regRegex.MatchString(lowerBody))
|
log.Debug().Bytes("body", []byte(body)).Msgf("body: '%s', match: %v, %#v", body, sendRegex.MatchString(body), sendRegex.FindStringSubmatch(body))
|
||||||
|
|
||||||
if lowerBody == "send me a message" {
|
if strings.ToLower(body) == "delete my sms" {
|
||||||
err := p.Send(message.User.Name, "Hey, here's a message.")
|
if err := p.delete(who); err != nil {
|
||||||
|
p.b.Send(c, bot.Message, ch, "Something went wrong.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.b.Send(c, bot.Message, ch, "Okay.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if sendRegex.MatchString(body) {
|
||||||
|
subs := sendRegex.FindStringSubmatch(body)
|
||||||
|
if len(subs) != 3 {
|
||||||
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message. Your request makes no sense."))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
user, body := subs[1], fmt.Sprintf("#%s: %s", chName, subs[2])
|
||||||
|
err := p.Send(user, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
||||||
return true
|
return true
|
||||||
|
@ -80,10 +96,11 @@ func (p *SMSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message,
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if regRegex.MatchString(lowerBody) {
|
if regRegex.MatchString(body) {
|
||||||
subs := regRegex.FindStringSubmatch(lowerBody)
|
subs := regRegex.FindStringSubmatch(body)
|
||||||
if subs == nil || len(subs) != 2 {
|
if subs == nil || len(subs) != 2 {
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("if you're trying to register a number, give me a message of the format: `%s`", regRegex))
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("if you're trying to register a number, give me a "+
|
||||||
|
"message of the format: `%s`", regRegex))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,11 +110,20 @@ func (p *SMSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message,
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
me := p.b.WhoAmI()
|
me := p.b.WhoAmI()
|
||||||
m := fmt.Sprintf("Hello from %s", me)
|
m := fmt.Sprintf("Hello from %s. You are registered for reminders and you can chat with the channel "+
|
||||||
p.knownUsers[message.User.Name] = num
|
"by talking to this number", me)
|
||||||
err = p.Send(message.User.Name, m)
|
err = p.add(who, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
delete(p.knownUsers, message.User.Name)
|
log.Error().Err(err).Msgf("error adding user")
|
||||||
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
err = p.Send(who, m)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("error sending to user")
|
||||||
|
if err := p.delete(who); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("error deleting user")
|
||||||
|
}
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -114,9 +140,83 @@ func (p *SMSPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, ar
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SMSPlugin) registerWeb() {
|
func (p *SMSPlugin) registerWeb() {
|
||||||
http.HandleFunc("/sms/recieve", p.receive)
|
http.HandleFunc("/sms/new", p.receive)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SMSPlugin) receive(w http.ResponseWriter, r *http.Request) {
|
func (p *SMSPlugin) receive(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
w.WriteHeader(405)
|
||||||
|
fmt.Fprintf(w, "Incorrect HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("could not parse incoming SMS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body := r.PostFormValue("Body")
|
||||||
|
number := strings.TrimPrefix(r.PostFormValue("From"), "+1")
|
||||||
|
from, err := p.getByNumber(number)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug().Err(err).Msgf("could not find user")
|
||||||
|
from = number
|
||||||
|
}
|
||||||
|
|
||||||
|
m := fmt.Sprintf("SMS From %s: %s", from, body)
|
||||||
|
chs := p.c.GetArray("channels", []string{})
|
||||||
|
|
||||||
|
log.Debug().Msgf("%s to %v", m, chs)
|
||||||
|
|
||||||
|
for _, ch := range chs {
|
||||||
|
p.b.Send(p.b.DefaultConnector(), bot.Message, ch, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) add(who, num string) error {
|
||||||
|
tx, err := p.b.DB().Beginx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.Exec(`insert or replace into sms (who, num) values (?, ?)`, who, num)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) delete(who string) error {
|
||||||
|
tx, err := p.b.DB().Beginx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.Exec(`delete from sms where who=?`, who)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) get(who string) (string, error) {
|
||||||
|
num := ""
|
||||||
|
err := p.b.DB().Get(&num, `select num from sms where who=?`, who)
|
||||||
|
return num, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) getByNumber(num string) (string, error) {
|
||||||
|
who := ""
|
||||||
|
err := p.b.DB().Get(&who, `select who from sms where num=?`, num)
|
||||||
|
return who, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) setup() {
|
||||||
|
_, err := p.b.DB().Exec(`create table if not exists sms (
|
||||||
|
who string primary key,
|
||||||
|
num string
|
||||||
|
)`)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msgf("could not create sms table")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue