mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-12-20 11:51:17 +00:00
[editor] Add validation for template fields
closes #38 Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
0dc648d02a
commit
4f12b5c206
5 changed files with 100 additions and 6 deletions
|
@ -172,6 +172,10 @@ func patchConfig(filename, authorName, authorEmail, summary string, patcher func
|
|||
return errors.Wrap(err, "patching config")
|
||||
}
|
||||
|
||||
if err = cfgFile.runLoadChecks(); err != nil {
|
||||
return errors.Wrap(err, "checking config after patch")
|
||||
}
|
||||
|
||||
return errors.Wrap(
|
||||
writeConfigToYAML(filename, authorName, authorEmail, summary, cfgFile),
|
||||
"replacing config",
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
var frontendReloadHooks = newHooker()
|
||||
|
||||
//nolint:funlen // Just contains a collection of objects
|
||||
func registerEditorGlobalMethods() {
|
||||
for _, rd := range []plugins.HTTPRouteRegistrationArgs{
|
||||
{
|
||||
|
@ -100,6 +101,23 @@ func registerEditorGlobalMethods() {
|
|||
},
|
||||
ResponseType: plugins.HTTPRouteResponseTypeTextPlain,
|
||||
},
|
||||
{
|
||||
Description: "Validate a template expression against the built in template function library",
|
||||
HandlerFunc: configEditorGlobalValidateTemplate,
|
||||
Method: http.MethodPut,
|
||||
Module: "config-editor",
|
||||
Name: "Validate template expression",
|
||||
Path: "/validate-template",
|
||||
QueryParams: []plugins.HTTPRouteParamDocumentation{
|
||||
{
|
||||
Description: "The template expression to test",
|
||||
Name: "template",
|
||||
Required: true,
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
ResponseType: plugins.HTTPRouteResponseTypeTextPlain,
|
||||
},
|
||||
} {
|
||||
if err := registerRoute(rd); err != nil {
|
||||
log.WithError(err).Fatal("Unable to register config editor route")
|
||||
|
@ -215,3 +233,12 @@ func configEditorGlobalValidateRegex(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func configEditorGlobalValidateTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
if err := validateTemplate(r.FormValue("template")); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
id="formAutoMessageMessage"
|
||||
v-model="models.autoMessage.message"
|
||||
:state="models.autoMessage.message ? models.autoMessage.message.length <= validateAutoMessageMessageLength : false"
|
||||
@valid-template="valid => updateTemplateValid('autoMessage.message', valid)"
|
||||
/>
|
||||
<div slot="description">
|
||||
<font-awesome-icon
|
||||
|
@ -227,6 +228,7 @@
|
|||
<template-editor
|
||||
id="formAutoMessageDisableOnTemplate"
|
||||
v-model="models.autoMessage.disable_on_template"
|
||||
@valid-template="valid => updateTemplateValid('autoMessage.disable_on_template', valid)"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
@ -284,6 +286,10 @@ export default {
|
|||
return false
|
||||
}
|
||||
|
||||
if (Object.entries(this.templateValid).filter(e => !e[1]).length > 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
|
@ -344,6 +350,7 @@ export default {
|
|||
},
|
||||
|
||||
showAutoMessageEditModal: false,
|
||||
templateValid: {},
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -376,6 +383,7 @@ export default {
|
|||
...msg,
|
||||
sendMode: msg.cron ? 'cron' : 'lines',
|
||||
})
|
||||
this.templateValid = {}
|
||||
this.showAutoMessageEditModal = true
|
||||
},
|
||||
|
||||
|
@ -392,6 +400,7 @@ export default {
|
|||
|
||||
newAutoMessage() {
|
||||
Vue.set(this.models, 'autoMessage', {})
|
||||
this.templateValid = {}
|
||||
this.showAutoMessageEditModal = true
|
||||
},
|
||||
|
||||
|
@ -422,6 +431,10 @@ export default {
|
|||
})
|
||||
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
||||
},
|
||||
|
||||
updateTemplateValid(id, valid) {
|
||||
Vue.set(this.templateValid, id, valid)
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
|
|
@ -398,6 +398,7 @@
|
|||
<template-editor
|
||||
id="formRuleDisableOnTemplate"
|
||||
v-model="models.rule.disable_on_template"
|
||||
@valid-template="valid => updateTemplateValid('rule.disable_on_template', valid)"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-tab>
|
||||
|
@ -603,6 +604,7 @@
|
|||
:id="`${models.rule.uuid}-action-${idx}-${field.key}`"
|
||||
v-model="models.rule.actions[idx].attributes[field.key]"
|
||||
:state="validateActionArgument(idx, field.key)"
|
||||
@valid-template="valid => updateTemplateValid(`${models.rule.uuid}-action-${idx}-${field.key}`, valid)"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
|
@ -781,6 +783,7 @@ export default {
|
|||
|
||||
showRuleEditModal: false,
|
||||
showRuleSubscribeModal: false,
|
||||
templateValid: {},
|
||||
validateReason: null,
|
||||
}
|
||||
},
|
||||
|
@ -850,6 +853,7 @@ export default {
|
|||
cooldown: this.fixDurationRepresentationToString(msg.cooldown),
|
||||
user_cooldown: this.fixDurationRepresentationToString(msg.user_cooldown),
|
||||
})
|
||||
this.templateValid = {}
|
||||
this.showRuleEditModal = true
|
||||
this.validateMatcherRegex()
|
||||
},
|
||||
|
@ -976,6 +980,7 @@ export default {
|
|||
|
||||
newRule() {
|
||||
Vue.set(this.models, 'rule', { match_message__validation: true })
|
||||
this.templateValid = {}
|
||||
this.showRuleEditModal = true
|
||||
},
|
||||
|
||||
|
@ -1094,6 +1099,10 @@ export default {
|
|||
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
||||
},
|
||||
|
||||
updateTemplateValid(id, valid) {
|
||||
Vue.set(this.templateValid, id, valid)
|
||||
},
|
||||
|
||||
validateActionArgument(idx, key) {
|
||||
const action = this.models.rule.actions[idx]
|
||||
const def = this.getActionDefinitionByType(action.type)
|
||||
|
@ -1189,6 +1198,11 @@ export default {
|
|||
},
|
||||
|
||||
validateRule() {
|
||||
if (Object.entries(this.templateValid).filter(e => !e[1]).length > 0) {
|
||||
this.validateReason = 'templateValid'
|
||||
return false
|
||||
}
|
||||
|
||||
if (!this.models.rule.match_message__validation) {
|
||||
this.validateReason = 'rule.match_message__validation'
|
||||
return false
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
<template>
|
||||
<div :class="wrapClasses">
|
||||
<div ref="editor" />
|
||||
<div>
|
||||
<div :class="wrapClasses">
|
||||
<div ref="editor" />
|
||||
</div>
|
||||
<div
|
||||
v-if="!isValid && validationError"
|
||||
class="d-block invalid-feedback"
|
||||
>
|
||||
{{ validationError }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as constants from './const.js'
|
||||
import axios from 'axios'
|
||||
import { CodeJar } from 'codejar/codejar.js'
|
||||
import Prism from 'prismjs'
|
||||
import { withLineNumbers } from 'codejar/linenumbers.js'
|
||||
|
@ -38,8 +47,8 @@ export default {
|
|||
wrapClasses() {
|
||||
return {
|
||||
'form-control': true,
|
||||
'is-invalid': this.state === false,
|
||||
'is-valid': this.state === true,
|
||||
'is-invalid': this.state === false || !this.isValid,
|
||||
'is-valid': this.state === true && this.isValid,
|
||||
'template-editor': true,
|
||||
}
|
||||
},
|
||||
|
@ -48,7 +57,9 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
emittedCode: '',
|
||||
isValid: true,
|
||||
jar: null,
|
||||
validationError: '',
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -57,6 +68,27 @@ export default {
|
|||
const code = editor.textContent
|
||||
editor.innerHTML = Prism.highlight(code, this.grammar, 'template')
|
||||
},
|
||||
|
||||
validateTemplate(template) {
|
||||
if (template === '') {
|
||||
this.isValid = true
|
||||
this.validationError = ''
|
||||
this.$emit('valid-template', true)
|
||||
return
|
||||
}
|
||||
|
||||
return axios.put(`config-editor/validate-template?template=${encodeURIComponent(template)}`)
|
||||
.then(() => {
|
||||
this.isValid = true
|
||||
this.validationError = ''
|
||||
this.$emit('valid-template', true)
|
||||
})
|
||||
.catch(resp => {
|
||||
this.isValid = false
|
||||
this.validationError = resp.response.data.split(':1:')[1]
|
||||
this.$emit('valid-template', false)
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
@ -65,6 +97,7 @@ export default {
|
|||
tab: ' '.repeat(2),
|
||||
})
|
||||
this.jar.onUpdate(code => {
|
||||
this.validateTemplate(code)
|
||||
this.emittedCode = code
|
||||
this.$emit('input', code)
|
||||
})
|
||||
|
@ -101,8 +134,6 @@ export default {
|
|||
|
||||
<style>
|
||||
.template-editor {
|
||||
background-color: #fff;
|
||||
border-radius: 0.25rem;
|
||||
color: #444;
|
||||
font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
|
||||
font-size: 87.5%;
|
||||
|
@ -110,6 +141,11 @@ export default {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.template-editor .codejar-wrap {
|
||||
background-color: #fff;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.template-editor .codejar-linenumbers {
|
||||
padding-right: 0.5em;
|
||||
text-align: right;
|
||||
|
|
Loading…
Reference in a new issue