mirror of https://github.com/velour/catbase.git
stock checker
This commit is contained in:
parent
50dfc71269
commit
d372541735
2
main.go
2
main.go
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/velour/catbase/plugins/rpgORdie"
|
"github.com/velour/catbase/plugins/rpgORdie"
|
||||||
"github.com/velour/catbase/plugins/rss"
|
"github.com/velour/catbase/plugins/rss"
|
||||||
"github.com/velour/catbase/plugins/sisyphus"
|
"github.com/velour/catbase/plugins/sisyphus"
|
||||||
|
"github.com/velour/catbase/plugins/stock"
|
||||||
"github.com/velour/catbase/plugins/talker"
|
"github.com/velour/catbase/plugins/talker"
|
||||||
"github.com/velour/catbase/plugins/tell"
|
"github.com/velour/catbase/plugins/tell"
|
||||||
"github.com/velour/catbase/plugins/tldr"
|
"github.com/velour/catbase/plugins/tldr"
|
||||||
|
@ -122,6 +123,7 @@ func main() {
|
||||||
b.AddPlugin(couldashouldawoulda.New(b))
|
b.AddPlugin(couldashouldawoulda.New(b))
|
||||||
b.AddPlugin(nerdepedia.New(b))
|
b.AddPlugin(nerdepedia.New(b))
|
||||||
b.AddPlugin(tldr.New(b))
|
b.AddPlugin(tldr.New(b))
|
||||||
|
b.AddPlugin(stock.New(b))
|
||||||
b.AddPlugin(cli.New(b))
|
b.AddPlugin(cli.New(b))
|
||||||
// catches anything left, will always return true
|
// catches anything left, will always return true
|
||||||
b.AddPlugin(fact.New(b))
|
b.AddPlugin(fact.New(b))
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package stock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"github.com/velour/catbase/bot"
|
||||||
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StockPlugin struct {
|
||||||
|
bot bot.Bot
|
||||||
|
apiKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(b bot.Bot) *StockPlugin {
|
||||||
|
s := &StockPlugin{
|
||||||
|
bot: b,
|
||||||
|
apiKey: b.Config().GetString("Stock.API_KEY", "0E1DP61SJ7GF81IE"),
|
||||||
|
}
|
||||||
|
b.Register(s, bot.Message, s.message)
|
||||||
|
b.Register(s, bot.Help, s.help)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type GlobalQuote struct {
|
||||||
|
Info StockInfo `json:"GlobalQuote"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StockInfo struct {
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Open string `json:"open"`
|
||||||
|
High string `json:"high"`
|
||||||
|
Low string `json:"low"`
|
||||||
|
Price string `json:"price"`
|
||||||
|
Volume string `json:"volume"`
|
||||||
|
LatestTradingDay string `json:"latesttradingday"`
|
||||||
|
PreviousClose string `json:"previousclose"`
|
||||||
|
Change string `json:"change"`
|
||||||
|
ChangePercent string `json:"changepercent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StockPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
|
if !message.Command {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := strings.Fields(message.Body)
|
||||||
|
numTokens := len(tokens)
|
||||||
|
|
||||||
|
if numTokens == 2 && strings.ToLower(tokens[0]) == "stock-price" {
|
||||||
|
query := fmt.Sprintf("https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=%s&apikey=%s", tokens[1], p.apiKey)
|
||||||
|
|
||||||
|
resp, err := http.Get(query)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to get stock info")
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Error stock info body")
|
||||||
|
}
|
||||||
|
|
||||||
|
response := "Failed to retrieve data for stock symbol: " + tokens[1]
|
||||||
|
|
||||||
|
cleaned := strings.ReplaceAll(string(body), " ", "")
|
||||||
|
regex := regexp.MustCompile("[0-9][0-9]\\.")
|
||||||
|
|
||||||
|
cleaned = regex.ReplaceAllString(cleaned, "")
|
||||||
|
|
||||||
|
var info GlobalQuote
|
||||||
|
err = json.Unmarshal([]byte(cleaned), &info)
|
||||||
|
|
||||||
|
if err == nil && strings.EqualFold(tokens[1], info.Info.Symbol) {
|
||||||
|
response = fmt.Sprintf("%s : $%s (%s)", tokens[1], info.Info.Price, info.Info.ChangePercent)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.bot.Send(c, bot.Message, message.Channel, response)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StockPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
|
p.bot.Send(c, bot.Message, message.Channel, "try '!stock-price SYMBOL'")
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package stock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/velour/catbase/plugins/cli"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/velour/catbase/bot"
|
||||||
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
"github.com/velour/catbase/bot/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) {
|
||||||
|
isCmd := strings.HasPrefix(payload, "!")
|
||||||
|
if isCmd {
|
||||||
|
payload = payload[1:]
|
||||||
|
}
|
||||||
|
return &cli.CliPlugin{}, bot.Message, msg.Message{
|
||||||
|
User: &user.User{Name: "tester"},
|
||||||
|
Channel: "test",
|
||||||
|
Body: payload,
|
||||||
|
Command: isCmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValid(t *testing.T) {
|
||||||
|
mb := bot.NewMockBot()
|
||||||
|
c := New(mb)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
res := c.message(makeMessage("!stock-price TWTR"))
|
||||||
|
assert.Len(t, mb.Messages, 1)
|
||||||
|
assert.True(t, res)
|
||||||
|
assert.Contains(t, mb.Messages[0], "TWTR : $")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalid(t *testing.T) {
|
||||||
|
mb := bot.NewMockBot()
|
||||||
|
c := New(mb)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
res := c.message(makeMessage("!stock-price NOTREAL"))
|
||||||
|
assert.Len(t, mb.Messages, 1)
|
||||||
|
assert.True(t, res)
|
||||||
|
assert.Contains(t, mb.Messages[0], "Failed to retrieve data for stock symbol: NOTREAL")
|
||||||
|
}
|
Loading…
Reference in New Issue