Fix #87: updating chat room title when video/channel title is changed:
* renaming module list_rooms to manage_rooms * added some API to update room info * when a video or a channel is updated, sending an API call to update the room
This commit is contained in:
parent
2115b352a4
commit
4dd4f18965
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## ??? (Not Released Yet)
|
## ??? (Not Released Yet)
|
||||||
|
|
||||||
|
* Fix #87: updating chat room title when video/channel title is changed.
|
||||||
* Updating xmppjs-chat-box version.
|
* Updating xmppjs-chat-box version.
|
||||||
|
|
||||||
## 8.3.2
|
## 8.3.2
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# mod_http_peertubelivechat_list_rooms
|
# mod_http_peertubelivechat_manage_rooms
|
||||||
|
|
||||||
This module is a custom module that allows Peertube server to list chat rooms.
|
This module is a custom module that allows Peertube server to list chat rooms, and update some meta data.
|
||||||
|
|
||||||
This module is part of peertube-plugin-livechat, and is under the same LICENSE.
|
This module is part of peertube-plugin-livechat, and is under the same LICENSE.
|
@ -1,15 +1,17 @@
|
|||||||
local json = require "util.json";
|
local json = require "util.json";
|
||||||
local jid_split = require"util.jid".split;
|
local jid_split = require"util.jid".split;
|
||||||
local array = require "util.array";
|
local array = require "util.array";
|
||||||
|
local st = require "util.stanza";
|
||||||
|
|
||||||
local mod_muc = module:depends"muc";
|
local mod_muc = module:depends"muc";
|
||||||
local all_rooms = rawget(mod_muc, "all_rooms")
|
local all_rooms = rawget(mod_muc, "all_rooms");
|
||||||
|
local get_room_from_jid = rawget(mod_muc, "get_room_from_jid");
|
||||||
|
|
||||||
module:depends"http";
|
module:depends"http";
|
||||||
|
|
||||||
function check_auth(routes)
|
function check_auth(routes)
|
||||||
local function check_request_auth(event)
|
local function check_request_auth(event)
|
||||||
local apikey = module:get_option_string("peertubelivechat_list_rooms_apikey", "")
|
local apikey = module:get_option_string("peertubelivechat_manage_rooms_apikey", "")
|
||||||
if apikey == "" then
|
if apikey == "" then
|
||||||
return false, 500;
|
return false, 500;
|
||||||
end
|
end
|
||||||
@ -55,8 +57,51 @@ local function list_rooms(event)
|
|||||||
return json.encode_array(rooms_json);
|
return json.encode_array(rooms_json);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function update_room(event)
|
||||||
|
local request, response = event.request, event.response;
|
||||||
|
event.response.headers["Content-Type"] = "application/json";
|
||||||
|
|
||||||
|
local config = json.decode(request.body);
|
||||||
|
if not config.jid then
|
||||||
|
return json.encode({
|
||||||
|
result = "failed";
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
local room = get_room_from_jid(config.jid);
|
||||||
|
if not room then
|
||||||
|
return json.encode({
|
||||||
|
result = "failed";
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
local must104 = false;
|
||||||
|
|
||||||
|
if type(config.name) == "string" then
|
||||||
|
if room:get_name() ~= config.name then
|
||||||
|
room:set_name(config.name);
|
||||||
|
must104 = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if must104 then
|
||||||
|
-- we must broadcast a status 104 message, so that clients can update room info
|
||||||
|
local msg = st.message({type='groupchat', from=room.jid})
|
||||||
|
:tag('x', {xmlns='http://jabber.org/protocol/muc#user'})
|
||||||
|
msg:tag("status", {code = '104';}):up();
|
||||||
|
msg:up();
|
||||||
|
room:broadcast_message(msg);
|
||||||
|
end
|
||||||
|
|
||||||
|
return json.encode({
|
||||||
|
result = "ok";
|
||||||
|
changed = must104;
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
module:provides("http", {
|
module:provides("http", {
|
||||||
route = check_auth {
|
route = check_auth {
|
||||||
["GET /list-rooms"] = list_rooms;
|
["GET /list-rooms"] = list_rooms;
|
||||||
|
["POST /update-room"] = update_room;
|
||||||
};
|
};
|
||||||
});
|
});
|
@ -2,6 +2,8 @@ import type { RegisterServerOptions, MVideoFullLight, VideoChannel } from '@peer
|
|||||||
import { RoomChannel } from '../../room-channel'
|
import { RoomChannel } from '../../room-channel'
|
||||||
import { fillVideoCustomFields } from '../../custom-fields'
|
import { fillVideoCustomFields } from '../../custom-fields'
|
||||||
import { videoHasWebchat } from '../../../../shared/lib/video'
|
import { videoHasWebchat } from '../../../../shared/lib/video'
|
||||||
|
import { updateProsodyRoom } from '../../prosody/api/manage-rooms'
|
||||||
|
import { getChannelInfosById } from '../../database/channel'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register stuffs related to channel configuration
|
* Register stuffs related to channel configuration
|
||||||
@ -98,11 +100,48 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
|||||||
|
|
||||||
logger.debug(`Ensuring a room-channel link between room ${roomLocalPart} and channel ${video.channelId}`)
|
logger.debug(`Ensuring a room-channel link between room ${roomLocalPart} and channel ${video.channelId}`)
|
||||||
RoomChannel.singleton().link(video.channelId, roomLocalPart)
|
RoomChannel.singleton().link(video.channelId, roomLocalPart)
|
||||||
|
|
||||||
|
if (settings['prosody-room-type'] === 'video') {
|
||||||
|
// Also updating chatroom meta data.
|
||||||
|
// FIXME: this piece of code should not be in this file (nothing to do with initChannelConfiguration,
|
||||||
|
// but will be more efficient to add here, as we already tested hasChat).
|
||||||
|
// Note: no need to await here, would only degrade performances.
|
||||||
|
updateProsodyRoom(options, video.channelId, video.uuid, {
|
||||||
|
name: video.name
|
||||||
|
}).then(
|
||||||
|
() => {},
|
||||||
|
(err) => logger.error(err)
|
||||||
|
)
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
registerHook({
|
||||||
|
target: 'action:api.video-channel.updated',
|
||||||
|
handler: async (params: { videoChannel: VideoChannel }) => {
|
||||||
|
const channel = await getChannelInfosById(options, params.videoChannel.id, true)
|
||||||
|
if (!channel) { return }
|
||||||
|
|
||||||
|
// FIXME: this piece of code should not be in this file (nothing to do with initChannelConfiguration,
|
||||||
|
// but for now i keep it close to the similar code on video.updated hook).
|
||||||
|
const settings = await options.settingsManager.getSettings([
|
||||||
|
'prosody-room-type'
|
||||||
|
])
|
||||||
|
if (settings['prosody-room-type'] === 'channel') {
|
||||||
|
const jid = 'channel.' + channel.id.toString()
|
||||||
|
// Note: no need to await here, would only degrade performances.
|
||||||
|
updateProsodyRoom(options, channel.id, jid, {
|
||||||
|
name: channel.displayName
|
||||||
|
}).then(
|
||||||
|
() => {},
|
||||||
|
(err) => logger.error(err)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
|
||||||
import { getCurrentProsody } from './host'
|
|
||||||
import { getAPIKey } from '../../apikey'
|
|
||||||
const got = require('got')
|
|
||||||
|
|
||||||
interface ProsodyRoomDesc {
|
|
||||||
jid: string
|
|
||||||
localpart: string
|
|
||||||
name: string
|
|
||||||
lang: string
|
|
||||||
description: string
|
|
||||||
lasttimestamp?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
async function listProsodyRooms (options: RegisterServerOptions): Promise<ProsodyRoomDesc[]> {
|
|
||||||
const logger = options.peertubeHelpers.logger
|
|
||||||
|
|
||||||
const currentProsody = getCurrentProsody()
|
|
||||||
if (!currentProsody) {
|
|
||||||
throw new Error('It seems that prosody is not binded... Cant list rooms.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Requesting on localhost, because currentProsody.host does not always resolves correctly (docker use case, ...)
|
|
||||||
const apiUrl = `http://localhost:${currentProsody.port}/peertubelivechat_list_rooms/list-rooms`
|
|
||||||
logger.debug('Calling list rooms API on url: ' + apiUrl)
|
|
||||||
const rooms = await got(apiUrl, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
authorization: 'Bearer ' + await getAPIKey(options),
|
|
||||||
host: currentProsody.host
|
|
||||||
},
|
|
||||||
responseType: 'json',
|
|
||||||
resolveBodyOnly: true
|
|
||||||
})
|
|
||||||
|
|
||||||
return rooms
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
listProsodyRooms
|
|
||||||
}
|
|
110
server/lib/prosody/api/manage-rooms.ts
Normal file
110
server/lib/prosody/api/manage-rooms.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
||||||
|
import { getCurrentProsody } from './host'
|
||||||
|
import { getAPIKey } from '../../apikey'
|
||||||
|
import { getProsodyDomain } from '../config/domain'
|
||||||
|
const got = require('got')
|
||||||
|
|
||||||
|
interface ProsodyRoomDesc {
|
||||||
|
jid: string
|
||||||
|
localpart: string
|
||||||
|
name: string
|
||||||
|
lang: string
|
||||||
|
description: string
|
||||||
|
lasttimestamp?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists existing chatrooms.
|
||||||
|
* @param options Peertube server options
|
||||||
|
* @returns List of chat rooms on the Prosody server
|
||||||
|
*/
|
||||||
|
async function listProsodyRooms (options: RegisterServerOptions): Promise<ProsodyRoomDesc[]> {
|
||||||
|
const logger = options.peertubeHelpers.logger
|
||||||
|
|
||||||
|
const currentProsody = getCurrentProsody()
|
||||||
|
if (!currentProsody) {
|
||||||
|
throw new Error('It seems that prosody is not binded... Cant list rooms.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requesting on localhost, because currentProsody.host does not always resolves correctly (docker use case, ...)
|
||||||
|
const apiUrl = `http://localhost:${currentProsody.port}/peertubelivechat_manage_rooms/list-rooms`
|
||||||
|
logger.debug('Calling list rooms API on url: ' + apiUrl)
|
||||||
|
const rooms = await got(apiUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
authorization: 'Bearer ' + await getAPIKey(options),
|
||||||
|
host: currentProsody.host
|
||||||
|
},
|
||||||
|
responseType: 'json',
|
||||||
|
resolveBodyOnly: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return rooms
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update room metadata on the Prosody server.
|
||||||
|
* Uses an API provided by mod_http_peertubelivechat_manage_rooms.
|
||||||
|
*
|
||||||
|
* Note: could be called without verifying that the room exists.
|
||||||
|
* On the Prosody side, non existing rooms will be ignored.
|
||||||
|
* @param options Peertube server options
|
||||||
|
* @param channelId associated channelId
|
||||||
|
* @param jid Room JID (can be only the local part, or the local + domain)
|
||||||
|
* @param data Data to update
|
||||||
|
* @returns true if success
|
||||||
|
*/
|
||||||
|
async function updateProsodyRoom (
|
||||||
|
options: RegisterServerOptions,
|
||||||
|
channelId: number | string,
|
||||||
|
jid: string,
|
||||||
|
data: {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
): Promise<boolean> {
|
||||||
|
const logger = options.peertubeHelpers.logger
|
||||||
|
|
||||||
|
const currentProsody = getCurrentProsody()
|
||||||
|
if (!currentProsody) {
|
||||||
|
throw new Error('It seems that prosody is not binded... Cant update room.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jid.includes('@')) {
|
||||||
|
jid = jid + '@room.' + await getProsodyDomain(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug('Calling update room for ' + jid)
|
||||||
|
|
||||||
|
// Requesting on localhost, because currentProsody.host does not always resolves correctly (docker use case, ...)
|
||||||
|
const apiUrl = `http://localhost:${currentProsody.port}/peertubelivechat_manage_rooms/update-room`
|
||||||
|
const apiData = {
|
||||||
|
jid,
|
||||||
|
name: data.name
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
logger.debug('Calling update room API on url: ' + apiUrl + ', with data: ' + JSON.stringify(apiData))
|
||||||
|
const result = await got(apiUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
authorization: 'Bearer ' + await getAPIKey(options),
|
||||||
|
host: currentProsody.host
|
||||||
|
},
|
||||||
|
json: apiData,
|
||||||
|
responseType: 'json',
|
||||||
|
resolveBodyOnly: true
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.debug('Update room API response: ' + JSON.stringify(result))
|
||||||
|
} catch (err) {
|
||||||
|
// We consider it is not very bad if the metadata are not correctly updated.
|
||||||
|
// Nothing too important.
|
||||||
|
logger.error(`Failed to update room: ' ${err as string}`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
listProsodyRooms,
|
||||||
|
updateProsodyRoom
|
||||||
|
}
|
@ -313,7 +313,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
|||||||
// TODO: add a settings to choose?
|
// TODO: add a settings to choose?
|
||||||
config.useDefaultPersistent()
|
config.useDefaultPersistent()
|
||||||
|
|
||||||
config.useListRoomsApi(apikey)
|
config.useManageRoomsApi(apikey)
|
||||||
config.usePeertubeVCards(basePeertubeUrl)
|
config.usePeertubeVCards(basePeertubeUrl)
|
||||||
config.useAnonymousRandomVCards(paths.avatars, paths.avatarsFiles)
|
config.useAnonymousRandomVCards(paths.avatars, paths.avatarsFiles)
|
||||||
|
|
||||||
|
@ -415,9 +415,9 @@ class ProsodyConfigContent {
|
|||||||
this.muc.set('muc_room_default_persistent', true)
|
this.muc.set('muc_room_default_persistent', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
useListRoomsApi (apikey: string): void {
|
useManageRoomsApi (apikey: string): void {
|
||||||
this.muc.add('modules_enabled', 'http_peertubelivechat_list_rooms')
|
this.muc.add('modules_enabled', 'http_peertubelivechat_manage_rooms')
|
||||||
this.muc.set('peertubelivechat_list_rooms_apikey', apikey)
|
this.muc.set('peertubelivechat_manage_rooms_apikey', apikey)
|
||||||
}
|
}
|
||||||
|
|
||||||
useTestModule (prosodyApikey: string, apiurl: string): void {
|
useTestModule (prosodyApikey: string, apiurl: string): void {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
||||||
import type { RoomConf } from 'xmppjs-chat-bot'
|
import type { RoomConf } from 'xmppjs-chat-bot'
|
||||||
import { getProsodyDomain } from '../prosody/config/domain'
|
import { getProsodyDomain } from '../prosody/config/domain'
|
||||||
import { listProsodyRooms } from '../prosody/api/list-rooms'
|
import { listProsodyRooms } from '../prosody/api/manage-rooms'
|
||||||
import { getChannelInfosById } from '../database/channel'
|
import { getChannelInfosById } from '../database/channel'
|
||||||
import { ChannelConfigurationOptions } from '../../../shared/lib/types'
|
import { ChannelConfigurationOptions } from '../../../shared/lib/types'
|
||||||
import {
|
import {
|
||||||
|
@ -9,7 +9,7 @@ import { fetchMissingRemoteServerInfos } from '../federation/fetch-infos'
|
|||||||
import { getConverseJSParams } from '../conversejs/params'
|
import { getConverseJSParams } from '../conversejs/params'
|
||||||
import { setCurrentProsody, delCurrentProsody } from '../prosody/api/host'
|
import { setCurrentProsody, delCurrentProsody } from '../prosody/api/host'
|
||||||
import { getChannelInfosById } from '../database/channel'
|
import { getChannelInfosById } from '../database/channel'
|
||||||
import { listProsodyRooms } from '../prosody/api/list-rooms'
|
import { listProsodyRooms } from '../prosody/api/manage-rooms'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
const fs = require('fs').promises
|
const fs = require('fs').promises
|
||||||
|
Loading…
x
Reference in New Issue
Block a user