Room list: handle channel rooms.
This commit is contained in:
parent
855ed51251
commit
e9d1e55084
@ -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()
|
||||||
|
@ -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 ?? ''
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user