From 0e5f7eb2d5f692a47c79638cf5ebdf6c14c672cf Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Sun, 31 Jan 2021 18:08:25 -0500 Subject: [PATCH] newsbid: refactor --- bot/bot.go | 11 +++ bot/interfaces.go | 4 + bot/mock.go | 11 +-- plugins/newsbid/newsbid.go | 171 +++++++++++++++++++++---------------- 4 files changed, 118 insertions(+), 79 deletions(-) diff --git a/bot/bot.go b/bot/bot.go index bbc736d..8f48c18 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -245,6 +245,17 @@ func (b *bot) RegisterRegex(p Plugin, kind Kind, r *regexp.Regexp, resp Response b.callbacks[t][kind][r] = append(b.callbacks[t][kind][r], resp) } +// RegisterRegexCmd is a shortcut to filter non-command messages from a registration +func (b *bot) RegisterRegexCmd(p Plugin, kind Kind, r *regexp.Regexp, resp ResponseHandler) { + newResp := func(req Request) bool { + if !req.Msg.Command { + return false + } + return resp(req) + } + b.RegisterRegex(p, kind, r, newResp) +} + // Register a callback // This function should be considered deprecated. func (b *bot) Register(p Plugin, kind Kind, cb Callback) { diff --git a/bot/interfaces.go b/bot/interfaces.go index f47a8b8..c9951e4 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -94,6 +94,10 @@ type Bot interface { // Kind will be matched to the event for the callback RegisterRegex(Plugin, Kind, *regexp.Regexp, ResponseHandler) + // Register a plugin callback filtering non-commands out + // Kind will be matched to the event for the callback + RegisterRegexCmd(Plugin, Kind, *regexp.Regexp, ResponseHandler) + // Register a plugin callback // Kind will be matched to the event for the callback Register(Plugin, Kind, Callback) diff --git a/bot/mock.go b/bot/mock.go index 33143ed..49d2636 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -52,11 +52,12 @@ func (mb *MockBot) Send(c Connector, kind Kind, args ...interface{}) (string, er } return "ERR", fmt.Errorf("Mesasge type unhandled") } -func (mb *MockBot) AddPlugin(f Plugin) {} -func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {} -func (mb *MockBot) RegisterRegex(p Plugin, kind Kind, r *regexp.Regexp, h ResponseHandler) {} -func (mb *MockBot) RegisterWeb(_, _ string) {} -func (mb *MockBot) GetWebNavigation() []EndPoint { return nil } +func (mb *MockBot) AddPlugin(f Plugin) {} +func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {} +func (mb *MockBot) RegisterRegex(p Plugin, kind Kind, r *regexp.Regexp, h ResponseHandler) {} +func (mb *MockBot) RegisterRegexCmd(p Plugin, kind Kind, r *regexp.Regexp, h ResponseHandler) {} +func (mb *MockBot) RegisterWeb(_, _ string) {} +func (mb *MockBot) GetWebNavigation() []EndPoint { return nil } func (mb *MockBot) Receive(c Connector, kind Kind, msg msg.Message, args ...interface{}) bool { return false } diff --git a/plugins/newsbid/newsbid.go b/plugins/newsbid/newsbid.go index d5191fb..10eba4e 100644 --- a/plugins/newsbid/newsbid.go +++ b/plugins/newsbid/newsbid.go @@ -2,13 +2,14 @@ package newsbid import ( "fmt" + "regexp" "sort" "strconv" "strings" "github.com/jmoiron/sqlx" + "github.com/rs/zerolog/log" "github.com/velour/catbase/bot" - "github.com/velour/catbase/bot/msg" "github.com/velour/catbase/plugins/newsbid/webshit" ) @@ -30,90 +31,111 @@ func New(b bot.Bot) *NewsBid { db: b.DB(), ws: ws, } - p.bot.Register(p, bot.Message, p.message) + + p.bot.RegisterRegexCmd(p, bot.Message, balanceRegex, p.balanceCmd) + p.bot.RegisterRegexCmd(p, bot.Message, bidsRegex, p.bidsCmd) + p.bot.RegisterRegexCmd(p, bot.Message, scoresRegex, p.scoresCmd) + p.bot.RegisterRegexCmd(p, bot.Message, bidRegex, p.bidCmd) + p.bot.RegisterRegexCmd(p, bot.Message, checkRegex, p.checkCmd) + return p } -func (p *NewsBid) message(conn bot.Connector, k bot.Kind, message msg.Message, args ...interface{}) bool { - body := strings.ToLower(message.Body) - ch := message.Channel - if message.Command && body == "balance" { - bal := p.ws.GetBalance(message.User.Name) - p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("%s, your current balance is %d.", - message.User.Name, bal)) - return true - } - if message.Command && body == "bids" { - bids, err := p.ws.GetAllBids() - if err != nil { - p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err)) - return true - } - if len(bids) == 0 { - p.bot.Send(conn, bot.Message, ch, "No bids to report.") - return true - } - sort.Slice(bids, func(i, j int) bool { - if bids[i].User == bids[j].User { - return bids[i].Bid > bids[j].Bid - } - return bids[i].User < bids[j].User - }) - out := "Bids:\n" - for _, b := range bids { - hnURL := fmt.Sprintf("https://news.ycombinator.com/item?id=%d", b.HNID) - out += fmt.Sprintf("• %s bid %s <%s|%s> (<%s|Comments>)\n", b.User, b.BidStr, b.URL, b.Title, hnURL) - } - p.bot.Send(conn, bot.Message, ch, out) - return true - } - if message.Command && body == "scores" { - bals, err := p.ws.GetAllBalances() - if err != nil { - p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err)) - return true - } - if len(bals) == 0 { - p.bot.Send(conn, bot.Message, ch, "No balances to report.") - return true - } - out := "NGate balances:\n" - sort.Sort(bals) - for _, b := range bals { - out += fmt.Sprintf("%s has a total score of %d with %d left to bid this session\n", b.User, b.Score, b.Balance) - } - p.bot.Send(conn, bot.Message, ch, out) - return true +var balanceRegex = regexp.MustCompile(`(?i)^balance$`) +var bidsRegex = regexp.MustCompile(`(?i)^bids$`) +var scoresRegex = regexp.MustCompile(`(?i)^scores$`) +var bidRegex = regexp.MustCompile(`(?i)^bid (?P\S+) (?P)\S+$`) +var checkRegex = regexp.MustCompile(`(?i)^check ngate$`) +func (p *NewsBid) balanceCmd(r bot.Request) bool { + if !r.Msg.Command { + return false } - if message.Command && strings.HasPrefix(body, "bid") { - parts := strings.Fields(body) - if len(parts) != 3 { - p.bot.Send(conn, bot.Message, ch, "You must bid with an amount and a URL.") - return true - } - amount, _ := strconv.Atoi(parts[1]) - url := parts[2] - if bid, err := p.ws.Bid(message.User.Name, amount, parts[1], url); err != nil { - p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error placing bid: %s", err)) - } else { - p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Your bid has been placed on %s", bid.Title)) - } - return true - } - if message.Command && body == "check ngate" { - p.check(conn, ch) - return true - } - return false + + bal := p.ws.GetBalance(r.Msg.User.Name) + p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("%s, your current balance is %d.", + r.Msg.User.Name, bal)) + return true } -func (p *NewsBid) check(conn bot.Connector, ch string) { +func (p *NewsBid) bidsCmd(r bot.Request) bool { + ch := r.Msg.Channel + bids, err := p.ws.GetAllBids() + if err != nil { + p.bot.Send(r.Conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err)) + return true + } + if len(bids) == 0 { + p.bot.Send(r.Conn, bot.Message, ch, "No bids to report.") + return true + } + sort.Slice(bids, func(i, j int) bool { + if bids[i].User == bids[j].User { + return bids[i].Bid > bids[j].Bid + } + return bids[i].User < bids[j].User + }) + out := "Bids:\n" + for _, b := range bids { + hnURL := fmt.Sprintf("https://news.ycombinator.com/item?id=%d", b.HNID) + out += fmt.Sprintf("• %s bid %s <%s|%s> (<%s|Comments>)\n", b.User, b.BidStr, b.URL, b.Title, hnURL) + } + p.bot.Send(r.Conn, bot.Message, ch, out) + return true +} + +func (p *NewsBid) scoresCmd(r bot.Request) bool { + + ch := r.Msg.Channel + bals, err := p.ws.GetAllBalances() + if err != nil { + p.bot.Send(r.Conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err)) + return true + } + if len(bals) == 0 { + p.bot.Send(r.Conn, bot.Message, ch, "No balances to report.") + return true + } + out := "NGate balances:\n" + sort.Sort(bals) + for _, b := range bals { + out += fmt.Sprintf("%s has a total score of %d with %d left to bid this session\n", b.User, b.Score, b.Balance) + } + p.bot.Send(r.Conn, bot.Message, ch, out) + return true +} + +func (p *NewsBid) bidCmd(r bot.Request) bool { + body := strings.ToLower(r.Msg.Body) + ch := r.Msg.Channel + conn := r.Conn + + log.Debug().Interface("request", r).Msg("bid request") + + parts := strings.Fields(body) + if len(parts) != 3 { + p.bot.Send(conn, bot.Message, ch, "You must bid with an amount and a URL.") + return true + } + + amount, _ := strconv.Atoi(parts[1]) + url := parts[2] + if bid, err := p.ws.Bid(r.Msg.User.Name, amount, parts[1], url); err != nil { + p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error placing bid: %s", err)) + } else { + p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Your bid has been placed on %s", bid.Title)) + } + return true +} + +func (p *NewsBid) checkCmd(r bot.Request) bool { + ch := r.Msg.Channel + conn := r.Conn last := p.bot.Config().GetInt64("newsbid.lastprocessed", 0) wr, pubTime, err := p.ws.Check(last) if err != nil { p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error checking ngate: %s", err)) - return + return true } p.bot.Config().Set("newsbid.lastprocessed", strconv.FormatInt(pubTime, 10)) @@ -147,4 +169,5 @@ func (p *NewsBid) check(conn bot.Connector, ch string) { } p.bot.Send(conn, bot.Message, ch, msg) } + return true }