From 8b8ac7b24488e7074e8f0d5075e95adf8454e8c2 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Fri, 3 Mar 2023 12:14:06 -0500 Subject: [PATCH 01/18] gpt: reset client when prompt changes --- plugins/gpt/chatgpt.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/plugins/gpt/chatgpt.go b/plugins/gpt/chatgpt.go index f7ea523..1267350 100644 --- a/plugins/gpt/chatgpt.go +++ b/plugins/gpt/chatgpt.go @@ -6,7 +6,7 @@ import ( ) import "github.com/andrewstuart/openai" -var session *openai.ChatSession +var session openai.ChatSession var client *openai.Client func (p *GPTPlugin) getClient() (*openai.Client, error) { @@ -14,14 +14,11 @@ func (p *GPTPlugin) getClient() (*openai.Client, error) { if token == "" { return nil, fmt.Errorf("no GPT token given") } - if client == nil { - return openai.NewClient(token) - } - return client, nil + return openai.NewClient(token) } func (p *GPTPlugin) chatGPT(request string) (string, error) { - if session == nil { + if client == nil { if err := p.setDefaultPrompt(); err != nil { return "", err } @@ -38,7 +35,6 @@ func (p *GPTPlugin) setPrompt(prompt string) error { if err != nil { return err } - sess := client.NewChatSession(prompt) - session = &sess + session = client.NewChatSession(prompt) return nil } From 7d5cf3909d36ac6df660633313928f216e6c1c57 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Fri, 3 Mar 2023 15:04:06 -0500 Subject: [PATCH 02/18] gpt: remove a colon --- plugins/gpt/chatgpt.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/gpt/chatgpt.go b/plugins/gpt/chatgpt.go index 1267350..f877ea7 100644 --- a/plugins/gpt/chatgpt.go +++ b/plugins/gpt/chatgpt.go @@ -31,7 +31,8 @@ func (p *GPTPlugin) setDefaultPrompt() error { } func (p *GPTPlugin) setPrompt(prompt string) error { - client, err := p.getClient() + var err error + client, err = p.getClient() if err != nil { return err } From 4626d0270c36f0e65288ba1aae4b467644f1e5de Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Fri, 3 Mar 2023 15:08:54 -0500 Subject: [PATCH 03/18] gpt: make echo configurable --- plugins/gpt/gpt3.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/gpt/gpt3.go b/plugins/gpt/gpt3.go index 10d37c8..8b3737b 100644 --- a/plugins/gpt/gpt3.go +++ b/plugins/gpt/gpt3.go @@ -96,7 +96,7 @@ func (p *GPTPlugin) gpt3(stem string) string { TopP: p.c.GetFloat64("gpt3.top_p", 1), N: p.c.GetInt("gpt3.n", 1), Stop: p.c.GetArray("gpt3.stop", []string{"\n"}), - Echo: true, + Echo: p.c.GetBool("gpt3.echo", false), } val, err := p.mkRequest(gpt3URL, postStruct) if err != nil { From d1986be68a2f76503407d3e8a62024284b66f116 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Sun, 5 Mar 2023 15:26:41 -0500 Subject: [PATCH 04/18] gpt: make gpt the catchall --- connectors/discord/discord.go | 22 +++++++++++++++++++++- main.go | 4 ++-- plugins/fact/factoid.go | 13 +------------ plugins/gpt/gpt3.go | 5 +++++ 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/connectors/discord/discord.go b/connectors/discord/discord.go index 6e5109a..8f1b3a1 100644 --- a/connectors/discord/discord.go +++ b/connectors/discord/discord.go @@ -151,7 +151,27 @@ func (d *Discord) sendMessage(channel, message string, meMessage bool, args ...a Interface("data", data). Msg("sending message") - st, err := d.client.ChannelMessageSendComplex(channel, data) + maxLen := 2000 + chunkSize := maxLen - 100 + var st *discordgo.Message + var err error + if len(data.Content) > maxLen { + tmp := data.Content + data.Content = tmp[:chunkSize] + st, err = d.client.ChannelMessageSendComplex(channel, data) + if err != nil { + return "", err + } + for i := chunkSize; i < len(data.Content); i += chunkSize { + data := &discordgo.MessageSend{Content: tmp[i : i+chunkSize]} + st, err = d.client.ChannelMessageSendComplex(channel, data) + if err != nil { + break + } + } + } else { + st, err = d.client.ChannelMessageSendComplex(channel, data) + } //st, err := d.client.ChannelMessageSend(channel, message) if err != nil { diff --git a/main.go b/main.go index b134a0e..296ce88 100644 --- a/main.go +++ b/main.go @@ -135,7 +135,6 @@ func main() { b.AddPlugin(roles.New(b)) b.AddPlugin(twitch.New(b)) b.AddPlugin(pagecomment.New(b)) - b.AddPlugin(gpt.New(b)) b.AddPlugin(secrets.New(b)) b.AddPlugin(mayi.New(b)) b.AddPlugin(giphy.New(b)) @@ -179,8 +178,9 @@ func main() { b.AddPlugin(cowboy.New(b)) b.AddPlugin(topic.New(b)) b.AddPlugin(talker.New(b)) - // catches anything left, will always return true b.AddPlugin(fact.New(b)) + // catches anything left, will always return true + b.AddPlugin(gpt.New(b)) if err := client.Serve(); err != nil { log.Fatal().Err(err) diff --git a/plugins/fact/factoid.go b/plugins/fact/factoid.go index d4098e8..9a68f68 100644 --- a/plugins/fact/factoid.go +++ b/plugins/fact/factoid.go @@ -485,18 +485,7 @@ func (p *FactoidPlugin) register() { return true } - notFound := p.c.GetArray("fact.notfound", []string{ - "I don't know.", - "NONONONO", - "((", - "*pukes*", - "NOPE! NOPE! NOPE!", - "One time, I learned how to jump rope.", - }) - - // We didn't find anything, panic! - p.b.Send(c, bot.Message, message.Channel, notFound[rand.Intn(len(notFound))]) - return true + return false }}, } p.b.RegisterTable(p, p.handlers) diff --git a/plugins/gpt/gpt3.go b/plugins/gpt/gpt3.go index 8b3737b..4cba3f0 100644 --- a/plugins/gpt/gpt3.go +++ b/plugins/gpt/gpt3.go @@ -54,6 +54,11 @@ func (p *GPTPlugin) register() { HelpText: "set the ChatGPT prompt", Handler: p.setPromptMessage, }, + { + Kind: bot.Message, IsCmd: true, + Regex: regexp.MustCompile(`(?P.*)`), + Handler: p.chatMessage, + }, } log.Debug().Msg("Registering GPT3 handlers") p.b.RegisterTable(p, p.h) From 6707902caff66dc1e7a2686548e942c199b6afeb Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Sun, 5 Mar 2023 15:46:22 -0500 Subject: [PATCH 05/18] fact: don't look for is actions --- plugins/fact/factoid.go | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/plugins/fact/factoid.go b/plugins/fact/factoid.go index 9a68f68..e399624 100644 --- a/plugins/fact/factoid.go +++ b/plugins/fact/factoid.go @@ -90,21 +90,8 @@ func New(botInst bot.Bot) *FactoidPlugin { // findAction simply regexes a string for the action verb func findAction(message string) string { - r, err := regexp.Compile("<.+?>") - if err != nil { - panic(err) - } - action := r.FindString(message) - - if action == "" { - if strings.Contains(message, " is ") { - return "is" - } else if strings.Contains(message, " are ") { - return "are" - } - } - - return action + r := regexp.MustCompile("<.+?>") + return r.FindString(message) } // learnFact assumes we have a learning situation and inserts a new fact From 295d9fef77a920d9e91b0e3d6dcf224d57e562d5 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:30:49 -0400 Subject: [PATCH 06/18] tap: maybe fix font locations --- plugins/meme/meme.go | 10 +++++----- plugins/tappd/image.go | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/meme/meme.go b/plugins/meme/meme.go index 178c385..319eabf 100644 --- a/plugins/meme/meme.go +++ b/plugins/meme/meme.go @@ -329,7 +329,7 @@ func FindFontSize(c *config.Config, config []string, fontLocation string, w, h i longestStr, longestW := "", 0.0 for _, s := range config { - err := m.LoadFontFace(getFont(c, fontLocation), 12) + err := m.LoadFontFace(GetFont(c, fontLocation), 12) if err != nil { log.Error().Err(err).Msg("could not load font") return fontSize @@ -343,7 +343,7 @@ func FindFontSize(c *config.Config, config []string, fontLocation string, w, h i } for _, sz := range sizes { - err := m.LoadFontFace(getFont(c, fontLocation), sz) // problem + err := m.LoadFontFace(GetFont(c, fontLocation), sz) // problem if err != nil { log.Error().Err(err).Msg("could not load font") return fontSize @@ -476,7 +476,7 @@ func (p *MemePlugin) genMeme(spec specification) ([]byte, error) { if fontLocation == "" { fontLocation = defaultFont } - m.LoadFontFace(getFont(p.c, fontLocation), fontSize) + m.LoadFontFace(GetFont(p.c, fontLocation), fontSize) x := float64(w)*c.XPerc + float64(dx) y := float64(h)*c.YPerc + float64(dy) m.DrawStringAnchored(c.Text, x, y, 0.5, 0.5) @@ -491,7 +491,7 @@ func (p *MemePlugin) genMeme(spec specification) ([]byte, error) { if fontLocation == "" { fontLocation = defaultFont } - m.LoadFontFace(getFont(p.c, fontLocation), fontSize) + m.LoadFontFace(GetFont(p.c, fontLocation), fontSize) x := float64(w) * c.XPerc y := float64(h) * c.YPerc m.DrawStringAnchored(c.Text, x, y, 0.5, 0.5) @@ -506,7 +506,7 @@ func (p *MemePlugin) genMeme(spec specification) ([]byte, error) { return p.images[jsonSpec].repr, nil } -func getFont(c *config.Config, name string) string { +func GetFont(c *config.Config, name string) string { location := c.Get("meme.fontLocation", "") fontShortcuts := c.GetMap("meme.fontShortcuts", map[string]string{"impact": "impact.ttf"}) if file, ok := fontShortcuts[name]; ok { diff --git a/plugins/tappd/image.go b/plugins/tappd/image.go index 87b1eb1..cfc204d 100644 --- a/plugins/tappd/image.go +++ b/plugins/tappd/image.go @@ -67,7 +67,7 @@ func defaultSpec() textSpec { } func (p *Tappd) overlay(img image.Image, texts []textSpec) ([]byte, error) { - font := p.c.Get("meme.font", "impact.ttf") + font := meme.GetFont(p.c, p.c.Get("meme.font", "impact.ttf")) fontSizes := []float64{48, 36, 24, 16, 12} r := img.Bounds() w := r.Dx() @@ -79,6 +79,7 @@ func (p *Tappd) overlay(img image.Image, texts []textSpec) ([]byte, error) { } fontSize := meme.FindFontSize(p.c, txts, font, w, h, fontSizes) + log.Debug().Msgf("Decided on font size: %d", fontSize) m := gg.NewContext(w, h) m.DrawImage(img, 0, 0) From 21ce66fc15bd97c4e59d519582e4f59a5c286428 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:35:17 -0400 Subject: [PATCH 07/18] font: remove debug --- plugins/tappd/image.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/tappd/image.go b/plugins/tappd/image.go index cfc204d..893ad0f 100644 --- a/plugins/tappd/image.go +++ b/plugins/tappd/image.go @@ -79,7 +79,6 @@ func (p *Tappd) overlay(img image.Image, texts []textSpec) ([]byte, error) { } fontSize := meme.FindFontSize(p.c, txts, font, w, h, fontSizes) - log.Debug().Msgf("Decided on font size: %d", fontSize) m := gg.NewContext(w, h) m.DrawImage(img, 0, 0) From b63b317dfc23deb1a057ce6fda47ab527d0eea8e Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Sat, 8 Apr 2023 21:17:21 -0400 Subject: [PATCH 08/18] gpt: reset chat prompt every N messages --- plugins/gpt/chatgpt.go | 15 +++- plugins/gpt/gpt3.go | 2 + plugins/twitch/demo/main.go | 146 ++++++++++++++++++++++++++++++++++++ util/stats/main.go | 1 + 4 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 plugins/twitch/demo/main.go create mode 100644 util/stats/main.go diff --git a/plugins/gpt/chatgpt.go b/plugins/gpt/chatgpt.go index f877ea7..9b0f5f5 100644 --- a/plugins/gpt/chatgpt.go +++ b/plugins/gpt/chatgpt.go @@ -19,15 +19,20 @@ func (p *GPTPlugin) getClient() (*openai.Client, error) { func (p *GPTPlugin) chatGPT(request string) (string, error) { if client == nil { - if err := p.setDefaultPrompt(); err != nil { + if err := p.setPrompt(p.getDefaultPrompt()); err != nil { return "", err } } + if p.chatCount > p.c.GetInt("gpt.maxchats", 10) { + p.setPrompt(p.c.Get("gpt3.lastprompt", p.getDefaultPrompt())) + p.chatCount = 0 + } + p.chatCount++ return session.Complete(context.Background(), request) } -func (p *GPTPlugin) setDefaultPrompt() error { - return p.setPrompt(p.c.Get("gpt.prompt", "")) +func (p *GPTPlugin) getDefaultPrompt() string { + return p.c.Get("gpt.prompt", "") } func (p *GPTPlugin) setPrompt(prompt string) error { @@ -37,5 +42,9 @@ func (p *GPTPlugin) setPrompt(prompt string) error { return err } session = client.NewChatSession(prompt) + err = p.c.Set("gpt3.lastprompt", prompt) + if err != nil { + return err + } return nil } diff --git a/plugins/gpt/gpt3.go b/plugins/gpt/gpt3.go index 4cba3f0..764ca53 100644 --- a/plugins/gpt/gpt3.go +++ b/plugins/gpt/gpt3.go @@ -23,6 +23,8 @@ type GPTPlugin struct { b bot.Bot c *config.Config h bot.HandlerTable + + chatCount int } func New(b bot.Bot) *GPTPlugin { diff --git a/plugins/twitch/demo/main.go b/plugins/twitch/demo/main.go new file mode 100644 index 0000000..e77fdb8 --- /dev/null +++ b/plugins/twitch/demo/main.go @@ -0,0 +1,146 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/nicklaw5/helix" + "io" + "log" + "net/http" +) + +func main() { + client, err := helix.NewClient(&helix.Options{ + ClientID: "ptwtiuzl9tcrekpf3d26ey3hb7qsge", + ClientSecret: "rpa0w6qemjqp7sgrmidwi4k0kcah82", + }) + if err != nil { + log.Printf("Login error: %v", err) + return + } + + access, err := client.RequestAppAccessToken([]string{"user:read:email"}) + if err != nil { + log.Printf("Login error: %v", err) + return + } + + fmt.Printf("%+v\n", access) + + // Set the access token on the client + client.SetAppAccessToken(access.Data.AccessToken) + + users, err := client.GetUsers(&helix.UsersParams{ + Logins: []string{"drseabass"}, + }) + if err != nil { + log.Printf("Error getting users: %v", err) + return + } + + if users.Error != "" { + log.Printf("Users error: %s", users.Error) + return + } + + log.Printf("drseabass: %+v", users.Data.Users[0]) + return + + resp, err := client.CreateEventSubSubscription(&helix.EventSubSubscription{ + Type: helix.EventSubTypeStreamOnline, + Version: "1", + Condition: helix.EventSubCondition{ + BroadcasterUserID: users.Data.Users[0].ID, + }, + Transport: helix.EventSubTransport{ + Method: "webhook", + Callback: "https://rathaus.chrissexton.org/live", + Secret: "s3cre7w0rd", + }, + }) + if err != nil { + log.Printf("Eventsub error: %v", err) + return + } + + fmt.Printf("%+v\n", resp) + + resp, err = client.CreateEventSubSubscription(&helix.EventSubSubscription{ + Type: helix.EventSubTypeStreamOffline, + Version: "1", + Condition: helix.EventSubCondition{ + BroadcasterUserID: users.Data.Users[0].ID, + }, + Transport: helix.EventSubTransport{ + Method: "webhook", + Callback: "https://rathaus.chrissexton.org/offline", + Secret: "s3cre7w0rd", + }, + }) + if err != nil { + log.Printf("Eventsub error: %v", err) + return + } + + fmt.Printf("%+v\n", resp) + + http.HandleFunc("/offline", func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + if err != nil { + log.Println(err) + return + } + defer r.Body.Close() + // verify that the notification came from twitch using the secret. + if !helix.VerifyEventSubNotification("s3cre7w0rd", r.Header, string(body)) { + log.Println("no valid signature on subscription") + return + } else { + log.Println("verified signature for subscription") + } + var vals map[string]any + if err = json.Unmarshal(body, &vals); err != nil { + log.Println(err) + return + } + + if challenge, ok := vals["challenge"]; ok { + w.Write([]byte(challenge.(string))) + return + } + + log.Printf("got offline webhook: %v\n", vals) + w.WriteHeader(200) + w.Write([]byte("ok")) + }) + http.HandleFunc("/live", func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + if err != nil { + log.Println(err) + return + } + defer r.Body.Close() + // verify that the notification came from twitch using the secret. + if !helix.VerifyEventSubNotification("s3cre7w0rd", r.Header, string(body)) { + log.Println("no valid signature on subscription") + return + } else { + log.Println("verified signature for subscription") + } + var vals map[string]any + if err = json.Unmarshal(body, &vals); err != nil { + log.Println(err) + return + } + + if challenge, ok := vals["challenge"]; ok { + w.Write([]byte(challenge.(string))) + return + } + + log.Printf("got live webhook: %v\n", vals) + w.WriteHeader(200) + w.Write([]byte("ok")) + }) + http.ListenAndServe("0.0.0.0:1337", nil) +} diff --git a/util/stats/main.go b/util/stats/main.go new file mode 100644 index 0000000..43b4fd5 --- /dev/null +++ b/util/stats/main.go @@ -0,0 +1 @@ +package stats From c91fdcdf29581f89642add0755ee0c5368cfa7d9 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:52:11 -0400 Subject: [PATCH 09/18] bot: add spoiler message type --- bot/interfaces.go | 2 ++ bot/mock.go | 3 +++ connectors/discord/discord.go | 3 +++ plugins/talker/talker.go | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/bot/interfaces.go b/bot/interfaces.go index c574212..c238409 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -26,6 +26,8 @@ const ( Reply // Action any /me action Action + // Spoiler is for commented out messages + Spoiler // Reaction Icon reaction if service supports it Reaction // Edit message ref'd new message to replace diff --git a/bot/mock.go b/bot/mock.go index b1d7ae2..cab54c9 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -37,6 +37,9 @@ func (mb *MockBot) GetPassword() string { return "12345" } func (mb *MockBot) SetQuiet(bool) {} func (mb *MockBot) Send(c Connector, kind Kind, args ...any) (string, error) { switch kind { + case Spoiler: + mb.Messages = append(mb.Messages, "||"+args[1].(string)+"||") + return fmt.Sprintf("m-%d", len(mb.Actions)-1), nil case Message: mb.Messages = append(mb.Messages, args[1].(string)) return fmt.Sprintf("m-%d", len(mb.Actions)-1), nil diff --git a/connectors/discord/discord.go b/connectors/discord/discord.go index 8f1b3a1..66834a6 100644 --- a/connectors/discord/discord.go +++ b/connectors/discord/discord.go @@ -74,6 +74,9 @@ func (d Discord) Send(kind bot.Kind, args ...any) (string, error) { return d.sendMessage(args[0].(string), args[2].(string), false, args...) case bot.Message: return d.sendMessage(args[0].(string), args[1].(string), false, args...) + case bot.Spoiler: + outgoing := "||" + args[1].(string) + "||" + return d.sendMessage(args[0].(string), outgoing, false, args...) case bot.Action: return d.sendMessage(args[0].(string), args[1].(string), true, args...) case bot.Edit: diff --git a/plugins/talker/talker.go b/plugins/talker/talker.go index 5cba8a1..618e078 100644 --- a/plugins/talker/talker.go +++ b/plugins/talker/talker.go @@ -104,7 +104,7 @@ func (p *TalkerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Messa line = strings.Replace(line, "{nick}", nick, 1) output += line + "\n" } - p.bot.Send(c, bot.Message, channel, output) + p.bot.Send(c, bot.Spoiler, channel, output) return true } From 3dc8c77505e6a87d28cfcdb059e117fe0267cdfb Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Thu, 3 Aug 2023 10:34:12 -0400 Subject: [PATCH 10/18] reminder: remove natural language thing --- plugins/reminder/reminder.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/reminder/reminder.go b/plugins/reminder/reminder.go index f37f37a..31f5523 100644 --- a/plugins/reminder/reminder.go +++ b/plugins/reminder/reminder.go @@ -120,7 +120,6 @@ func (p *ReminderPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mes channel := message.Channel from := message.User.Name - message.Body = replaceDuration(p.when, message.Body) parts := strings.Fields(message.Body) if len(parts) >= 5 { From c32738f4440b662481bb461277043b1f66833e9e Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:43:27 -0400 Subject: [PATCH 11/18] admin: convert variables page to htmx --- bot/bot.go | 2 + bot/nav.html | 22 +++++++++ bot/web.go | 17 +++++++ plugins/admin/vars.html | 99 ++++++++++++----------------------------- plugins/admin/web.go | 28 +++++++++++- plugins/fact/factoid.go | 1 - 6 files changed, 96 insertions(+), 73 deletions(-) create mode 100644 bot/nav.html diff --git a/bot/bot.go b/bot/bot.go index 98a5824..d8a3b51 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -147,6 +147,8 @@ func (b *bot) setupHTTP() { b.router.HandleFunc("/", b.serveRoot) b.router.HandleFunc("/nav", b.serveNav) + b.router.HandleFunc("/navHTML", b.serveNavHTML) + b.router.HandleFunc("/navHTML/{currentPage}", b.serveNavHTML) } func (b *bot) ListenAndServe() { diff --git a/bot/nav.html b/bot/nav.html new file mode 100644 index 0000000..c3d9068 --- /dev/null +++ b/bot/nav.html @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/bot/web.go b/bot/web.go index e32aa23..4d901a6 100644 --- a/bot/web.go +++ b/bot/web.go @@ -3,8 +3,12 @@ package bot import ( "embed" "encoding/json" + "fmt" + "github.com/go-chi/chi/v5" + "github.com/rs/zerolog/log" "net/http" "strings" + "text/template" ) //go:embed *.html @@ -15,6 +19,19 @@ func (b *bot) serveRoot(w http.ResponseWriter, r *http.Request) { w.Write(index) } +func (b *bot) serveNavHTML(w http.ResponseWriter, r *http.Request) { + currentPage := chi.URLParam(r, "currentPage") + tpl := template.Must(template.ParseFS(embeddedFS, "nav.html")) + if err := tpl.Execute(w, struct { + CurrentPage string + Items []EndPoint + }{currentPage, b.GetWebNavigation()}); err != nil { + log.Error().Err(err).Msg("template error") + w.WriteHeader(500) + fmt.Fprint(w, "Error parsing nav template") + } +} + func (b *bot) serveNav(w http.ResponseWriter, r *http.Request) { enc := json.NewEncoder(w) err := enc.Encode(b.GetWebNavigation()) diff --git a/plugins/admin/vars.html b/plugins/admin/vars.html index eded1ce..a401642 100644 --- a/plugins/admin/vars.html +++ b/plugins/admin/vars.html @@ -1,77 +1,36 @@ - + - - - - - - - - - - - - - Vars + + + vars + + +
+
-
- - Variables - - {{ item.name }} - - - - - {{ err }} - - - - -
- - + + + + + + + + + {{range .Items}} + + + + {{else}} + + + + {{end}} + +
KeyValue
{{.Key}}{{.Value}}
No data
+
+ \ No newline at end of file diff --git a/plugins/admin/web.go b/plugins/admin/web.go index b20f143..706edd9 100644 --- a/plugins/admin/web.go +++ b/plugins/admin/web.go @@ -6,6 +6,7 @@ import ( "embed" "encoding/json" "fmt" + "html/template" "io/ioutil" "net/http" "strings" @@ -166,9 +167,32 @@ func writeErr(w http.ResponseWriter, err error) { fmt.Fprint(w, string(j)) } +type configEntry struct { + Key string `json:"key"` + Value string `json:"value"` +} + func (p *AdminPlugin) handleVars(w http.ResponseWriter, r *http.Request) { - index, _ := embeddedFS.ReadFile("vars.html") - w.Write(index) + tpl := template.Must(template.ParseFS(embeddedFS, "vars.html")) + var configEntries []configEntry + q := `select key, value from config` + err := p.db.Select(&configEntries, q) + if err != nil { + log.Error(). + Err(err). + Msg("Error getting config entries.") + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + + if err := tpl.Execute(w, struct { + Items []configEntry + }{configEntries}); err != nil { + log.Error().Err(err).Msg("template error") + w.WriteHeader(500) + fmt.Fprint(w, "Error parsing template") + } } func (p *AdminPlugin) handleVarsAPI(w http.ResponseWriter, r *http.Request) { diff --git a/plugins/fact/factoid.go b/plugins/fact/factoid.go index e399624..ca1bddf 100644 --- a/plugins/fact/factoid.go +++ b/plugins/fact/factoid.go @@ -144,7 +144,6 @@ func (p *FactoidPlugin) findTrigger(fact string) (bool, *Factoid) { f, err := GetSingleFact(p.db, fact) if err != nil { - log.Error().Err(err).Msg("GetSingleFact") return findAlias(p.db, fact) } return true, f From bfd50a346d5f67210a5a840594864d36443cbc3d Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:34:50 -0400 Subject: [PATCH 12/18] admin: update html formatting --- plugins/admin/vars.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/admin/vars.html b/plugins/admin/vars.html index a401642..74b0bf5 100644 --- a/plugins/admin/vars.html +++ b/plugins/admin/vars.html @@ -8,10 +8,10 @@ -
-
+
- +
+
From 5de82d96e4e203b8acf126b29e86f93164f35a8e Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:45:00 -0400 Subject: [PATCH 13/18] counter: maybe count some stuff better via API --- plugins/counter/api.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/counter/api.go b/plugins/counter/api.go index 9d0ba18..ed7706d 100644 --- a/plugins/counter/api.go +++ b/plugins/counter/api.go @@ -7,6 +7,7 @@ import ( "github.com/velour/catbase/bot/user" "io/ioutil" "net/http" + "net/url" "strconv" "time" @@ -39,8 +40,8 @@ func (p *CounterPlugin) registerWeb() { func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - userName := chi.URLParam(r, "user") - itemName := chi.URLParam(r, "item") + userName, _ := url.QueryUnescape(chi.URLParam(r, "user")) + itemName, _ := url.QueryUnescape(chi.URLParam(r, "item")) delta, _ := strconv.Atoi(chi.URLParam(r, "delta")) secret, pass, ok := r.BasicAuth() @@ -85,7 +86,11 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg) } - chs := p.cfg.GetArray("channels", []string{p.cfg.Get("channels", "none")}) + //chs := p.cfg.GetArray("channels", []string{p.cfg.Get("channels", "none")}) + chs := p.cfg.GetMap("counter.channelItems", map[string]string{}) + if len(chs) == 0 { + return + } req := &bot.Request{ Conn: p.b.DefaultConnector(), Kind: bot.Message, @@ -93,7 +98,7 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri User: &u, // Noting here that we're only going to do goals in a "default" // channel even if it should send updates to others. - Channel: chs[0], + Channel: chs[itemName], Body: fmt.Sprintf("%s += %d", itemName, delta), Time: time.Now(), }, From f2153bf0b4b2fa8a103b6f039d5318d5668be56b Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:58:43 -0400 Subject: [PATCH 14/18] counter: maybe finish this feature --- plugins/counter/api.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/counter/api.go b/plugins/counter/api.go index ed7706d..fac0ce9 100644 --- a/plugins/counter/api.go +++ b/plugins/counter/api.go @@ -86,9 +86,9 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg) } - //chs := p.cfg.GetArray("channels", []string{p.cfg.Get("channels", "none")}) chs := p.cfg.GetMap("counter.channelItems", map[string]string{}) - if len(chs) == 0 { + ch, ok := chs[itemName] + if len(chs) == 0 || !ok { return } req := &bot.Request{ @@ -98,7 +98,7 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri User: &u, // Noting here that we're only going to do goals in a "default" // channel even if it should send updates to others. - Channel: chs[itemName], + Channel: ch, Body: fmt.Sprintf("%s += %d", itemName, delta), Time: time.Now(), }, @@ -119,8 +119,8 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri func (p *CounterPlugin) mkIncrementAPI(delta int) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - userName := chi.URLParam(r, "user") - itemName := chi.URLParam(r, "item") + userName, _ := url.QueryUnescape(chi.URLParam(r, "user")) + itemName, _ := url.QueryUnescape(chi.URLParam(r, "item")) secret, pass, ok := r.BasicAuth() if !ok || !p.b.CheckPassword(secret, pass) { @@ -164,7 +164,11 @@ func (p *CounterPlugin) mkIncrementAPI(delta int) func(w http.ResponseWriter, r personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg) } - chs := p.cfg.GetArray("channels", []string{p.cfg.Get("channels", "none")}) + chs := p.cfg.GetMap("counter.channelItems", map[string]string{}) + ch, ok := chs[itemName] + if len(chs) == 0 || !ok { + return + } req := &bot.Request{ Conn: p.b.DefaultConnector(), Kind: bot.Message, @@ -172,7 +176,7 @@ func (p *CounterPlugin) mkIncrementAPI(delta int) func(w http.ResponseWriter, r User: &u, // Noting here that we're only going to do goals in a "default" // channel even if it should send updates to others. - Channel: chs[0], + Channel: ch, Body: fmt.Sprintf("%s += %d", itemName, delta), Time: time.Now(), }, From f6cfec477fda5b86c6fb5e1b604510b05a7d65e9 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:52:11 -0400 Subject: [PATCH 15/18] counter: fix double counter api issue --- plugins/counter/api.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/counter/api.go b/plugins/counter/api.go index fac0ce9..1f6d515 100644 --- a/plugins/counter/api.go +++ b/plugins/counter/api.go @@ -164,11 +164,9 @@ func (p *CounterPlugin) mkIncrementAPI(delta int) func(w http.ResponseWriter, r personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg) } - chs := p.cfg.GetMap("counter.channelItems", map[string]string{}) - ch, ok := chs[itemName] - if len(chs) == 0 || !ok { - return - } + genericChs := p.cfg.GetArray("counter.channels", []string{}) + specificChs := p.cfg.GetMap("counter.channelItems", map[string]string{}) + ch, ok := specificChs[itemName] req := &bot.Request{ Conn: p.b.DefaultConnector(), Kind: bot.Message, @@ -185,7 +183,12 @@ func (p *CounterPlugin) mkIncrementAPI(delta int) func(w http.ResponseWriter, r } msg := fmt.Sprintf("%s changed their %s counter by %d for a total of %d via the amazing %s API. %s", userName, itemName, delta, item.Count+delta, p.cfg.Get("nick", "catbase"), personalMsg) - for _, ch := range chs { + if !ok { + for _, ch := range genericChs { + p.b.Send(p.b.DefaultConnector(), bot.Message, ch, msg) + req.Msg.Channel = ch + } + } else { p.b.Send(p.b.DefaultConnector(), bot.Message, ch, msg) req.Msg.Channel = ch } From 9cecccfcdddf0a4c39288f907c48dd0b842c09c9 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:49:25 -0400 Subject: [PATCH 16/18] counter: consolidate multiple counter code --- plugins/counter/api.go | 90 +++--------------------------------------- 1 file changed, 6 insertions(+), 84 deletions(-) diff --git a/plugins/counter/api.go b/plugins/counter/api.go index 1f6d515..35d3a90 100644 --- a/plugins/counter/api.go +++ b/plugins/counter/api.go @@ -30,8 +30,8 @@ func (p *CounterPlugin) registerWeb() { subrouter.Use(httprate.LimitByIP(requests, dur)) subrouter.HandleFunc("/api/users/{user}/items/{item}/increment/{delta}", p.mkIncrementByNAPI(1)) subrouter.HandleFunc("/api/users/{user}/items/{item}/decrement/{delta}", p.mkIncrementByNAPI(-1)) - subrouter.HandleFunc("/api/users/{user}/items/{item}/increment", p.mkIncrementAPI(1)) - subrouter.HandleFunc("/api/users/{user}/items/{item}/decrement", p.mkIncrementAPI(-1)) + subrouter.HandleFunc("/api/users/{user}/items/{item}/increment", p.mkIncrementByNAPI(1)) + subrouter.HandleFunc("/api/users/{user}/items/{item}/decrement", p.mkIncrementByNAPI(-1)) r.Mount("/", subrouter) r.HandleFunc("/api", p.handleCounterAPI) r.HandleFunc("/", p.handleCounter) @@ -42,7 +42,10 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri return func(w http.ResponseWriter, r *http.Request) { userName, _ := url.QueryUnescape(chi.URLParam(r, "user")) itemName, _ := url.QueryUnescape(chi.URLParam(r, "item")) - delta, _ := strconv.Atoi(chi.URLParam(r, "delta")) + delta, err := strconv.Atoi(chi.URLParam(r, "delta")) + if err != nil || delta == 0 { + delta = direction + } secret, pass, ok := r.BasicAuth() if !ok || !p.b.CheckPassword(secret, pass) { @@ -117,87 +120,6 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri } } -func (p *CounterPlugin) mkIncrementAPI(delta int) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - userName, _ := url.QueryUnescape(chi.URLParam(r, "user")) - itemName, _ := url.QueryUnescape(chi.URLParam(r, "item")) - - secret, pass, ok := r.BasicAuth() - if !ok || !p.b.CheckPassword(secret, pass) { - err := fmt.Errorf("unauthorized access") - log.Error(). - Err(err). - Msg("error authenticating user") - w.WriteHeader(401) - j, _ := json.Marshal(struct { - Status bool - Error string - }{false, err.Error()}) - fmt.Fprint(w, string(j)) - return - } - - // Try to find an ID if possible - id := "" - u, err := p.b.DefaultConnector().Profile(userName) - if err == nil { - id = u.ID - } - - item, err := GetUserItem(p.db, userName, id, itemName) - if err != nil { - log.Error().Err(err).Msg("error finding item") - w.WriteHeader(400) - j, _ := json.Marshal(struct { - Status bool - Error error - }{false, err}) - fmt.Fprint(w, string(j)) - return - } - - body, _ := ioutil.ReadAll(r.Body) - postData := map[string]string{} - err = json.Unmarshal(body, &postData) - personalMsg := "" - if inputMsg, ok := postData["message"]; ok { - personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg) - } - - genericChs := p.cfg.GetArray("counter.channels", []string{}) - specificChs := p.cfg.GetMap("counter.channelItems", map[string]string{}) - ch, ok := specificChs[itemName] - req := &bot.Request{ - Conn: p.b.DefaultConnector(), - Kind: bot.Message, - Msg: msg.Message{ - User: &u, - // Noting here that we're only going to do goals in a "default" - // channel even if it should send updates to others. - Channel: ch, - Body: fmt.Sprintf("%s += %d", itemName, delta), - Time: time.Now(), - }, - Values: nil, - Args: nil, - } - msg := fmt.Sprintf("%s changed their %s counter by %d for a total of %d via the amazing %s API. %s", - userName, itemName, delta, item.Count+delta, p.cfg.Get("nick", "catbase"), personalMsg) - if !ok { - for _, ch := range genericChs { - p.b.Send(p.b.DefaultConnector(), bot.Message, ch, msg) - req.Msg.Channel = ch - } - } else { - p.b.Send(p.b.DefaultConnector(), bot.Message, ch, msg) - req.Msg.Channel = ch - } - item.UpdateDelta(req, delta) - j, _ := json.Marshal(struct{ Status bool }{true}) - fmt.Fprint(w, string(j)) - } -} - func (p *CounterPlugin) handleCounter(w http.ResponseWriter, r *http.Request) { index, _ := embeddedFS.ReadFile("index.html") w.Write(index) From f18154be5b986ea6925744b785f5c61e1f056c4a Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:19:21 -0400 Subject: [PATCH 17/18] counter: maybe really fix it finally --- plugins/counter/api.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/counter/api.go b/plugins/counter/api.go index 35d3a90..7be7ee3 100644 --- a/plugins/counter/api.go +++ b/plugins/counter/api.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" "github.com/velour/catbase/bot/user" - "io/ioutil" + "io" "net/http" "net/url" "strconv" @@ -81,7 +81,7 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri return } - body, _ := ioutil.ReadAll(r.Body) + body, _ := io.ReadAll(r.Body) postData := map[string]string{} err = json.Unmarshal(body, &postData) personalMsg := "" @@ -110,7 +110,13 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri } msg := fmt.Sprintf("%s changed their %s counter by %d for a total of %d via the amazing %s API. %s", userName, itemName, delta, item.Count+delta*direction, p.cfg.Get("nick", "catbase"), personalMsg) - for _, ch := range chs { + if !ok { + chs := p.cfg.GetArray("counter.channels", []string{}) + for _, ch := range chs { + p.b.Send(p.b.DefaultConnector(), bot.Message, ch, msg) + req.Msg.Channel = ch + } + } else { p.b.Send(p.b.DefaultConnector(), bot.Message, ch, msg) req.Msg.Channel = ch } From c44ada3061073bc3e7038b62e436f468d2eea885 Mon Sep 17 00:00:00 2001 From: Chris Sexton <3216719+chrissexton@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:22:17 -0400 Subject: [PATCH 18/18] counter: fix decrement-by --- plugins/counter/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/counter/api.go b/plugins/counter/api.go index 7be7ee3..35eb4df 100644 --- a/plugins/counter/api.go +++ b/plugins/counter/api.go @@ -45,6 +45,8 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri delta, err := strconv.Atoi(chi.URLParam(r, "delta")) if err != nil || delta == 0 { delta = direction + } else { + delta = delta * direction } secret, pass, ok := r.BasicAuth()
Key