diff --git a/client/common/configuration/register.ts b/client/common/configuration/register.ts index 51573a9b..d4c7f9b7 100644 --- a/client/common/configuration/register.ts +++ b/client/common/configuration/register.ts @@ -1,7 +1,6 @@ import type { RegisterClientOptions } from '@peertube/peertube-types/client' import { renderConfigurationHome } from './templates/home' import { renderConfigurationChannel } from './templates/channel' -import { vivifyConfigurationChannel } from './logic/channel' /** * Registers stuff related to the user's configuration pages. @@ -25,14 +24,7 @@ async function registerConfiguration (clientOptions: RegisterClientOptions): Pro onMount: async ({ rootEl }) => { const urlParams = new URLSearchParams(window.location.search) const channelId = urlParams.get('channelId') ?? '' - const html = await renderConfigurationChannel(clientOptions, channelId) - if (!html) { - // renderConfigurationChannel has already used the notifier to display an error - rootEl.innerHTML = '' - return - } - rootEl.innerHTML = html - await vivifyConfigurationChannel(clientOptions, rootEl, channelId) + await renderConfigurationChannel(clientOptions, channelId, rootEl) } }) diff --git a/client/common/configuration/templates/channel.ts b/client/common/configuration/templates/channel.ts index b69f8d9b..4550b023 100644 --- a/client/common/configuration/templates/channel.ts +++ b/client/common/configuration/templates/channel.ts @@ -1,129 +1,29 @@ import type { RegisterClientOptions } from '@peertube/peertube-types/client' -import type { ChannelConfiguration } from 'shared/lib/types' -import { getBaseRoute } from '../../../videowatch/uri' import { localizedHelpUrl } from '../../../utils/help' import { helpButtonSVG } from '../../../videowatch/buttons' +import { vivifyConfigurationChannel, getConfigurationChannelViewData } from './logic/channel' // Must use require for mustache, import seems buggy. const Mustache = require('mustache') /** - * Renders the configuration settings page for a given channel. + * Renders the configuration settings page for a given channel, + * and set it as innerHTML to rootEl. + * The page content can be empty. In such case, the notifier will be used to display a message. * @param registerClientOptions Peertube client options * @param channelId The channel id - * @returns The page content + * @param rootEl The HTMLElement in which insert the generated DOM. */ async function renderConfigurationChannel ( registerClientOptions: RegisterClientOptions, - channelId: string -): Promise { - const { peertubeHelpers } = registerClientOptions - + channelId: string, + rootEl: HTMLElement +): Promise { try { - if (!channelId || !/^\d+$/.test(channelId)) { - throw new Error('Missing or invalid channel id.') - } + const view = await getConfigurationChannelViewData(registerClientOptions, channelId) + await fillViewHelpButtons(registerClientOptions, view) + await fillLabels(registerClientOptions, view) - const response = await fetch( - getBaseRoute(registerClientOptions) + '/api/configuration/channel/' + encodeURIComponent(channelId), - { - method: 'GET', - headers: peertubeHelpers.getAuthHeader() - } - ) - if (!response.ok) { - throw new Error('Can\'t get channel configuration options.') - } - const channelConfiguration: ChannelConfiguration = await (response).json() - - // Basic testing that channelConfiguration has the correct format - if ((typeof channelConfiguration !== 'object') || !channelConfiguration.channel) { - throw new Error('Invalid channel configuration options.') - } - - const helpUrl = await localizedHelpUrl(registerClientOptions, { - page: 'documentation/user/streamers/' // FIXME: this is not the good link - }) - const helpIcon = helpButtonSVG() - const helpButton = `${helpIcon}` - const helpButtonForbiddenWords = helpButton - const helpButtonQuotes = helpButton - const helpButtonCommands = helpButton - - const view = { - title: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_TITLE), - description: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_DESC), - enableBot: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_ENABLE_BOT_LABEL), - botOptions: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_BOT_OPTIONS_TITLE), - forbiddenWords: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL), - forbiddenWordsDesc: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC), - forbiddenWordsDesc2: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC2), - forbiddenWordsReason: await peertubeHelpers.translate( - LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_LABEL - ), - forbiddenWordsReasonDesc: await peertubeHelpers.translate( - LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_DESC - ), - forbiddenWordsRegexp: await peertubeHelpers.translate( - LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_LABEL - ), - forbiddenWordsRegexpDesc: await peertubeHelpers.translate( - LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_DESC - ), - forbiddenWordsApplyToModerators: await peertubeHelpers.translate( - LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_LABEL - ), - forbiddenWordsApplyToModeratorsDesc: await peertubeHelpers.translate( - LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_DESC - ), - quoteLabel: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_LABEL), - quoteDesc: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DESC), - quoteDesc2: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DESC2), - quoteDelayLabel: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DELAY_LABEL), - quoteDelayDesc: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DELAY_DESC), - commandLabel: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_LABEL), - commandDesc: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_DESC), - commandCmdLabel: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_CMD_LABEL), - commandCmdDesc: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_CMD_DESC), - commandMessageLabel: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_MESSAGE_LABEL), - commandMessageDesc: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_MESSAGE_DESC), - // bannedJIDs: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_BANNED_JIDS_LABEL), - save: await peertubeHelpers.translate(LOC_SAVE), - cancel: await peertubeHelpers.translate(LOC_CANCEL), - botNickname: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_BOT_NICKNAME), - moreInfo: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FOR_MORE_INFO), - forbiddenWordsArray: [0, 1, 2].map(count => { - return { - displayNumber: count + 1, - fieldNumber: count, - displayHelp: count === 0 - } - }), - quotesArray: [0].map(count => { - return { - displayNumber: count + 1, - fieldNumber: count, - displayHelp: count === 0 - } - }), - cmdsArray: [0, 1, 2].map(count => { - return { - displayNumber: count + 1, - fieldNumber: count, - displayHelp: count === 0 - } - }), - helpButton, - helpButtonForbiddenWords, - helpButtonCommands, - helpButtonQuotes, - channelConfiguration - } - - return Mustache.render(` + const content = Mustache.render(`

{{title}}: @@ -312,12 +212,84 @@ async function renderConfigurationChannel (

`, view) as string + + rootEl.innerHTML = content + + await vivifyConfigurationChannel(registerClientOptions, rootEl, channelId) } catch (err: any) { - peertubeHelpers.notifier.error(err.toString()) - return '' + registerClientOptions.peertubeHelpers.notifier.error(err.toString()) + rootEl.innerHTML = '' } } +async function fillViewHelpButtons ( + registerClientOptions: RegisterClientOptions, + view: any +): Promise { + const helpUrl = await localizedHelpUrl(registerClientOptions, { + page: 'documentation/user/streamers/' // FIXME: this is not the good link + }) + const helpIcon = helpButtonSVG() + view.helpButton = `${helpIcon}` + view.helpButtonForbiddenWords = view.helpButton // FIXME: this is not the good link + view.helpButtonQuotes = view.helpButton // FIXME: this is not the good link + view.helpButtonCommands = view.helpButton // FIXME: this is not the good link +} + +async function fillLabels ( + registerClientOptions: RegisterClientOptions, + view: any +): Promise { + const { peertubeHelpers } = registerClientOptions + view.title = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_TITLE) + view.description = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_DESC) + + view.enableBot = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_ENABLE_BOT_LABEL) + view.botOptions = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_BOT_OPTIONS_TITLE) + view.forbiddenWords = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL) + view.forbiddenWordsDesc = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC) + view.forbiddenWordsDesc2 = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC2) + view.forbiddenWordsReason = await peertubeHelpers.translate( + LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_LABEL + ) + view.forbiddenWordsReasonDesc = await peertubeHelpers.translate( + LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_DESC + ) + view.forbiddenWordsRegexp = await peertubeHelpers.translate( + LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_LABEL + ) + view.forbiddenWordsRegexpDesc = await peertubeHelpers.translate( + LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_DESC + ) + view.forbiddenWordsApplyToModerators = await peertubeHelpers.translate( + LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_LABEL + ) + view.forbiddenWordsApplyToModeratorsDesc = await peertubeHelpers.translate( + LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_DESC + ) + view.quoteLabel = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_LABEL) + view.quoteDesc = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DESC) + view.quoteDesc2 = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DESC2) + view.quoteDelayLabel = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DELAY_LABEL) + view.quoteDelayDesc = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_QUOTE_DELAY_DESC) + view.commandLabel = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_LABEL) + view.commandDesc = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_DESC) + view.commandCmdLabel = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_CMD_LABEL) + view.commandCmdDesc = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_CMD_DESC) + view.commandMessageLabel = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_MESSAGE_LABEL) + view.commandMessageDesc = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_MESSAGE_DESC) + // view.bannedJIDs = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_BANNED_JIDS_LABEL) + + view.save = await peertubeHelpers.translate(LOC_SAVE) + view.cancel = await peertubeHelpers.translate(LOC_CANCEL) + view.botNickname = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_BOT_NICKNAME) + view.moreInfo = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FOR_MORE_INFO) +} + export { renderConfigurationChannel } diff --git a/client/common/configuration/logic/channel.ts b/client/common/configuration/templates/logic/channel.ts similarity index 62% rename from client/common/configuration/logic/channel.ts rename to client/common/configuration/templates/logic/channel.ts index 074dfeb9..d1b4eff4 100644 --- a/client/common/configuration/logic/channel.ts +++ b/client/common/configuration/templates/logic/channel.ts @@ -1,6 +1,63 @@ import type { RegisterClientOptions } from '@peertube/peertube-types/client' -import type { ChannelConfigurationOptions } from 'shared/lib/types' -import { getBaseRoute } from '../../../videowatch/uri' +import type { ChannelConfiguration, ChannelConfigurationOptions } from 'shared/lib/types' +import { getBaseRoute } from '../../../../videowatch/uri' + +/** + * Returns the data that can be feed into the template view + * @param registerClientOptions + * @param channelId + */ +async function getConfigurationChannelViewData ( + registerClientOptions: RegisterClientOptions, + channelId: string +): Promise { + if (!channelId || !/^\d+$/.test(channelId)) { + throw new Error('Missing or invalid channel id.') + } + + const { peertubeHelpers } = registerClientOptions + const response = await fetch( + getBaseRoute(registerClientOptions) + '/api/configuration/channel/' + encodeURIComponent(channelId), + { + method: 'GET', + headers: peertubeHelpers.getAuthHeader() + } + ) + if (!response.ok) { + throw new Error('Can\'t get channel configuration options.') + } + const channelConfiguration: ChannelConfiguration = await (response).json() + + // Basic testing that channelConfiguration has the correct format + if ((typeof channelConfiguration !== 'object') || !channelConfiguration.channel) { + throw new Error('Invalid channel configuration options.') + } + + return { + channelConfiguration, + forbiddenWordsArray: [0, 1, 2].map(count => { + return { + displayNumber: count + 1, + fieldNumber: count, + displayHelp: count === 0 + } + }), + quotesArray: [0].map(count => { + return { + displayNumber: count + 1, + fieldNumber: count, + displayHelp: count === 0 + } + }), + cmdsArray: [0, 1, 2].map(count => { + return { + displayNumber: count + 1, + fieldNumber: count, + displayHelp: count === 0 + } + }) + } +} /** * Adds the front-end logic on the generated html for the channel configuration options. @@ -87,5 +144,6 @@ async function vivifyConfigurationChannel ( } export { + getConfigurationChannelViewData, vivifyConfigurationChannel } diff --git a/server/lib/routers/api/configuration.ts b/server/lib/routers/api/configuration.ts index 4db99d41..5eca59af 100644 --- a/server/lib/routers/api/configuration.ts +++ b/server/lib/routers/api/configuration.ts @@ -52,6 +52,9 @@ async function initConfigurationApiRouter (options: RegisterServerOptions, route let channelOptions try { + // Note: the front-end should do some input validation. + // If there is any invalid value, we just return a 400 error. + // The frontend should have prevented to post invalid data. channelOptions = await sanitizeChannelConfigurationOptions(options, channelInfos.id, req.body) } catch (err) { logger.warn(err)