Custom channel emoticons WIP (#130) + various fix/refactoring
This commit is contained in:
@ -1,13 +1,13 @@
|
||||
// SPDX-FileCopyrightText: 2024 Mehdi Benadel <https://mehdibenadel.com>
|
||||
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
||||
import type { ValidationError } from '../../lib/models/validation'
|
||||
import type {
|
||||
ChannelLiveChatInfos, ChannelConfiguration, ChannelConfigurationOptions, ChannelEmojisConfiguration
|
||||
ChannelLiveChatInfos, ChannelConfiguration, ChannelConfigurationOptions, ChannelEmojisConfiguration, ChannelEmojis
|
||||
} from 'shared/lib/types'
|
||||
import { ValidationErrorType } from '../../lib/models/validation'
|
||||
import { ValidationError, ValidationErrorType } from '../../lib/models/validation'
|
||||
import { getBaseRoute } from '../../../utils/uri'
|
||||
|
||||
export class ChannelDetailsService {
|
||||
@ -22,53 +22,46 @@ export class ChannelDetailsService {
|
||||
this._headers['content-type'] = 'application/json;charset=UTF-8'
|
||||
}
|
||||
|
||||
validateOptions = (channelConfigurationOptions: ChannelConfigurationOptions): boolean => {
|
||||
let hasErrors = false
|
||||
const validationError: ValidationError = {
|
||||
name: 'ChannelConfigurationOptionsValidationError',
|
||||
message: 'There was an error during validation',
|
||||
properties: {}
|
||||
}
|
||||
validateOptions = async (channelConfigurationOptions: ChannelConfigurationOptions): Promise<boolean> => {
|
||||
const propertiesError: ValidationError['properties'] = {}
|
||||
|
||||
const botConf = channelConfigurationOptions.bot
|
||||
const slowModeDuration = channelConfigurationOptions.slowMode.duration
|
||||
|
||||
validationError.properties['slowMode.duration'] = []
|
||||
propertiesError['slowMode.duration'] = []
|
||||
|
||||
if (
|
||||
(typeof slowModeDuration !== 'number') ||
|
||||
isNaN(slowModeDuration)) {
|
||||
validationError.properties['slowMode.duration'].push(ValidationErrorType.WrongType)
|
||||
hasErrors = true
|
||||
isNaN(slowModeDuration)
|
||||
) {
|
||||
propertiesError['slowMode.duration'].push(ValidationErrorType.WrongType)
|
||||
} else if (
|
||||
slowModeDuration < 0 ||
|
||||
slowModeDuration > 1000
|
||||
) {
|
||||
validationError.properties['slowMode.duration'].push(ValidationErrorType.NotInRange)
|
||||
hasErrors = true
|
||||
propertiesError['slowMode.duration'].push(ValidationErrorType.NotInRange)
|
||||
}
|
||||
|
||||
// If !bot.enabled, we don't have to validate these fields:
|
||||
// The backend will ignore those values.
|
||||
if (botConf.enabled) {
|
||||
validationError.properties['bot.nickname'] = []
|
||||
propertiesError['bot.nickname'] = []
|
||||
|
||||
if (/[^\p{L}\p{N}\p{Z}_-]/u.test(botConf.nickname ?? '')) {
|
||||
validationError.properties['bot.nickname'].push(ValidationErrorType.WrongFormat)
|
||||
hasErrors = true
|
||||
propertiesError['bot.nickname'].push(ValidationErrorType.WrongFormat)
|
||||
}
|
||||
|
||||
for (const [i, fw] of botConf.forbiddenWords.entries()) {
|
||||
for (const v of fw.entries) {
|
||||
validationError.properties[`bot.forbiddenWords.${i}.entries`] = []
|
||||
propertiesError[`bot.forbiddenWords.${i}.entries`] = []
|
||||
if (fw.regexp) {
|
||||
if (v.trim() !== '') {
|
||||
try {
|
||||
// eslint-disable-next-line no-new
|
||||
new RegExp(v)
|
||||
} catch (_) {
|
||||
validationError.properties[`bot.forbiddenWords.${i}.entries`]
|
||||
propertiesError[`bot.forbiddenWords.${i}.entries`]
|
||||
.push(ValidationErrorType.WrongFormat)
|
||||
hasErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,16 +69,20 @@ export class ChannelDetailsService {
|
||||
}
|
||||
|
||||
for (const [i, cd] of botConf.commands.entries()) {
|
||||
validationError.properties[`bot.commands.${i}.command`] = []
|
||||
propertiesError[`bot.commands.${i}.command`] = []
|
||||
|
||||
if (/\s+/.test(cd.command)) {
|
||||
validationError.properties[`bot.commands.${i}.command`].push(ValidationErrorType.WrongFormat)
|
||||
hasErrors = true
|
||||
propertiesError[`bot.commands.${i}.command`].push(ValidationErrorType.WrongFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasErrors) {
|
||||
if (Object.values(propertiesError).find(e => e.length > 0)) {
|
||||
const validationError = new ValidationError(
|
||||
'ChannelConfigurationOptionsValidationError',
|
||||
await this._registerClientOptions.peertubeHelpers.translate(LOC_VALIDATION_ERROR),
|
||||
propertiesError
|
||||
)
|
||||
throw validationError
|
||||
}
|
||||
|
||||
@ -161,7 +158,7 @@ export class ChannelDetailsService {
|
||||
return response.json()
|
||||
}
|
||||
|
||||
fetchEmojisConfiguration = async (channelId: number): Promise<ChannelEmojisConfiguration> => {
|
||||
public async fetchEmojisConfiguration (channelId: number): Promise<ChannelEmojisConfiguration> {
|
||||
const response = await fetch(
|
||||
getBaseRoute(this._registerClientOptions) +
|
||||
'/api/configuration/channel/emojis/' +
|
||||
@ -181,4 +178,56 @@ export class ChannelDetailsService {
|
||||
|
||||
return response.json()
|
||||
}
|
||||
|
||||
public async validateEmojisConfiguration (channelEmojis: ChannelEmojis): Promise<boolean> {
|
||||
const propertiesError: ValidationError['properties'] = {}
|
||||
|
||||
for (const [i, e] of channelEmojis.customEmojis.entries()) {
|
||||
propertiesError[`emojis.${i}.sn`] = []
|
||||
// FIXME: the ":" should not be in the value, but added afterward.
|
||||
if (!/^:[\w-]+:$/.test(e.sn)) {
|
||||
propertiesError[`emojis.${i}.sn`].push(ValidationErrorType.WrongFormat)
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.values(propertiesError).find(e => e.length > 0)) {
|
||||
const validationError = new ValidationError(
|
||||
'ChannelEmojisValidationError',
|
||||
await this._registerClientOptions.peertubeHelpers.translate(LOC_VALIDATION_ERROR),
|
||||
propertiesError
|
||||
)
|
||||
throw validationError
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public async saveEmojisConfiguration (
|
||||
channelId: number,
|
||||
channelEmojis: ChannelEmojis
|
||||
): Promise<void> {
|
||||
if (!await this.validateEmojisConfiguration(channelEmojis)) {
|
||||
throw new Error('Invalid form data')
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
getBaseRoute(this._registerClientOptions) +
|
||||
'/api/configuration/channel/emojis/' +
|
||||
encodeURIComponent(channelId),
|
||||
{
|
||||
method: 'POST',
|
||||
headers: this._headers,
|
||||
body: JSON.stringify(channelEmojis)
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
// File does not exist yet, that is a normal use case.
|
||||
}
|
||||
throw new Error('Can\'t get channel emojis options.')
|
||||
}
|
||||
|
||||
return response.json()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user