From 859fb258d2480313dcb6e9467d4533dc9e3ff289 Mon Sep 17 00:00:00 2001 From: Scott Kiesel Date: Fri, 13 Mar 2020 10:16:32 -0400 Subject: [PATCH] A great stupid plugin where you guess the random wikipedia article --- go.mod | 1 - go.sum | 7 +- main.go | 2 + plugins/impossible/impossible.go | 147 ++++++++++++++++++++++++++ plugins/impossible/impossible_test.go | 59 +++++++++++ 5 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 plugins/impossible/impossible.go create mode 100644 plugins/impossible/impossible_test.go diff --git a/go.mod b/go.mod index c1e5076..1c97c36 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/AlekSi/pointer v1.1.0 // indirect github.com/ChimeraCoder/anaconda v2.0.0+incompatible github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7 // indirect - github.com/PaulRosset/go-hacknews v0.0.0-20170815075127-4aad99273a3c github.com/PuerkitoBio/goquery v1.5.0 github.com/andybalholm/cascadia v1.1.0 // indirect github.com/antchfx/htmlquery v1.2.0 // indirect diff --git a/go.sum b/go.sum index 64d1b90..dc90243 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -code.chrissexton.org/cws/getaoc v0.0.0-20191201041923-dc696067b57c h1:X5c+asGWxR/Whkgl/YYXDanC4n2RHYeFcC7mT37+uZ4= -code.chrissexton.org/cws/getaoc v0.0.0-20191201041923-dc696067b57c/go.mod h1:rEpfJR9MplF2TUj2Oy+u4XAaLve2kwB8I2zlzeIQxl8= code.chrissexton.org/cws/getaoc v0.0.0-20191201043947-d5417d4b618d h1:XS13tP+cMAvXYHQiYqcst64wQ854pueMRZSU4+6puU4= code.chrissexton.org/cws/getaoc v0.0.0-20191201043947-d5417d4b618d/go.mod h1:rEpfJR9MplF2TUj2Oy+u4XAaLve2kwB8I2zlzeIQxl8= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -12,8 +10,6 @@ github.com/ChimeraCoder/anaconda v2.0.0+incompatible h1:F0eD7CHXieZ+VLboCD5UAqCe github.com/ChimeraCoder/anaconda v2.0.0+incompatible/go.mod h1:TCt3MijIq3Qqo9SBtuW/rrM4x7rDfWqYWHj8T7hLcLg= github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7 h1:r+EmXjfPosKO4wfiMLe1XQictsIlhErTufbWUsjOTZs= github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7/go.mod h1:b2EuEMLSG9q3bZ95ql1+8oVqzzrTNSiOQqSXWFBzxeI= -github.com/PaulRosset/go-hacknews v0.0.0-20170815075127-4aad99273a3c h1:bJ0HbTMaInVjakxM76G+2gsmbKTdHzpTUGyLGYxdMO0= -github.com/PaulRosset/go-hacknews v0.0.0-20170815075127-4aad99273a3c/go.mod h1:8+24kIp7vJsYy0GmQDDNnPwAYEWkl3OcaPxJSDAfe1U= github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -51,6 +47,7 @@ github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/ github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE= github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= @@ -78,6 +75,7 @@ github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhB github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o= github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= @@ -161,6 +159,7 @@ gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go index a82c944..7c0e539 100644 --- a/main.go +++ b/main.go @@ -32,6 +32,7 @@ import ( "github.com/velour/catbase/plugins/first" "github.com/velour/catbase/plugins/fuck" "github.com/velour/catbase/plugins/git" + "github.com/velour/catbase/plugins/impossible" "github.com/velour/catbase/plugins/inventory" "github.com/velour/catbase/plugins/leftpad" "github.com/velour/catbase/plugins/nerdepedia" @@ -134,6 +135,7 @@ func main() { b.AddPlugin(newsbid.New(b)) b.AddPlugin(twitter.New(b)) b.AddPlugin(git.New(b)) + b.AddPlugin(impossible.New(b)) b.AddPlugin(cli.New(b)) b.AddPlugin(aoc.New(b)) // catches anything left, will always return true diff --git a/plugins/impossible/impossible.go b/plugins/impossible/impossible.go new file mode 100644 index 0000000..00d912b --- /dev/null +++ b/plugins/impossible/impossible.go @@ -0,0 +1,147 @@ +package impossible + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "math/rand" + "regexp" + "strings" + "time" + + "github.com/rs/zerolog/log" + + "github.com/velour/catbase/bot" + "github.com/velour/catbase/bot/msg" + "github.com/velour/catbase/config" +) + +type Impossible struct { + b bot.Bot + c *config.Config + + title string + content []string + updated time.Time + testing bool +} + +func New(b bot.Bot) *Impossible { + i := &Impossible{ + b: b, + c: b.Config(), + title: "", + content: []string{}, + updated: getTodaysMidnight().Add(time.Hour * -24), + testing: false, + } + + b.Register(i, bot.Help, i.help) + b.Register(i, bot.Message, i.message) + + return i +} + +func newTesting(b bot.Bot) *Impossible { + i := &Impossible{ + b: b, + c: b.Config(), + title: "", + content: []string{}, + updated: getTodaysMidnight().Add(time.Hour * -24), + testing: true, + } + + b.Register(i, bot.Help, i.help) + b.Register(i, bot.Message, i.message) + + return i +} + +func (p *Impossible) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.b.Send(c, bot.Message, message.Channel, "You don't need to do anything. I'll take care of it. But guess what I'm thinking.") + return true +} + +func (p *Impossible) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + messaged := false + if p.updated.Before(time.Now()) { + if p.title != "" { + p.b.Send(c, bot.Message, message.Channel, fmt.Sprintf("The last impossible wikipedia article was: \"%s\"", p.title)) + messaged = true + } + for !p.refreshImpossible() {} + + if p.testing { + p.b.Send(c, bot.Message, message.Channel, p.title) + messaged = true + } + } + + lowercase := strings.ToLower(message.Body) + if lowercase == "hint" || lowercase == "clue" { + messaged = true + p.b.Send(c, bot.Message, message.Channel, p.content[rand.Intn(len(p.content))]) + } else if strings.Contains(lowercase, strings.ToLower(p.title)) { + messaged = true + p.b.Send(c, bot.Message, message.Channel, fmt.Sprintf("You guessed the last impossible wikipedia article: \"%s\"", p.title)) + for !p.refreshImpossible() {} + } + + return messaged +} + +func (p *Impossible) refreshImpossible() bool { + p.updated = getTodaysMidnight() + resp, err := http.Get("https://en.wikipedia.org/wiki/Special:Random") + if err != nil { + log.Fatal().Err(err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + + titleRegex := regexp.MustCompile(`id="firstHeading"[^>]*(?P[^<]*)`) + results := titleRegex.FindStringSubmatch(string(body)) + title := results[1][1:] //remove the leading < + + if title == "" { + return false + } + + p.title = title + p.content = []string{} + + resp, err = http.Get("https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&explaintext&titles=" + url.PathEscape(title)) + if err != nil { + log.Fatal().Err(err) + } + defer resp.Body.Close() + body, err = ioutil.ReadAll(resp.Body) + + var object map[string]interface{} + json.Unmarshal([]byte(body), &object) + + pages := object["query"].(map[string]interface{})["pages"].(map[string]interface{}) + for _, page := range pages { + descriptionText := page.(map[string]interface{})["extract"].(string) + sentences := strings.Split(strings.ReplaceAll(descriptionText, "\n", " "), ". ") + for _, sentence := range sentences { + trimmed := strings.ToLower(strings.TrimSpace(sentence)) + if len(trimmed) == 0 || strings.HasPrefix(trimmed, "==") || len(strings.Split(trimmed, " ")) < 5 { + continue + } + + censored := strings.ReplaceAll(trimmed, strings.ToLower(title), "?????") + + p.content = append(p.content, censored) + } + } + return true +} + +func getTodaysMidnight() time.Time { + now := time.Now() + return time.Date(now.Year(), now.Month(), now.Day(), 24, 0, 0, 0, now.Location()) +} diff --git a/plugins/impossible/impossible_test.go b/plugins/impossible/impossible_test.go new file mode 100644 index 0000000..c67fd90 --- /dev/null +++ b/plugins/impossible/impossible_test.go @@ -0,0 +1,59 @@ +package impossible + +import ( + "fmt" + "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" + "github.com/velour/catbase/plugins/counter" +) + +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 makePlugin(t *testing.T) (*Impossible, *bot.MockBot) { + mb := bot.NewMockBot() + counter.New(mb) + p := newTesting(mb) + assert.NotNil(t, p) + return p, mb +} + +func TestNothing(t *testing.T) { + p, mb := makePlugin(t) + p.message(makeMessage("hi")) + p.message(makeMessage("nothing")) + assert.Len(t, mb.Messages, 1) +} + +func TestHint(t *testing.T) { + p, mb := makePlugin(t) + p.message(makeMessage("hi")) + p.message(makeMessage("!hint")) + assert.Len(t, mb.Messages, 2) +} + +func TestCorrect(t *testing.T) { + p, mb := makePlugin(t) + p.message(makeMessage("hi")) + p.message(makeMessage(mb.Messages[0])) + + congrats := fmt.Sprintf("You guessed the last impossible wikipedia article: \"%s\"", mb.Messages[0]) + + assert.Contains(t, mb.Messages[1], congrats) +}