Room list: handle channel rooms.

This commit is contained in:
John Livingston 2021-08-05 18:25:27 +02:00
parent 855ed51251
commit e9d1e55084
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
4 changed files with 95 additions and 26 deletions

View File

@ -85,6 +85,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
RoomDescription: 'Room description', RoomDescription: 'Room description',
NotFound: 'Not found', NotFound: 'Not found',
Video: 'Video', Video: 'Video',
Channel: 'Channel',
LastActivity: 'Last activity' LastActivity: 'Last activity'
} }
@ -94,7 +95,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
const titleDescriptionEl = document.createElement('th') const titleDescriptionEl = document.createElement('th')
titleDescriptionEl.textContent = labels.RoomDescription titleDescriptionEl.textContent = labels.RoomDescription
const titleVideoEl = document.createElement('th') const titleVideoEl = document.createElement('th')
titleVideoEl.textContent = labels.Video titleVideoEl.textContent = `${labels.Video as string} / ${labels.Channel as string}`
const titleLastActivityEl = document.createElement('th') const titleLastActivityEl = document.createElement('th')
titleLastActivityEl.textContent = labels.LastActivity titleLastActivityEl.textContent = labels.LastActivity
titleLineEl.append(titleNameEl) titleLineEl.append(titleNameEl)
@ -103,8 +104,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
titleLineEl.append(titleLastActivityEl) titleLineEl.append(titleLastActivityEl)
table.append(titleLineEl) table.append(titleLineEl)
rooms.forEach(room => { rooms.forEach(room => {
const uuid = room.localpart const localpart = room.localpart
const href = getBaseRoute() + '/webchat/room/' + encodeURIComponent(uuid)
const lineEl = document.createElement('tr') const lineEl = document.createElement('tr')
const nameEl = document.createElement('td') const nameEl = document.createElement('td')
const aEl = document.createElement('a') const aEl = document.createElement('a')
@ -125,7 +125,24 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
lineEl.append(lastActivityEl) lineEl.append(lastActivityEl)
table.append(lineEl) table.append(lineEl)
if (/^[a-zA-A0-9-]+$/.test(uuid)) { const channelMatches = localpart.match(/^channel\.(\d+)$/)
if (channelMatches) {
// Here we have a channel chat room
// The backend should have added informations here
// (because the Peertube API can't work with channelId...)
const href = getBaseRoute() + '/webchat/room/' + encodeURIComponent(localpart)
if (room.channel?.name) {
aEl.href = href // here we know that the channel still exists, so we can open the webchat.
const aVideoEl = document.createElement('a')
aVideoEl.textContent = room.channel?.displayName ?? '-'
aVideoEl.target = '_blank'
aVideoEl.href = '/video-channels/' + room.channel.name
videoEl.append(aVideoEl)
}
} else if (/^[a-zA-A0-9-]+$/.test(localpart)) {
// localpart must be a video uuid.
const uuid = localpart
const href = getBaseRoute() + '/webchat/room/' + encodeURIComponent(uuid)
const p = fetch('/api/v1/videos/' + uuid, { const p = fetch('/api/v1/videos/' + uuid, {
method: 'GET', method: 'GET',
headers: peertubeHelpers.getAuthHeader() headers: peertubeHelpers.getAuthHeader()

View File

@ -61,6 +61,7 @@ async function getChannelInfosById (options: RegisterServerOptions, channelId: n
const [results] = await options.peertubeHelpers.database.query( const [results] = await options.peertubeHelpers.database.query(
'SELECT' + 'SELECT' +
' "actor"."preferredUsername" as "channelName",' + ' "actor"."preferredUsername" as "channelName",' +
' "videoChannel"."id" as "channelId",' +
' "videoChannel"."name" as "channelDisplayName"' + ' "videoChannel"."name" as "channelDisplayName"' +
' FROM "videoChannel"' + ' FROM "videoChannel"' +
' RIGHT JOIN "actor" ON "actor"."id" = "videoChannel"."actorId"' + ' RIGHT JOIN "actor" ON "actor"."id" = "videoChannel"."actorId"' +
@ -74,7 +75,7 @@ async function getChannelInfosById (options: RegisterServerOptions, channelId: n
return null return null
} }
return { return {
id: channelId, id: results[0].channelId,
name: results[0].channelName ?? '', name: results[0].channelName ?? '',
displayName: results[0].channelDisplayName ?? '' displayName: results[0].channelDisplayName ?? ''
} }

View File

@ -1,11 +1,11 @@
import type { Router, RequestHandler, Request, Response, NextFunction } from 'express' import type { Router, RequestHandler, Request, Response, NextFunction } from 'express'
import type { ProxyOptions } from 'express-http-proxy' import type { ProxyOptions } from 'express-http-proxy'
import type { ChatType, ProsodyListRoomsResult } from '../../../shared/lib/types' import type { ChatType, ProsodyListRoomsResult, ProsodyListRoomsResultRoom } from '../../../shared/lib/types'
import { getBaseRouterRoute, getBaseStaticRoute, isUserAdmin } from '../helpers' import { getBaseRouterRoute, getBaseStaticRoute, isUserAdmin } from '../helpers'
import { asyncMiddleware } from '../middlewares/async' import { asyncMiddleware } from '../middlewares/async'
import { getProsodyDomain } from '../prosody/config/domain' import { getProsodyDomain } from '../prosody/config/domain'
import { getAPIKey } from '../apikey' import { getAPIKey } from '../apikey'
import { getChannelNameById } from '../database/channel' import { getChannelInfosById, getChannelNameById } from '../database/channel'
import * as path from 'path' import * as path from 'path'
const bodyParser = require('body-parser') const bodyParser = require('body-parser')
const got = require('got') const got = require('got')
@ -31,10 +31,11 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
const router: Router = getRouter() const router: Router = getRouter()
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
router.get('/room/:videoUUID', asyncMiddleware( router.get('/room/:roomKey', asyncMiddleware(
async (req: Request, res: Response, _next: NextFunction): Promise<void> => { async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
res.removeHeader('X-Frame-Options') // this route can be opened in an iframe res.removeHeader('X-Frame-Options') // this route can be opened in an iframe
const roomKey = req.params.roomKey
const settings = await settingsManager.getSettings([ const settings = await settingsManager.getSettings([
'chat-type', 'chat-room', 'chat-server', 'chat-type', 'chat-room', 'chat-server',
'chat-bosh-uri', 'chat-ws-uri', 'chat-bosh-uri', 'chat-ws-uri',
@ -51,7 +52,9 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
if (chatType === 'builtin-prosody') { if (chatType === 'builtin-prosody') {
const prosodyDomain = await getProsodyDomain(options) const prosodyDomain = await getProsodyDomain(options)
jid = 'anon.' + prosodyDomain jid = 'anon.' + prosodyDomain
if (settings['prosody-room-type'] === 'channel') { if (settings['prosody-room-type'] === 'channel' || /^channel\.\d+$/.test(roomKey)) {
// NB: roomKey=~channel.\d+ should normally only happen when user
// comes from the room list in the plugin settings.
room = 'channel.{{CHANNEL_ID}}@room.' + prosodyDomain room = 'channel.{{CHANNEL_ID}}@room.' + prosodyDomain
} else { } else {
room = '{{VIDEO_UUID}}@room.' + prosodyDomain room = '{{VIDEO_UUID}}@room.' + prosodyDomain
@ -80,21 +83,43 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
throw new Error('Builtin chat disabled.') throw new Error('Builtin chat disabled.')
} }
const uuid = req.params.videoUUID let video: MVideoThumbnail | undefined
const video = await peertubeHelpers.videos.loadByIdOrUUID(uuid) let channelId: number
const channelMatches = roomKey.match(/^channel\.(\d+)$/)
if (channelMatches?.[1]) {
channelId = parseInt(channelMatches[1])
// Here we are on a room... must be in prosody mode.
if (chatType !== 'builtin-prosody') {
throw new Error('Cant access a chat by a channel uri if chatType!==builtin-prosody')
}
const channelInfos = await getChannelInfosById(options, channelId)
if (!channelInfos) {
throw new Error('Channel not found')
}
channelId = channelInfos.id
} else {
const uuid = roomKey // must be a video UUID.
video = await peertubeHelpers.videos.loadByIdOrUUID(uuid)
if (!video) { if (!video) {
throw new Error('Video not found') throw new Error('Video not found')
} }
channelId = video.channelId
}
let page = '' + (converseJSIndex as string) let page = '' + (converseJSIndex as string)
const baseStaticUrl = getBaseStaticRoute(options) const baseStaticUrl = getBaseStaticRoute(options)
page = page.replace(/{{BASE_STATIC_URL}}/g, baseStaticUrl) page = page.replace(/{{BASE_STATIC_URL}}/g, baseStaticUrl)
page = page.replace(/{{JID}}/g, jid) page = page.replace(/{{JID}}/g, jid)
// Computing the room name... // Computing the room name...
if (room.includes('{{VIDEO_UUID}}')) {
if (!video) {
throw new Error('Missing video')
}
room = room.replace(/{{VIDEO_UUID}}/g, video.uuid) room = room.replace(/{{VIDEO_UUID}}/g, video.uuid)
room = room.replace(/{{CHANNEL_ID}}/g, `${video.channelId}`) }
room = room.replace(/{{CHANNEL_ID}}/g, `${channelId}`)
if (room.includes('{{CHANNEL_NAME}}')) { if (room.includes('{{CHANNEL_NAME}}')) {
const channelName = await getChannelNameById(options, video.channelId) const channelName = await getChannelNameById(options, channelId)
if (channelName === null) { if (channelName === null) {
throw new Error('Channel not found') throw new Error('Channel not found')
} }
@ -164,6 +189,24 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
resolveBodyOnly: true resolveBodyOnly: true
}) })
if (Array.isArray(rooms)) {
for (let i = 0; i < rooms.length; i++) {
const room: ProsodyListRoomsResultRoom = rooms[i]
const matches = room.localpart.match(/^channel\.(\d+)$/)
if (matches?.[1]) {
const channelId = parseInt(matches[1])
const channelInfos = await getChannelInfosById(options, channelId)
if (channelInfos) {
room.channel = {
id: channelInfos.id,
name: channelInfos.name,
displayName: channelInfos.displayName
}
}
}
}
}
res.status(200) res.status(200)
const r: ProsodyListRoomsResult = { const r: ProsodyListRoomsResult = {
ok: true, ok: true,

View File

@ -5,21 +5,29 @@ interface ProsodyListRoomsResultError {
error: string error: string
} }
interface ProsodyListRoomsResultSuccess { interface ProsodyListRoomsResultRoom {
ok: true
rooms: Array<{
jid: string jid: string
localpart: string localpart: string
name: string name: string
lang: string lang: string
description: string description: string
lasttimestamp?: number lasttimestamp?: number
}> channel?: {
id: number
name: string
displayName: string
}
}
interface ProsodyListRoomsResultSuccess {
ok: true
rooms: ProsodyListRoomsResultRoom[]
} }
type ProsodyListRoomsResult = ProsodyListRoomsResultError | ProsodyListRoomsResultSuccess type ProsodyListRoomsResult = ProsodyListRoomsResultError | ProsodyListRoomsResultSuccess
export { export {
ChatType, ChatType,
ProsodyListRoomsResult ProsodyListRoomsResult,
ProsodyListRoomsResultRoom
} }