Emoji only mode WIP
This commit is contained in:
parent
2f78b901e3
commit
1a75b30c50
@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 11.1.0 (Not Released Yet)
|
||||
|
||||
### New features
|
||||
|
||||
* #131: Emoji only mode.
|
||||
|
||||
## 11.0.1
|
||||
|
||||
### Minor changes and fixes
|
||||
|
@ -10,12 +10,12 @@ set -euo pipefail
|
||||
# This script download the Prosody AppImage from the https://github.com/JohnXLivingston/prosody-appimage project.
|
||||
|
||||
repo_base_url='https://github.com/JohnXLivingston/prosody-appimage/releases/download'
|
||||
wanted_release='v0.12.3-1'
|
||||
wanted_release='v0.12.4-2'
|
||||
|
||||
x86_64_filename='prosody-x86_64.AppImage'
|
||||
x86_64_sha256sum='f4af9bfefa2f804ad7e8b03a68f04194abb801f070ae620b3d4bcedb144e8523'
|
||||
x86_64_sha256sum='664d9f3b1ea6dc5fdbe29ef8e8b4c0655abdff697e8c94bfecc894ef2c2fea08'
|
||||
aarch64_filename='prosody-aarch64.AppImage'
|
||||
aarch64_sha256sum='878c5be719e1e36a84d637fd2bd44e3059aa91ddb6906ad05f1dd0334078df09'
|
||||
aarch64_sha256sum='9911c0d581a92a817e9795a7944773a07e85151127233a2e551eb07dc4c44fb5'
|
||||
|
||||
download_dir="$(pwd)/vendor/prosody-appimage"
|
||||
dist_dir="$(pwd)/dist/server/prosody"
|
||||
|
@ -40,6 +40,7 @@ if [ -n "$CONVERSE_COMMIT" ]; then
|
||||
fi
|
||||
converse_build_dir="$rootdir/build/conversejs"
|
||||
converse_destination_dir="$rootdir/dist/client/conversejs"
|
||||
converse_emoji_destination="$rootdir/dist/converse-emoji.json"
|
||||
|
||||
if [[ ! -d $src_dir ]]; then
|
||||
echo "$0 must be called from the plugin livechat root dir."
|
||||
@ -119,6 +120,9 @@ cd $rootdir
|
||||
echo "Copying ConverseJS dist files..."
|
||||
mkdir -p "$converse_destination_dir" && cp -r $converse_build_dir/dist/* "$converse_destination_dir/"
|
||||
|
||||
echo "Copying ConverseJS original emoji.json file..." # this is needed for some backend code.
|
||||
cp "$converse_build_dir/src/headless/plugins/emoji/emoji.json" "$converse_emoji_destination"
|
||||
|
||||
echo "ConverseJS OK."
|
||||
|
||||
exit 0
|
||||
|
@ -66,6 +66,7 @@ CORE_PLUGINS.push('livechat-converse-mam-search')
|
||||
// We must also add our custom ROOM_FEATURES, so that they correctly resets
|
||||
// (see headless/plugins/muc, getDiscoInfoFeatures, which loops on this const)
|
||||
ROOM_FEATURES.push('x_peertubelivechat_mute_anonymous')
|
||||
ROOM_FEATURES.push('x_peertubelivechat_emoji_only_mode')
|
||||
|
||||
_converse.exports.CustomElement = CustomElement
|
||||
|
||||
|
@ -35,6 +35,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Emoji only info box
|
||||
.livechat-emoji-only-info-box {
|
||||
border: 1px dashed var(--peertube-menu-background);
|
||||
color: var(--peertube-main-foreground);
|
||||
background-color: var(--peertube-main-background);
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
converse-chat-toolbar {
|
||||
border-top: none !important; // removing border, to avoid confusing the toolbar with an input field.
|
||||
color: var(--peertube-main-foreground);
|
||||
|
@ -83,6 +83,20 @@ const tplSlowMode = (o) => {
|
||||
return html`<livechat-slow-mode jid=${o.model.get('jid')}>`
|
||||
}
|
||||
|
||||
const tplEmojiOnly = (o) => {
|
||||
if (!o.can_post) { return html`` }
|
||||
if (!o.model.features?.get?.('x_peertubelivechat_emoji_only_mode')) {
|
||||
return ''
|
||||
}
|
||||
return html`<div class="livechat-emoji-only-info-box">
|
||||
<converse-icon class="fa fa-info-circle" size="1.2em"></converse-icon>
|
||||
${
|
||||
// eslint-disable-next-line no-undef
|
||||
__(LOC_emoji_only_info)
|
||||
}
|
||||
</div>`
|
||||
}
|
||||
|
||||
const tplViewerMode = (o) => {
|
||||
if (!api.settings.get('livechat_enable_viewer_mode')) {
|
||||
return html``
|
||||
@ -145,6 +159,7 @@ export default (o) => {
|
||||
return html`
|
||||
${tplViewerMode(o)}
|
||||
${tplSlowMode(o)}
|
||||
${tplEmojiOnly(o)}
|
||||
${
|
||||
mutedAnonymousMessage
|
||||
? html`<span class="muc-bottom-panel muc-bottom-panel--muted">${mutedAnonymousMessage}</span>`
|
||||
|
@ -9,6 +9,7 @@ import { chatRoomOverrides } from './livechat-specific/chatroom'
|
||||
import { chatRoomMessageOverrides } from './livechat-specific/chatroom-message'
|
||||
import { customizeMessageAction } from './livechat-specific/message-action'
|
||||
import { customizeProfileModal } from './livechat-specific/profile'
|
||||
import { customizeMUCBottomPanel } from './livechat-specific/muc-bottom-panel'
|
||||
|
||||
export const livechatSpecificsPlugin = {
|
||||
dependencies: ['converse-muc', 'converse-muc-views'],
|
||||
@ -26,6 +27,7 @@ export const livechatSpecificsPlugin = {
|
||||
customizeToolbar(this)
|
||||
customizeMessageAction(this)
|
||||
customizeProfileModal(this)
|
||||
customizeMUCBottomPanel(this)
|
||||
|
||||
_converse.api.listen.on('chatRoomViewInitialized', function (this: any, _model: any): void {
|
||||
// Remove the spinner if present...
|
||||
|
23
conversejs/lib/plugins/livechat-specific/muc-bottom-panel.ts
Normal file
23
conversejs/lib/plugins/livechat-specific/muc-bottom-panel.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/**
|
||||
* Override the MUCBottomPanel custom element
|
||||
*/
|
||||
export function customizeMUCBottomPanel (plugin: any): void {
|
||||
const _converse = plugin._converse
|
||||
const MUCBottomPanel = _converse.api.elements.registry['converse-muc-bottom-panel']
|
||||
if (MUCBottomPanel) {
|
||||
class MUCBottomPanelOverloaded extends MUCBottomPanel {
|
||||
async initialize (): Promise<any> {
|
||||
await super.initialize()
|
||||
// We must refresh the bottom panel when these features changes (to display the infobox)
|
||||
// FIXME: the custom muc-bottom-panel template should be used here, in an overloaded render method, instead
|
||||
// of using webpack to overload the original file.
|
||||
this.listenTo(this.model.features, 'change:x_peertubelivechat_emoji_only_mode', () => this.requestUpdate())
|
||||
}
|
||||
}
|
||||
_converse.api.elements.define('converse-muc-bottom-panel', MUCBottomPanelOverloaded)
|
||||
}
|
||||
}
|
@ -62,7 +62,8 @@ const locKeys = [
|
||||
'moderator_note_original_nick',
|
||||
'search_occupant_message',
|
||||
'message_search',
|
||||
'message_search_original_nick'
|
||||
'message_search_original_nick',
|
||||
'emoji_only_info'
|
||||
]
|
||||
|
||||
module.exports = locKeys
|
||||
|
@ -636,3 +636,5 @@ prosody_firewall_name_desc: |
|
||||
Can only contain: alphanumerical characters, underscores and hyphens.
|
||||
Scripts will be loaded in alphabetical order.
|
||||
prosody_firewall_content: File content
|
||||
|
||||
emoji_only_info: Emoji only mode is enabled, you can only use emoji in your messages.
|
||||
|
@ -16,6 +16,9 @@ module:depends"http";
|
||||
|
||||
local mod_muc_peertubelivechat_terms = module:depends"muc_peertubelivechat_terms";
|
||||
local set_muc_terms = rawget(mod_muc_peertubelivechat_terms, "set_muc_terms");
|
||||
local mod_muc_peertubelivechat_restrict_message = module:depends"muc_peertubelivechat_restrict_message";
|
||||
local set_peertubelivechat_emoji_only_mode = rawget(mod_muc_peertubelivechat_restrict_message, "set_peertubelivechat_emoji_only_mode");
|
||||
local set_peertubelivechat_emoji_only_regexp = rawget(mod_muc_peertubelivechat_restrict_message, "set_peertubelivechat_emoji_only_regexp");
|
||||
|
||||
function check_auth(routes)
|
||||
local function check_request_auth(event)
|
||||
@ -102,6 +105,16 @@ local function update_room(event)
|
||||
room._data.moderation_delay = config.moderation_delay;
|
||||
end
|
||||
end
|
||||
if type(config.livechat_emoji_only) == "boolean" then
|
||||
if set_peertubelivechat_emoji_only_mode then
|
||||
set_peertubelivechat_emoji_only_mode(room, config.livechat_emoji_only)
|
||||
end
|
||||
end
|
||||
if type(config.livechat_emoji_only_regexp) == "string" then
|
||||
if set_peertubelivechat_emoji_only_mode then
|
||||
set_peertubelivechat_emoji_only_regexp(room, config.livechat_emoji_only_regexp)
|
||||
end
|
||||
end
|
||||
if (type(config.livechat_muc_terms) == "string") then
|
||||
-- to easily detect if the value is given or not, we consider that the caller passes "" when terms must be deleted.
|
||||
if set_muc_terms then
|
||||
|
@ -9,6 +9,9 @@
|
||||
-- * "mute_anonymous"
|
||||
-- * "moderation_delay"
|
||||
-- * "anonymize_moderation_actions"
|
||||
-- * "livechat_emoji_only"
|
||||
-- * "livechat_emoji_only_regexp"
|
||||
-- * "livechat_muc_terms"
|
||||
-- These options are introduced in the Peertube livechat plugin.
|
||||
--
|
||||
-- The "slow_mode_duration" comes with mod_muc_slow_mode.
|
||||
@ -128,6 +131,12 @@ local function apply_config(room, settings)
|
||||
if (type(config.mute_anonymous) == "boolean") then
|
||||
room._data.x_peertubelivechat_mute_anonymous = config.mute_anonymous;
|
||||
end
|
||||
if (type(config.livechat_emoji_only) == "boolean") then
|
||||
room._data.x_peertubelivechat_emoji_only_mode = config.livechat_emoji_only;
|
||||
end
|
||||
if (type(config.livechat_emoji_only_regexp) == "string" and config.livechat_emoji_only_regexp ~= "") then
|
||||
room._data.x_peertubelivechat_emoji_only_regexp = config.emoji_only_regexp;
|
||||
end
|
||||
if (type(config.livechat_muc_terms) == "string") then
|
||||
-- we don't need to use set_muc_terms here, as this is called for a newly created room
|
||||
-- (and thus we don't need to broadcast changes)
|
||||
|
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
# mod_muc_peertubelivechat_restrict_message
|
||||
|
||||
This module is a custom module designed for the peertube-plugin-livechat project, that can restrict message content to
|
||||
given regular expression.
|
||||
|
||||
This module is part of peertube-plugin-livechat, and is under the same LICENSE (AGPL-v3).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This modules needs lrexlib instlaled (available as lua-rex-pcre2 package on Debian).
|
@ -0,0 +1,131 @@
|
||||
-- mod_muc_peertubelivechat_roles
|
||||
--
|
||||
-- SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||
-- SPDX-License-Identifier: AGPL-3.0-only
|
||||
--
|
||||
-- This file is AGPL-v3 licensed.
|
||||
-- Please see the Peertube livechat plugin copyright information.
|
||||
-- https://livingston.frama.io/peertube-plugin-livechat/credits/
|
||||
--
|
||||
|
||||
local st = require "util.stanza";
|
||||
local jid_bare = require "util.jid".bare;
|
||||
|
||||
local rex = require "rex_pcre2"; -- We are using PCRE2 (Perl Compatible Regular Expression)
|
||||
|
||||
-- Plugin dependencies
|
||||
local mod_muc = module:depends "muc";
|
||||
local muc_util = module:require "muc/util";
|
||||
local valid_roles = muc_util.valid_roles;
|
||||
|
||||
|
||||
function get_peertubelivechat_emoji_only_mode(room)
|
||||
return room._data.x_peertubelivechat_emoji_only_mode;
|
||||
end
|
||||
|
||||
function set_peertubelivechat_emoji_only_mode(room, emoji_only)
|
||||
emoji_only = emoji_only and true or nil;
|
||||
if get_peertubelivechat_emoji_only_mode(room) == emoji_only then return false; end
|
||||
room._data.x_peertubelivechat_emoji_only_mode = emoji_only;
|
||||
return true;
|
||||
end
|
||||
|
||||
function get_peertubelivechat_emoji_only_regexp(room)
|
||||
return room._data.x_peertubelivechat_emoji_only_regexp;
|
||||
end
|
||||
|
||||
function set_peertubelivechat_emoji_only_regexp(room, emoji_only_regexp)
|
||||
if (emoji_only_regexp ~= nil and type(emoji_only_regexp) ~= "string") then
|
||||
return false;
|
||||
end
|
||||
if emoji_only_regexp == "" then emoji_only_regexp = nil; end
|
||||
if get_peertubelivechat_emoji_only_regexp(room) == emoji_only_regexp then return false; end
|
||||
room._data.x_peertubelivechat_emoji_only_regexp = emoji_only_regexp;
|
||||
|
||||
-- and we must decache the compile regexp
|
||||
room.x_peertubelivechat_emoji_only_compiled_regexp = nil;
|
||||
return true;
|
||||
end
|
||||
|
||||
module:hook("muc-disco#info", function(event)
|
||||
if get_peertubelivechat_emoji_only_mode(event.room) and get_peertubelivechat_emoji_only_regexp(event.room) ~= nil then
|
||||
event.reply:tag("feature", {var = "x_peertubelivechat_emoji_only_mode"}):up();
|
||||
end
|
||||
end);
|
||||
|
||||
module:hook("muc-config-form", function(event)
|
||||
if (get_peertubelivechat_emoji_only_regexp(event.room) ~= nil) then
|
||||
table.insert(event.form, {
|
||||
name = "muc#roomconfig_x_peertubelivechat_emoji_only_mode";
|
||||
type = "boolean";
|
||||
label = "Emoji only mode";
|
||||
desc = "Occupants will only be able to send emoji. This does not affect moderators.";
|
||||
value = get_peertubelivechat_emoji_only_mode(event.room);
|
||||
});
|
||||
end
|
||||
end, 121);
|
||||
|
||||
module:hook("muc-config-submitted/muc#roomconfig_x_peertubelivechat_emoji_only_mode", function(event)
|
||||
if get_peertubelivechat_emoji_only_regexp(event.room) ~= nil and set_peertubelivechat_emoji_only_mode(event.room, event.value) then
|
||||
event.status_codes["104"] = true;
|
||||
end
|
||||
end);
|
||||
|
||||
|
||||
-- handling groupchat messages
|
||||
function handle_groupchat(event)
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
local room = event.room;
|
||||
|
||||
if (not get_peertubelivechat_emoji_only_mode(room)) then
|
||||
return;
|
||||
end
|
||||
|
||||
if not room.x_peertubelivechat_emoji_only_compiled_regexp then
|
||||
-- compute the regexp on first access
|
||||
local r = get_peertubelivechat_emoji_only_regexp(room);
|
||||
if (r == nil) then
|
||||
return;
|
||||
end
|
||||
room.x_peertubelivechat_emoji_only_compiled_regexp = rex.new(r, "i");
|
||||
end
|
||||
|
||||
-- only consider messages with body (ie: ignore chatstate and other non-text xmpp messages)
|
||||
local body = stanza:get_child_text("body")
|
||||
if not body or #body < 1 then
|
||||
-- module:log("debug", "No body, message accepted");
|
||||
return;
|
||||
end
|
||||
|
||||
-- Checking user's permissions (moderators are not subject to restrictions)
|
||||
local actor = stanza.attr.from;
|
||||
local actor_nick = room:get_occupant_jid(actor);
|
||||
local actor_jid = jid_bare(actor);
|
||||
-- Only checking role, not affiliation (restrictions only applies on users currently connected to the room)
|
||||
local role = room:get_role(actor_nick);
|
||||
if valid_roles[role or "none"] >= valid_roles.moderator then
|
||||
-- user bypasses
|
||||
-- module:log("debug", "User is moderator, bypassing restrictions");
|
||||
return;
|
||||
end
|
||||
|
||||
-- testing the content
|
||||
if (room.x_peertubelivechat_emoji_only_compiled_regexp:match(body) ~= nil) then
|
||||
-- module:log("debug", "Message accepted");
|
||||
return;
|
||||
end
|
||||
|
||||
module:log("debug", "Bouncing message for user %s", actor_nick);
|
||||
local reply = st.error_reply(
|
||||
stanza,
|
||||
-- error_type = 'modify' (see descriptions in RFC 6120 https://xmpp.org/rfcs/rfc6120.html#stanzas-error-syntax)
|
||||
"modify",
|
||||
-- error_condition = 'policy-violation' (see RFC 6120 Defined Error Conditions https://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions)
|
||||
"policy-violation",
|
||||
"Emoji only mode enabled"
|
||||
);
|
||||
|
||||
origin.send(reply);
|
||||
return true; -- stoping propagation
|
||||
end
|
||||
module:hook("muc-occupant-groupchat", handle_groupchat);
|
@ -120,6 +120,7 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
||||
// but will be more efficient to add here, as we already tested hasChat).
|
||||
// Note: no need to await here, would only degrade performances.
|
||||
// FIXME: should also update livechat_muc_terms if channel has changed.
|
||||
// FIXME: should also update livechat_emoji_only_regexp if channel has changed.
|
||||
updateProsodyRoom(options, video.uuid, {
|
||||
name: video.name
|
||||
}).then(
|
||||
|
@ -23,6 +23,7 @@ export class Emojis {
|
||||
protected channelBasePath: string
|
||||
protected channelBaseUri: string
|
||||
protected readonly channelCache = new Map<number, boolean>()
|
||||
protected readonly commonEmojisCodes: string[]
|
||||
protected readonly logger: {
|
||||
debug: (s: string) => void
|
||||
info: (s: string) => void
|
||||
@ -30,9 +31,10 @@ export class Emojis {
|
||||
error: (s: string) => void
|
||||
}
|
||||
|
||||
constructor (options: RegisterServerOptions) {
|
||||
constructor (options: RegisterServerOptions, commonEmojisCodes: string[]) {
|
||||
const logger = options.peertubeHelpers.logger
|
||||
this.options = options
|
||||
this.commonEmojisCodes = commonEmojisCodes
|
||||
this.channelBasePath = path.join(
|
||||
options.peertubeHelpers.plugin.getDataDirectoryPath(),
|
||||
'emojis',
|
||||
@ -138,9 +140,11 @@ export class Emojis {
|
||||
|
||||
/**
|
||||
* Test if short name is valid.
|
||||
*
|
||||
* @param sn short name
|
||||
*/
|
||||
public validShortName (sn: any): boolean {
|
||||
// Important note: do not change this without checking if it can breaks getChannelEmojisOnlyRegexp.
|
||||
if ((typeof sn !== 'string') || !/^:?[\w-]+:?$/.test(sn)) {
|
||||
this.logger.debug('Short name invalid: ' + (typeof sn === 'string' ? sn : '???'))
|
||||
return false
|
||||
@ -390,6 +394,40 @@ export class Emojis {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing a regular expression (Perl Compatible RE) that can validate that a message
|
||||
* contains only emojis (for this channel).
|
||||
* This is used for the emoji only mode (test are made on the Prosody server).
|
||||
*
|
||||
* @param channelId channel id
|
||||
*/
|
||||
public async getChannelEmojisOnlyRegexp (channelId: number): Promise<string | undefined> {
|
||||
const parts = [...this.commonEmojisCodes]
|
||||
if (await this.channelHasCustomEmojis(channelId)) {
|
||||
const def = await this.channelCustomEmojisDefinition(channelId)
|
||||
if (def) {
|
||||
parts.push(...def.customEmojis.map(d => d.sn))
|
||||
}
|
||||
}
|
||||
|
||||
// Note: validShortName should ensure we won't put special chars.
|
||||
// And for the common emojis, we assume that there is no special regexp chars (other that +, which will be escaped).
|
||||
const regexp = '^\\s*(?:(?:' + parts.map((s) => s.replace(/[+]/g, '\\$&')).join('|') + ')\\s*)+\\s*$'
|
||||
|
||||
// As a safety net, we check if it is a valid javascript regexp.
|
||||
try {
|
||||
const s = new RegExp(regexp)
|
||||
if (!s) {
|
||||
throw new Error('Can\'t create the RegExp from ' + regexp)
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error('Invalid Emoji Only regexp for channel ' + channelId.toString() + ': ' + regexp)
|
||||
return undefined
|
||||
}
|
||||
|
||||
return regexp
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton, of thrown an exception if it is not initialized yet.
|
||||
* Please note that this singleton won't exist if feature is disabled.
|
||||
@ -416,10 +454,14 @@ export class Emojis {
|
||||
*/
|
||||
public static async initSingleton (options: RegisterServerOptions): Promise<void> {
|
||||
const disabled = await options.settingsManager.getSetting('disable-channel-configuration')
|
||||
|
||||
// Loading common emojis codes
|
||||
const commonEmojisCodes = await _getConverseEmojiCodes(options)
|
||||
|
||||
if (disabled) {
|
||||
singleton = undefined
|
||||
} else {
|
||||
singleton = new Emojis(options)
|
||||
singleton = new Emojis(options, commonEmojisCodes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,3 +473,68 @@ export class Emojis {
|
||||
singleton = undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function _getConverseEmojiCodes (options: RegisterServerOptions): Promise<string[]> {
|
||||
try {
|
||||
// build-converse.sh copy the file emoji.json to /dist/converse-emoji.json
|
||||
const converseEmojiDefPath = path.join(__dirname, '..', '..', '..', 'converse-emoji.json')
|
||||
options.peertubeHelpers.logger.debug('Loading Converse Emojis from file ' + converseEmojiDefPath)
|
||||
|
||||
const converseEmojis: {[key: string]: any} = JSON.parse(
|
||||
await (await fs.promises.readFile(converseEmojiDefPath)).toString()
|
||||
)
|
||||
|
||||
const r = []
|
||||
for (const [key, block] of Object.entries(converseEmojis)) {
|
||||
if (key === 'custom') { continue } // These are not used.
|
||||
r.push(
|
||||
...Object.values(block)
|
||||
.map((d: any) => d.cp ? _convert(d.cp) : d.sn)
|
||||
.filter((sn: string) => sn && sn !== '')
|
||||
)
|
||||
}
|
||||
return r
|
||||
} catch (err) {
|
||||
options.peertubeHelpers.logger.error(
|
||||
'Failed to load Converse Emojis file, emoji only mode will be buggy. ' + (err as string)
|
||||
)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts unicode code points and code pairs to their respective characters.
|
||||
* See ConverseJS emoji/utils.js for more info.
|
||||
* @param {string} unicode
|
||||
*/
|
||||
function _convert (unicode: string): string {
|
||||
if (unicode.includes('-')) {
|
||||
const parts = []
|
||||
const s = unicode.split('-')
|
||||
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
const part = parseInt(s[i], 16)
|
||||
if (part >= 0x10000 && part <= 0x10FFFF) {
|
||||
const hi = Math.floor((part - 0x10000) / 0x400) + 0xD800
|
||||
const lo = ((part - 0x10000) % 0x400) + 0xDC00
|
||||
parts.push(String.fromCharCode(hi) + String.fromCharCode(lo))
|
||||
} else {
|
||||
parts.push(String.fromCharCode(part))
|
||||
}
|
||||
}
|
||||
return parts.join('')
|
||||
}
|
||||
return _fromCodePoint(unicode)
|
||||
}
|
||||
|
||||
function _fromCodePoint (codepoint: string): string {
|
||||
let code = typeof codepoint === 'string' ? parseInt(codepoint, 16) : codepoint
|
||||
if (code < 0x10000) {
|
||||
return String.fromCharCode(code)
|
||||
}
|
||||
code -= 0x10000
|
||||
return String.fromCharCode(
|
||||
0xD800 + (code >> 10),
|
||||
0xDC00 + (code & 0x3FF)
|
||||
)
|
||||
}
|
||||
|
@ -65,6 +65,8 @@ async function updateProsodyRoom (
|
||||
name?: string
|
||||
slow_mode_duration?: number
|
||||
moderation_delay?: number
|
||||
livechat_emoji_only?: boolean
|
||||
livechat_emoji_only_regexp?: string
|
||||
livechat_muc_terms?: string
|
||||
addAffiliations?: Affiliations
|
||||
removeAffiliationsFor?: string[]
|
||||
@ -100,6 +102,12 @@ async function updateProsodyRoom (
|
||||
if ('livechat_muc_terms' in data) {
|
||||
apiData.livechat_muc_terms = data.livechat_muc_terms ?? ''
|
||||
}
|
||||
if ('livechat_emoji_only' in data) {
|
||||
apiData.livechat_emoji_only = data.livechat_emoji_only ?? false
|
||||
}
|
||||
if ('livechat_emoji_only_regexp' in data) {
|
||||
apiData.livechat_emoji_only_regexp = data.livechat_emoji_only_regexp ?? ''
|
||||
}
|
||||
if (('addAffiliations' in data) && data.addAffiliations !== undefined) {
|
||||
apiData.addAffiliations = data.addAffiliations
|
||||
}
|
||||
|
@ -260,6 +260,8 @@ class ProsodyConfigContent {
|
||||
this.muc.set('anonymize_moderation_actions_form_position', 117)
|
||||
|
||||
this.muc.add('modules_enabled', 'muc_mam_search')
|
||||
|
||||
this.muc.add('modules_enabled', 'muc_peertubelivechat_restrict_message')
|
||||
}
|
||||
|
||||
useAnonymous (autoBanIP: boolean): void {
|
||||
|
@ -16,6 +16,8 @@ import {
|
||||
import { sanitizeChannelConfigurationOptions } from '../../configuration/channel/sanitize'
|
||||
import { getConverseJSParams } from '../../../lib/conversejs/params'
|
||||
import { Emojis } from '../../../lib/emojis'
|
||||
import { RoomChannel } from '../../../lib/room-channel'
|
||||
import { updateProsodyRoom } from '../../../lib/prosody/api/manage-rooms'
|
||||
|
||||
async function initConfigurationApiRouter (options: RegisterServerOptions, router: Router): Promise<void> {
|
||||
const logger = options.peertubeHelpers.logger
|
||||
@ -168,6 +170,20 @@ async function initConfigurationApiRouter (options: RegisterServerOptions, route
|
||||
|
||||
await emojis.saveChannelDefinition(channelInfos.id, emojisDefinitionSanitized, bufferInfos)
|
||||
|
||||
// We must update the emoji only regexp on the Prosody server.
|
||||
const emojisOnlyRegexp = await emojis.getChannelEmojisOnlyRegexp(channelInfos.id)
|
||||
const roomJIDs = RoomChannel.singleton().getChannelRoomJIDs(channelInfos.id)
|
||||
for (const roomJID of roomJIDs) {
|
||||
// No need to await here
|
||||
logger.info(`Updating room ${roomJID} emoji only regexp...`)
|
||||
updateProsodyRoom(options, roomJID, {
|
||||
livechat_emoji_only_regexp: emojisOnlyRegexp
|
||||
}).then(
|
||||
() => {},
|
||||
(err) => logger.error(err)
|
||||
)
|
||||
}
|
||||
|
||||
// Reloading data, to send them back to front:
|
||||
const channelEmojis =
|
||||
(await emojis.channelCustomEmojisDefinition(channelInfos.id)) ??
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
getChannelConfigurationOptions,
|
||||
getDefaultChannelConfigurationOptions
|
||||
} from '../../configuration/channel/storage'
|
||||
import { Emojis } from '../../emojis'
|
||||
|
||||
// See here for description: https://modules.prosody.im/mod_muc_http_defaults.html
|
||||
interface RoomDefaults {
|
||||
@ -37,6 +38,8 @@ interface RoomDefaults {
|
||||
// Following fields are specific to livechat (for now), and requires a customized version for mod_muc_http_defaults.
|
||||
slow_mode_duration?: number
|
||||
mute_anonymous?: boolean
|
||||
livechat_emoji_only?: boolean
|
||||
livechat_emoji_only_regexp?: string
|
||||
livechat_muc_terms?: string
|
||||
moderation_delay?: number
|
||||
anonymize_moderation_actions?: boolean
|
||||
@ -51,9 +54,12 @@ async function _getChannelSpecificOptions (
|
||||
const channelOptions = await getChannelConfigurationOptions(options, channelId) ??
|
||||
getDefaultChannelConfigurationOptions(options)
|
||||
|
||||
const emojiOnlyRegexp = await Emojis.singletonSafe()?.getChannelEmojisOnlyRegexp(channelId)
|
||||
|
||||
return {
|
||||
slow_mode_duration: channelOptions.slowMode.duration,
|
||||
mute_anonymous: channelOptions.mute.anonymous,
|
||||
livechat_emoji_only_regexp: emojiOnlyRegexp,
|
||||
livechat_muc_terms: channelOptions.terms,
|
||||
moderation_delay: channelOptions.moderation.delay,
|
||||
anonymize_moderation_actions: channelOptions.moderation.anonymize
|
||||
|
Loading…
Reference in New Issue
Block a user