From 4ca7b4c6be6fa785a76a23f6b416e08d0e7b77ae Mon Sep 17 00:00:00 2001 From: Ash Keel Date: Fri, 19 May 2023 15:07:32 +0200 Subject: [PATCH] feat: add rudimentary template checking on chat commands --- CHANGELOG.md | 4 +++ app.go | 12 +++++++ frontend/src/locale/en/translation.json | 3 +- frontend/src/locale/it/translation.json | 3 +- frontend/src/ui/pages/BotCommands.tsx | 43 ++++++++++++++++------ frontend/wailsjs/go/main/App.d.ts | 4 +++ frontend/wailsjs/go/main/App.js | 8 +++++ twitch/bot.alerts.go | 3 +- twitch/bot.go | 3 +- twitch/client.go | 4 +-- twitch/commands.go | 47 +++++++++++++++++++++++++ 11 files changed, 115 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93c4b43..a39f409 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Custom chat commands can now be sent as replies, whispers and announcements. Due to some API shenanigans yet to be solved, the latter two will always be sent from your main account, not the bot account (if they are different) +### Fixed + +- Fixed some minor bugs regarding backup file sorting and migration procedures + ## [3.2.1] - 2023-05-17 ### Fixed diff --git a/app.go b/app.go index 574ab58..6439e28 100644 --- a/app.go +++ b/app.go @@ -290,6 +290,18 @@ func (a *App) GetAppVersion() VersionInfo { } } +func (a *App) TestTemplate(message string, data any) error { + tpl, err := a.twitchManager.Client().Bot.MakeTemplate(message) + if err != nil { + return err + } + return tpl.Execute(io.Discard, data) +} + +func (a *App) TestCommandTemplate(message string) error { + return a.TestTemplate(message, twitch.TestMessageData) +} + func (a *App) interactiveAuth(client kv.Client, message map[string]any) bool { callbackID := fmt.Sprintf("auth-callback-%d", client.UID()) authResult := make(chan bool) diff --git a/frontend/src/locale/en/translation.json b/frontend/src/locale/en/translation.json index 1cc574d..0240837 100644 --- a/frontend/src/locale/en/translation.json +++ b/frontend/src/locale/en/translation.json @@ -131,7 +131,8 @@ }, "remove-command-title": "Remove command {{name}}?", "no-commands": "Chatbot has no commands configured", - "command-already-in-use": "Command name already in use" + "command-already-in-use": "Command name already in use", + "command-invalid-format": "The response template contains errors" }, "bottimers": { "title": "Bot timers", diff --git a/frontend/src/locale/it/translation.json b/frontend/src/locale/it/translation.json index dd77254..49a6775 100644 --- a/frontend/src/locale/it/translation.json +++ b/frontend/src/locale/it/translation.json @@ -118,7 +118,8 @@ "chat": "Canale", "reply": "Risposta", "whisper": "Chat privata" - } + }, + "command-invalid-format": "Il messaggio contiene errori" }, "bottimers": { "add-button": "Nuovo timer", diff --git a/frontend/src/ui/pages/BotCommands.tsx b/frontend/src/ui/pages/BotCommands.tsx index f959796..6904ae9 100644 --- a/frontend/src/ui/pages/BotCommands.tsx +++ b/frontend/src/ui/pages/BotCommands.tsx @@ -1,5 +1,5 @@ import { PlusIcon } from '@radix-ui/react-icons'; -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useModule } from '~/lib/react'; import { useAppDispatch } from '~/store'; @@ -35,6 +35,7 @@ import { TextBlock, } from '../theme'; import { Alert, AlertTrigger } from '../theme/alert'; +import { TestCommandTemplate } from '@wailsapp/go/main/App'; const CommandList = styled('div', { marginTop: '1rem' }); const CommandItemContainer = styled('article', { @@ -227,9 +228,11 @@ function CommandDialog({ item?.response_type ?? 'chat', ); const [response, setResponse] = useState(item?.response ?? ''); + const responseRef = useRef(null); const [accessLevel, setAccessLevel] = useState( item?.access_level ?? 'everyone', ); + const [responseError, setResponseError] = useState(null); const { t } = useTranslation(); const replyTypes: ReplyType[] = ['chat', 'reply', 'whisper', 'announce']; @@ -239,20 +242,29 @@ function CommandDialog({ closeButton={true} >
{ + onSubmit={async (e) => { if (!(e.target as HTMLFormElement).checkValidity()) { return; } e.preventDefault(); - if (onSubmit) { - onSubmit(commandName, { - ...item, - description, - response, - response_type: responseType, - access_level: accessLevel, - }); + try { + await TestCommandTemplate(response); + if (onSubmit) { + onSubmit(commandName, { + ...item, + description, + response, + response_type: responseType, + access_level: accessLevel, + }); + } + } catch (e) { + setResponseError(e); + responseRef.current?.setCustomValidity( + t('pages.botcommands.command-invalid-format'), + ); } + }} > @@ -309,12 +321,21 @@ function CommandDialog({ + {responseError && ( + {responseError} + )}