Channel conf UI WIP

This commit is contained in:
John Livingston 2023-09-22 16:30:12 +02:00
parent af115e984b
commit 562073fc09
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
6 changed files with 204 additions and 68 deletions

View File

@ -58,7 +58,7 @@
name="forbidden_words_{{fieldNumber}}" name="forbidden_words_{{fieldNumber}}"
id="peertube-livechat-forbidden-words-{{fieldNumber}}" id="peertube-livechat-forbidden-words-{{fieldNumber}}"
class="form-control" class="form-control"
>{{entries}}</textarea> >{{joinedEntries}}</textarea>
<p class="form-group-description">{{forbiddenWordsDesc2}}</p> <p class="form-group-description">{{forbiddenWordsDesc2}}</p>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -121,7 +121,7 @@
name="quote_{{fieldNumber}}" name="quote_{{fieldNumber}}"
id="peertube-livechat-quote-{{fieldNumber}}" id="peertube-livechat-quote-{{fieldNumber}}"
class="form-control" class="form-control"
>{{TODO}}</textarea> >{{joinedMessages}}</textarea>
<p class="form-group-description">{{quoteDesc2}}</p> <p class="form-group-description">{{quoteDesc2}}</p>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -134,7 +134,7 @@
name="quote_delay_{{fieldNumber}}" name="quote_delay_{{fieldNumber}}"
class="form-control" class="form-control"
id="peertube-livechat-quote-delay-{{fieldNumber}}" id="peertube-livechat-quote-delay-{{fieldNumber}}"
value="5" value="{{delay}}"
/> />
<p class="form-group-description">{{quoteDelayDesc}}</p> <p class="form-group-description">{{quoteDelayDesc}}</p>
</div> </div>
@ -159,7 +159,7 @@
name="command_{{fieldNumber}}" name="command_{{fieldNumber}}"
class="form-control" class="form-control"
id="peertube-livechat-command-{{fieldNumber}}" id="peertube-livechat-command-{{fieldNumber}}"
value="" value="{{command}}"
/> />
<p class="form-group-description">{{commandCmdDesc}}</p> <p class="form-group-description">{{commandCmdDesc}}</p>
</div> </div>
@ -170,7 +170,7 @@
name="command_message_{{fieldNumber}}" name="command_message_{{fieldNumber}}"
class="form-control" class="form-control"
id="peertube-livechat-command-message-{{fieldNumber}}" id="peertube-livechat-command-message-{{fieldNumber}}"
value="" value="{{message}}"
/> />
<p class="form-group-description">{{commandMessageDesc}}</p> <p class="form-group-description">{{commandMessageDesc}}</p>
</div> </div>

View File

@ -33,37 +33,90 @@ async function getConfigurationChannelViewData (
throw new Error('Invalid channel configuration options.') throw new Error('Invalid channel configuration options.')
} }
const forbiddenWordsArray = [] const forbiddenWordsArray: Object[] = []
for (let i = 0; i < channelConfiguration.configuration.bot.forbiddenWords.length; i++) { for (let i = 0; i < channelConfiguration.configuration.bot.forbiddenWords.length; i++) {
const fw = channelConfiguration.configuration.bot.forbiddenWords[i] const fw = channelConfiguration.configuration.bot.forbiddenWords[i]
forbiddenWordsArray.push({ forbiddenWordsArray.push({
displayNumber: i + 1, displayNumber: i + 1,
fieldNumber: i, fieldNumber: i,
displayHelp: i === 0, displayHelp: i === 0,
entries: fw.entries.join('\n'), joinedEntries: fw.entries.join('\n'),
regexp: !!fw.regexp, regexp: !!fw.regexp,
applyToModerators: fw.applyToModerators, applyToModerators: fw.applyToModerators,
reason: fw.reason reason: fw.reason
}) })
} }
// Ensuring we have at least N blocks:
while (forbiddenWordsArray.length < 3) {
const i = forbiddenWordsArray.length
// default value
forbiddenWordsArray.push({
displayNumber: i + 1,
fieldNumber: i,
displayHelp: i === 0,
joinedEntries: '',
regexp: false,
applyToModerators: false,
reason: ''
})
continue
}
const quotesArray: Object[] = []
for (let i = 0; i < channelConfiguration.configuration.bot.quotes.length; i++) {
const qs = channelConfiguration.configuration.bot.quotes[i]
quotesArray.push({
displayNumber: i + 1,
fieldNumber: i,
displayHelp: i === 0,
joinedMessages: qs.messages.join('\n'),
delay: Math.round(qs.delay / 60) // converting to minutes
})
}
// Ensuring we have at least N blocks:
while (quotesArray.length < 1) {
const i = quotesArray.length
// default value
quotesArray.push({
displayNumber: i + 1,
fieldNumber: i,
displayHelp: i === 0,
joinedMessages: '',
delay: 5
})
continue
}
const cmdsArray: Object[] = []
for (let i = 0; i < channelConfiguration.configuration.bot.commands.length; i++) {
const cs = channelConfiguration.configuration.bot.commands[i]
cmdsArray.push({
displayNumber: i + 1,
fieldNumber: i,
displayHelp: i === 0,
message: cs.message,
command: cs.command
})
}
// Ensuring we have at least N blocks:
while (cmdsArray.length < 3) {
const i = cmdsArray.length
// default value
cmdsArray.push({
displayNumber: i + 1,
fieldNumber: i,
displayHelp: i === 0,
message: '',
command: ''
})
continue
}
return { return {
channelConfiguration, channelConfiguration,
forbiddenWordsArray, forbiddenWordsArray,
quotesArray: [0].map(count => { quotesArray,
return { cmdsArray
displayNumber: count + 1,
fieldNumber: count,
displayHelp: count === 0
}
}),
cmdsArray: [0, 1, 2].map(count => {
return {
displayNumber: count + 1,
fieldNumber: count,
displayHelp: count === 0
}
})
} }
} }
@ -110,7 +163,9 @@ async function vivifyConfigurationChannel (
// TODO: handle form errors. // TODO: handle form errors.
for (let i = 0; data.has('forbidden_words_' + i.toString()); i++) { for (let i = 0; data.has('forbidden_words_' + i.toString()); i++) {
const entries = (data.get('forbidden_words_' + i.toString())?.toString() ?? '').split(/\r?\n|\r|\n/g) const entries = (data.get('forbidden_words_' + i.toString())?.toString() ?? '')
.split(/\r?\n|\r|\n/g)
.filter(s => !/^\s*$/.test(s)) // filtering empty lines
const regexp = data.get('forbidden_words_regexp_' + i.toString()) const regexp = data.get('forbidden_words_regexp_' + i.toString())
const applyToModerators = data.get('forbidden_words_applytomoderators_' + i.toString()) const applyToModerators = data.get('forbidden_words_applytomoderators_' + i.toString())
const reason = data.get('forbidden_words_reason_' + i.toString())?.toString() const reason = data.get('forbidden_words_reason_' + i.toString())?.toString()
@ -125,7 +180,31 @@ async function vivifyConfigurationChannel (
channelConfigurationOptions.bot.forbiddenWords.push(fw) channelConfigurationOptions.bot.forbiddenWords.push(fw)
} }
// TODO: quotes and commands. for (let i = 0; data.has('quote_' + i.toString()); i++) {
const messages = (data.get('quote_' + i.toString())?.toString() ?? '')
.split(/\r?\n|\r|\n/g)
.filter(s => !/^\s*$/.test(s)) // filtering empty lines
let delay = parseInt(data.get('quote_delay_' + i.toString())?.toString() ?? '')
if (!delay || isNaN(delay) || delay < 1) {
delay = 5
}
delay = delay * 60 // converting to seconds
const q: ChannelConfigurationOptions['bot']['quotes'][0] = {
messages,
delay
}
channelConfigurationOptions.bot.quotes.push(q)
}
for (let i = 0; data.has('command_' + i.toString()); i++) {
const command = (data.get('command_' + i.toString())?.toString() ?? '')
const message = (data.get('command_message_' + i.toString())?.toString() ?? '')
const c: ChannelConfigurationOptions['bot']['commands'][0] = {
command,
message
}
channelConfigurationOptions.bot.commands.push(c)
}
const headers: any = clientOptions.peertubeHelpers.getAuthHeader() ?? {} const headers: any = clientOptions.peertubeHelpers.getAuthHeader() ?? {}
headers['content-type'] = 'application/json;charset=UTF-8' headers['content-type'] = 'application/json;charset=UTF-8'

View File

@ -103,6 +103,21 @@ class BotConfiguration {
return singleton return singleton
} }
/**
* Get the current room conf content.
* @param roomJIDParam room JID (local or full)
* @returns the room conf, or null if does not exist
*/
public async getRoom (roomJIDParam: string): Promise<ChannelCommonRoomConf | null> {
const roomJID = this._canonicJID(roomJIDParam)
if (!roomJID) {
this.logger.error('Invalid room JID')
return null
}
const conf = await this._getRoomConf(roomJID)
return conf
}
/** /**
* Update the bot configuration for a given room. * Update the bot configuration for a given room.
* @param roomJIDParam Room full or local JID * @param roomJIDParam Room full or local JID

View File

@ -166,9 +166,9 @@ function _readQuotes (botData: any): ChannelConfigurationOptions['bot']['quotes'
throw new Error('Invalid quotes data') throw new Error('Invalid quotes data')
} }
const result: ChannelConfigurationOptions['bot']['quotes'] = [] const result: ChannelConfigurationOptions['bot']['quotes'] = []
for (const fw of botData.quotes) { for (const qs of botData.quotes) {
const messages = _readStringArray(fw, 'message') const messages = _readStringArray(qs, 'messages')
const delay = _readInteger(fw, 'delay', 1, 6000) const delay = _readInteger(qs, 'delay', 1, 6000)
result.push({ result.push({
messages, messages,
@ -183,9 +183,9 @@ function _readCommands (botData: any): ChannelConfigurationOptions['bot']['comma
throw new Error('Invalid commands data') throw new Error('Invalid commands data')
} }
const result: ChannelConfigurationOptions['bot']['commands'] = [] const result: ChannelConfigurationOptions['bot']['commands'] = []
for (const fw of botData.commands) { for (const cs of botData.commands) {
const message = _readSimpleInput(fw, 'message') const message = _readSimpleInput(cs, 'message')
const command = _readSimpleInput(fw, 'command') const command = _readSimpleInput(cs, 'command')
result.push({ result.push({
message, message,

View File

@ -39,39 +39,9 @@ function getDefaultChannelConfigurationOptions (_options: RegisterServerOptions)
bot: { bot: {
enabled: false, enabled: false,
nickname: 'Sepia', nickname: 'Sepia',
// Note: we are instanciating several data for forbiddenWords, quotes and commands. forbiddenWords: [],
// This will be used by the frontend to instanciates requires fields quotes: [],
forbiddenWords: [ commands: []
{
entries: []
},
{
entries: []
},
{
entries: []
}
],
quotes: [
{
messages: [],
delay: 5 * 60 // seconds to minutes
}
],
commands: [
{
command: '',
message: ''
},
{
command: '',
message: ''
},
{
command: '',
message: ''
}
]
} }
} }
} }
@ -109,22 +79,47 @@ async function storeChannelConfigurationOptions (
* Converts the channel configuration to the bot room configuration object (minus the room JID and domain) * Converts the channel configuration to the bot room configuration object (minus the room JID and domain)
* @param options server options * @param options server options
* @param channelConfigurationOptions The channel configuration * @param channelConfigurationOptions The channel configuration
* @param previousRoomConf the previous saved room conf, if available. Used to merge handlers.
* @returns Partial bot room configuration * @returns Partial bot room configuration
*/ */
function channelConfigurationOptionsToBotRoomConf ( function channelConfigurationOptionsToBotRoomConf (
options: RegisterServerOptions, options: RegisterServerOptions,
channelConfigurationOptions: ChannelConfigurationOptions channelConfigurationOptions: ChannelConfigurationOptions,
previousRoomConf: ChannelCommonRoomConf | null
): ChannelCommonRoomConf { ): ChannelCommonRoomConf {
// Note concerning handlers: // Note concerning handlers:
// If we want the bot to correctly enable/disable the handlers, // If we want the bot to correctly enable/disable the handlers,
// we must always define all handlers, even if not used. // we must always define all handlers, even if not used.
// That's why we are gathering handlers ids in handlersId, and disabling missing handlers at the end of this function.
const handlersIds: Map<string, true> = new Map<string, true>()
const handlers: ConfigHandlers = [] const handlers: ConfigHandlers = []
channelConfigurationOptions.bot.forbiddenWords.forEach((v, i) => { channelConfigurationOptions.bot.forbiddenWords.forEach((v, i) => {
handlers.push(_getForbiddenWordsHandler( const id = 'forbidden_words_' + i.toString()
'forbidden_words_' + i.toString(), handlersIds.set(id, true)
channelConfigurationOptions.bot.forbiddenWords[i] handlers.push(_getForbiddenWordsHandler(id, v))
))
}) })
channelConfigurationOptions.bot.quotes.forEach((v, i) => {
const id = 'quote_' + i.toString()
handlersIds.set(id, true)
handlers.push(_getQuotesHandler(id, v))
})
channelConfigurationOptions.bot.commands.forEach((v, i) => {
const id = 'command_' + i.toString()
handlersIds.set(id, true)
handlers.push(_getCommandsHandler(id, v))
})
// Disabling missing handlers:
if (previousRoomConf) {
for (const handler of previousRoomConf.handlers) {
if (!handlersIds.has(handler.id)) {
// cloning to avoid issues...
const disabledHandler = JSON.parse(JSON.stringify(handler))
disabledHandler.enabled = false
handlers.push(disabledHandler)
}
}
}
const roomConf: ChannelCommonRoomConf = { const roomConf: ChannelCommonRoomConf = {
enabled: channelConfigurationOptions.bot.enabled, enabled: channelConfigurationOptions.bot.enabled,
@ -192,6 +187,52 @@ function _getForbiddenWordsHandler (
return handler return handler
} }
function _getQuotesHandler (
id: string,
quotes: ChannelConfigurationOptions['bot']['quotes'][0]
): ConfigHandler {
const handler: ConfigHandler = {
type: 'quotes_random',
id,
enabled: false,
options: {
quotes: [],
delay: 5 * 60
}
}
if (quotes.messages.length === 0) {
return handler
}
handler.enabled = true
handler.options.quotes = quotes.messages
handler.options.delay = quotes.delay
return handler
}
function _getCommandsHandler (
id: string,
command: ChannelConfigurationOptions['bot']['commands'][0]
): ConfigHandler {
const handler: ConfigHandler = {
type: 'command_say',
id,
enabled: false,
options: {
quotes: [],
command: 'undefined' // This is arbitrary, and does not matter as enabled=false
}
}
if (!command.message || command.message === '') {
return handler
}
handler.enabled = true
handler.options.command = command.command
handler.options.quotes = [command.message]
return handler
}
const stringToWordRegexpSpecials = [ const stringToWordRegexpSpecials = [
// order matters for these // order matters for these
'-', '[', ']', '-', '[', ']',

View File

@ -334,12 +334,13 @@ class RoomChannel {
} }
this.logger.info(`Room ${roomJID} has associated channel options, writing it`) this.logger.info(`Room ${roomJID} has associated channel options, writing it`)
const previousRoomConf = await BotConfiguration.singleton().getRoom(roomJID)
const botConf: RoomConf = Object.assign( const botConf: RoomConf = Object.assign(
{ {
local: roomJID, local: roomJID,
domain: this.mucDomain domain: this.mucDomain
}, },
channelConfigurationOptionsToBotRoomConf(this.options, channelConfigurationOptions) channelConfigurationOptionsToBotRoomConf(this.options, channelConfigurationOptions, previousRoomConf)
) )
await BotConfiguration.singleton().updateRoom(roomJID, botConf) await BotConfiguration.singleton().updateRoom(roomJID, botConf)