testapp: add kick participant functionality and fix view recordings link
- Enhanced the web component to include a kick participant feature. - Updated the UI to allow moderators to input participant identity for kicking. - Modified the room controller to handle the new kick participant request. - Refactored code for better readability and maintainability across various services and controllers. - Updated the index.mustache and room.mustache templates to reflect changes in functionality.
This commit is contained in:
parent
0a028226f3
commit
2b7466c6e3
@ -3,6 +3,7 @@ const socket = (window as any).io();
|
|||||||
let meet: {
|
let meet: {
|
||||||
endMeeting: () => void;
|
endMeeting: () => void;
|
||||||
leaveRoom: () => void;
|
leaveRoom: () => void;
|
||||||
|
kickParticipant: (participantIdentity: string) => void;
|
||||||
on: (event: string, callback: (event: CustomEvent<any>) => void) => void;
|
on: (event: string, callback: (event: CustomEvent<any>) => void) => void;
|
||||||
};
|
};
|
||||||
let roomId: string | undefined;
|
let roomId: string | undefined;
|
||||||
@ -31,7 +32,10 @@ const escapeHtml = (unsafe: string): string => {
|
|||||||
|
|
||||||
const getWebhookEventsFromStorage = (roomId: string): any[] => {
|
const getWebhookEventsFromStorage = (roomId: string): any[] => {
|
||||||
const data = localStorage.getItem('webhookEventsByRoom');
|
const data = localStorage.getItem('webhookEventsByRoom');
|
||||||
if (!data) return [];
|
if (!data) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const map = JSON.parse(data);
|
const map = JSON.parse(data);
|
||||||
return map[roomId] || [];
|
return map[roomId] || [];
|
||||||
};
|
};
|
||||||
@ -39,7 +43,10 @@ const getWebhookEventsFromStorage = (roomId: string): any[] => {
|
|||||||
const saveWebhookEventToStorage = (roomId: string, event: any): void => {
|
const saveWebhookEventToStorage = (roomId: string, event: any): void => {
|
||||||
const data = localStorage.getItem('webhookEventsByRoom');
|
const data = localStorage.getItem('webhookEventsByRoom');
|
||||||
const map = data ? JSON.parse(data) : {};
|
const map = data ? JSON.parse(data) : {};
|
||||||
if (!map[roomId]) map[roomId] = [];
|
if (!map[roomId]) {
|
||||||
|
map[roomId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
map[roomId].push(event);
|
map[roomId].push(event);
|
||||||
localStorage.setItem('webhookEventsByRoom', JSON.stringify(map));
|
localStorage.setItem('webhookEventsByRoom', JSON.stringify(map));
|
||||||
};
|
};
|
||||||
@ -47,6 +54,7 @@ const saveWebhookEventToStorage = (roomId: string, event: any): void => {
|
|||||||
const clearWebhookEventsByRoom = (roomId: string): void => {
|
const clearWebhookEventsByRoom = (roomId: string): void => {
|
||||||
const data = localStorage.getItem('webhookEventsByRoom');
|
const data = localStorage.getItem('webhookEventsByRoom');
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
const map = JSON.parse(data);
|
const map = JSON.parse(data);
|
||||||
if (map[roomId]) {
|
if (map[roomId]) {
|
||||||
map[roomId] = [];
|
map[roomId] = [];
|
||||||
@ -57,6 +65,7 @@ const clearWebhookEventsByRoom = (roomId: string): void => {
|
|||||||
const shouldShowWebhook = (event: any): boolean => {
|
const shouldShowWebhook = (event: any): boolean => {
|
||||||
return showAllWebhooksCheckbox?.checked || event.data.roomId === roomId;
|
return showAllWebhooksCheckbox?.checked || event.data.roomId === roomId;
|
||||||
};
|
};
|
||||||
|
|
||||||
const listenWebhookServerEvents = () => {
|
const listenWebhookServerEvents = () => {
|
||||||
socket.on('webhookEvent', (event: any) => {
|
socket.on('webhookEvent', (event: any) => {
|
||||||
console.log('Webhook received:', event);
|
console.log('Webhook received:', event);
|
||||||
@ -86,6 +95,7 @@ const renderStoredWebhookEvents = (roomId: string) => {
|
|||||||
webhookLogList.removeChild(webhookLogList.firstChild);
|
webhookLogList.removeChild(webhookLogList.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const events = getWebhookEventsFromStorage(roomId);
|
const events = getWebhookEventsFromStorage(roomId);
|
||||||
events.forEach((event) => addWebhookEventElement(event));
|
events.forEach((event) => addWebhookEventElement(event));
|
||||||
};
|
};
|
||||||
@ -125,9 +135,9 @@ const addWebhookEventElement = (event: any) => {
|
|||||||
if (event.event.includes('recording')) {
|
if (event.event.includes('recording')) {
|
||||||
button.classList.add('bg-warning');
|
button.classList.add('bg-warning');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the header text with event name and timestamp
|
// Format the header text with event name and timestamp
|
||||||
const date = new Date(event.creationDate);
|
const date = new Date(event.creationDate);
|
||||||
|
|
||||||
const formattedDate = date.toLocaleString('es-ES', {
|
const formattedDate = date.toLocaleString('es-ES', {
|
||||||
// year: 'numeric',
|
// year: 'numeric',
|
||||||
// month: '2-digit',
|
// month: '2-digit',
|
||||||
@ -135,7 +145,7 @@ const addWebhookEventElement = (event: any) => {
|
|||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
second: '2-digit',
|
second: '2-digit',
|
||||||
hour12: false,
|
hour12: false
|
||||||
});
|
});
|
||||||
button.innerHTML = `[${formattedDate}] <strong>${event.event}</strong>`;
|
button.innerHTML = `[${formattedDate}] <strong>${event.event}</strong>`;
|
||||||
|
|
||||||
@ -152,9 +162,7 @@ const addWebhookEventElement = (event: any) => {
|
|||||||
|
|
||||||
// Format JSON with syntax highlighting if possible
|
// Format JSON with syntax highlighting if possible
|
||||||
const formattedJson = JSON.stringify(event, null, 2);
|
const formattedJson = JSON.stringify(event, null, 2);
|
||||||
bodyDiv.innerHTML = `<pre class="mb-0"><code>${escapeHtml(
|
bodyDiv.innerHTML = `<pre class="mb-0"><code>${escapeHtml(formattedJson)}</code></pre>`;
|
||||||
formattedJson
|
|
||||||
)}</code></pre>`;
|
|
||||||
|
|
||||||
// Assemble the components
|
// Assemble the components
|
||||||
header.appendChild(button);
|
header.appendChild(button);
|
||||||
@ -178,7 +186,6 @@ const addWebhookEventElement = (event: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Listen to events from openvidu-meet
|
// Listen to events from openvidu-meet
|
||||||
|
|
||||||
const listenWebComponentEvents = () => {
|
const listenWebComponentEvents = () => {
|
||||||
const meet = document.querySelector('openvidu-meet') as any;
|
const meet = document.querySelector('openvidu-meet') as any;
|
||||||
if (!meet) {
|
if (!meet) {
|
||||||
@ -195,7 +202,6 @@ const listenWebComponentEvents = () => {
|
|||||||
console.log('LEFT event received:', event);
|
console.log('LEFT event received:', event);
|
||||||
addEventToLog('LEFT', JSON.stringify(event));
|
addEventToLog('LEFT', JSON.stringify(event));
|
||||||
});
|
});
|
||||||
|
|
||||||
meet.on('MEETING_ENDED', (event: CustomEvent<any>) => {
|
meet.on('MEETING_ENDED', (event: CustomEvent<any>) => {
|
||||||
console.log('MEETING_ENDED event received:', event);
|
console.log('MEETING_ENDED event received:', event);
|
||||||
addEventToLog('MEETING_ENDED', JSON.stringify(event));
|
addEventToLog('MEETING_ENDED', JSON.stringify(event));
|
||||||
@ -211,26 +217,25 @@ const setUpWebComponentCommands = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// End meeting button click handler
|
// End meeting button click handler
|
||||||
document
|
document.getElementById('end-meeting-btn')?.addEventListener('click', () => meet.endMeeting());
|
||||||
.getElementById('end-meeting-btn')
|
|
||||||
?.addEventListener('click', () => meet.endMeeting());
|
|
||||||
|
|
||||||
// Leave room button click handler
|
// Leave room button click handler
|
||||||
document
|
document.getElementById('leave-room-btn')?.addEventListener('click', () => meet.leaveRoom());
|
||||||
.getElementById('leave-room-btn')
|
|
||||||
?.addEventListener('click', () => meet.leaveRoom());
|
|
||||||
|
|
||||||
// Toggle chat button click handler
|
// Kick participant button click handler
|
||||||
// document
|
document.getElementById('kick-participant-btn')?.addEventListener('click', () => {
|
||||||
// .getElementById('toggle-chat-btn')
|
const participantIdentity = (
|
||||||
// ?.addEventListener('click', () => meet.toggleChat());
|
document.getElementById('participant-identity-input') as HTMLInputElement
|
||||||
|
).value.trim();
|
||||||
|
if (participantIdentity) {
|
||||||
|
meet.kickParticipant(participantIdentity);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
roomId = document.getElementById('room-id')?.textContent?.trim();
|
roomId = document.getElementById('room-id')?.textContent?.trim();
|
||||||
showAllWebhooksCheckbox = document.getElementById(
|
showAllWebhooksCheckbox = document.getElementById('show-all-webhooks') as HTMLInputElement;
|
||||||
'show-all-webhooks'
|
|
||||||
) as HTMLInputElement;
|
|
||||||
meet = document.querySelector('openvidu-meet') as any;
|
meet = document.querySelector('openvidu-meet') as any;
|
||||||
|
|
||||||
if (!roomId) {
|
if (!roomId) {
|
||||||
@ -238,6 +243,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
alert('Room ID not found in the DOM');
|
alert('Room ID not found in the DOM');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderStoredWebhookEvents(roomId);
|
renderStoredWebhookEvents(roomId);
|
||||||
listenWebhookServerEvents();
|
listenWebhookServerEvents();
|
||||||
listenWebComponentEvents();
|
listenWebComponentEvents();
|
||||||
|
|||||||
@ -109,24 +109,29 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
{{! ONLY RECORDINGS LINK }}
|
{{! SHOW ONLY RECORDINGS LINK }}
|
||||||
<li>
|
<li>
|
||||||
<form action="/join-room" method="post">
|
<form action="/join-room" method="post">
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="roomUrl"
|
name="roomUrl"
|
||||||
value="{{ publisherRoomUrl + '?viewRecordings=true' }}"
|
value="{{ moderatorRoomUrl }}"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="participantRole"
|
name="participantRole"
|
||||||
value="publisher"
|
value="moderator"
|
||||||
/>
|
/>
|
||||||
<input type="hidden" name="roomId" value="{{ roomId }}" />
|
<input type="hidden" name="roomId" value="{{ roomId }}" />
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="showOnlyRecordings"
|
||||||
|
value="true"
|
||||||
|
/>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
id="join-as-publisher"
|
id="view-recordings"
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
>
|
>
|
||||||
View Recordings
|
View Recordings
|
||||||
@ -273,7 +278,6 @@
|
|||||||
<option value="admin-moderator-publisher" selected>
|
<option value="admin-moderator-publisher" selected>
|
||||||
Admin, Moderator & Publisher
|
Admin, Moderator & Publisher
|
||||||
</option>
|
</option>
|
||||||
<option value="public">Public Access</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -42,9 +42,17 @@
|
|||||||
<button id="leave-room-btn" class="btn btn-warning">
|
<button id="leave-room-btn" class="btn btn-warning">
|
||||||
Leave Room
|
Leave Room
|
||||||
</button>
|
</button>
|
||||||
<!-- <button id="toggle-chat-btn" class="btn btn-success">
|
{{#isModerator}}
|
||||||
Toggle Chat
|
<input
|
||||||
</button> -->
|
type="text"
|
||||||
|
id="participant-identity-input"
|
||||||
|
placeholder="Participant Identity"
|
||||||
|
class="form-control mb-2"
|
||||||
|
/>
|
||||||
|
<button id="kick-participant-btn" class="btn btn-info">
|
||||||
|
Kick Participant
|
||||||
|
</button>
|
||||||
|
{{/isModerator}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Events -->
|
<!-- Events -->
|
||||||
@ -82,7 +90,9 @@
|
|||||||
<openvidu-meet
|
<openvidu-meet
|
||||||
room-url="{{ roomUrl }}"
|
room-url="{{ roomUrl }}"
|
||||||
participant-name="{{ participantName }}"
|
participant-name="{{ participantName }}"
|
||||||
leave-redirect-url="https://openvidu.io"
|
{{#showOnlyRecordings}}
|
||||||
|
show-only-recordings=true
|
||||||
|
{{/showOnlyRecordings}}
|
||||||
></openvidu-meet>
|
></openvidu-meet>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,20 +1,12 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import {
|
import { getAllRooms, createRoom, deleteRoom, deleteAllRooms } from '../services/roomService';
|
||||||
getAllRooms,
|
import { deleteAllRecordings, getAllRecordings } from '../services/recordingService';
|
||||||
createRoom,
|
|
||||||
deleteRoom,
|
|
||||||
deleteAllRooms,
|
|
||||||
} from '../services/roomService';
|
|
||||||
import {
|
|
||||||
deleteAllRecordings,
|
|
||||||
getAllRecordings,
|
|
||||||
} from '../services/recordingService';
|
|
||||||
|
|
||||||
export const getHome = async (req: Request, res: Response) => {
|
export const getHome = async (_req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { rooms } = await getAllRooms();
|
const { rooms } = await getAllRooms();
|
||||||
|
|
||||||
//sort rooms by newest first
|
// Sort rooms by newest first
|
||||||
rooms.sort((a, b) => {
|
rooms.sort((a, b) => {
|
||||||
const dateA = new Date(a.creationDate);
|
const dateA = new Date(a.creationDate);
|
||||||
const dateB = new Date(b.creationDate);
|
const dateB = new Date(b.creationDate);
|
||||||
@ -64,6 +56,7 @@ export const deleteAllRoomsCtrl = async (_req: Request, res: Response) => {
|
|||||||
res.render('index', { rooms: [] });
|
res.render('index', { rooms: [] });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const roomIds = allRooms.rooms.map((room) => room.roomId);
|
const roomIds = allRooms.rooms.map((room) => room.roomId);
|
||||||
console.log(`Deleting ${roomIds.length} rooms`, roomIds);
|
console.log(`Deleting ${roomIds.length} rooms`, roomIds);
|
||||||
await deleteAllRooms(roomIds);
|
await deleteAllRooms(roomIds);
|
||||||
@ -77,15 +70,13 @@ export const deleteAllRoomsCtrl = async (_req: Request, res: Response) => {
|
|||||||
|
|
||||||
export const deleteAllRecordingsCtrl = async (_req: Request, res: Response) => {
|
export const deleteAllRecordingsCtrl = async (_req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const [{ recordings }, { rooms }] = await Promise.all([
|
const [{ recordings }, { rooms }] = await Promise.all([getAllRecordings(), getAllRooms()]);
|
||||||
getAllRecordings(),
|
|
||||||
getAllRooms(),
|
|
||||||
]);
|
|
||||||
if (recordings.length === 0) {
|
if (recordings.length === 0) {
|
||||||
console.log('No recordings to delete');
|
console.log('No recordings to delete');
|
||||||
res.render('index', { rooms });
|
res.render('index', { rooms });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const recordingIds = recordings.map((recording) => recording.recordingId);
|
const recordingIds = recordings.map((recording) => recording.recordingId);
|
||||||
await deleteAllRecordings(recordingIds);
|
await deleteAllRecordings(recordingIds);
|
||||||
console.log(`Deleted ${recordingIds.length} recordings`);
|
console.log(`Deleted ${recordingIds.length} recordings`);
|
||||||
@ -103,21 +94,18 @@ export const deleteAllRecordingsCtrl = async (_req: Request, res: Response) => {
|
|||||||
const processFormPreferences = (body: any): any => {
|
const processFormPreferences = (body: any): any => {
|
||||||
const preferences = {
|
const preferences = {
|
||||||
chatPreferences: {
|
chatPreferences: {
|
||||||
enabled: body['preferences.chatPreferences.enabled'] === 'on',
|
enabled: body['preferences.chatPreferences.enabled'] === 'on'
|
||||||
},
|
},
|
||||||
recordingPreferences: {
|
recordingPreferences: {
|
||||||
enabled: body['preferences.recordingPreferences.enabled'] === 'on',
|
enabled: body['preferences.recordingPreferences.enabled'] === 'on',
|
||||||
// Only include allowAccessTo if recording is enabled
|
// Only include allowAccessTo if recording is enabled
|
||||||
...(body['preferences.recordingPreferences.enabled'] === 'on' && {
|
...(body['preferences.recordingPreferences.enabled'] === 'on' && {
|
||||||
allowAccessTo:
|
allowAccessTo: body['preferences.recordingPreferences.allowAccessTo'] || 'admin-moderator-publisher'
|
||||||
body['preferences.recordingPreferences.allowAccessTo'] ||
|
})
|
||||||
'admin-moderator-publisher',
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
virtualBackgroundPreferences: {
|
virtualBackgroundPreferences: {
|
||||||
enabled:
|
enabled: body['preferences.virtualBackgroundPreferences.enabled'] === 'on'
|
||||||
body['preferences.virtualBackgroundPreferences.enabled'] === 'on',
|
}
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return preferences;
|
return preferences;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ interface JoinRoomRequest {
|
|||||||
roomUrl: string;
|
roomUrl: string;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
participantName?: string;
|
participantName?: string;
|
||||||
|
showOnlyRecordings?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const joinRoom = (req: Request, res: Response) => {
|
export const joinRoom = (req: Request, res: Response) => {
|
||||||
@ -18,16 +19,18 @@ export const joinRoom = (req: Request, res: Response) => {
|
|||||||
roomUrl,
|
roomUrl,
|
||||||
roomId,
|
roomId,
|
||||||
participantName = 'User',
|
participantName = 'User',
|
||||||
|
showOnlyRecordings
|
||||||
} = req.body as JoinRoomRequest;
|
} = req.body as JoinRoomRequest;
|
||||||
if (!roomUrl) {
|
if (!roomUrl) {
|
||||||
throw new Error('Room URL is required.');
|
throw new Error('Room URL is required.');
|
||||||
}
|
}
|
||||||
|
|
||||||
res.render('room', {
|
res.render('room', {
|
||||||
roomUrl,
|
roomUrl,
|
||||||
participantRole,
|
isModerator: participantRole === 'moderator',
|
||||||
participantName,
|
participantName,
|
||||||
roomId,
|
roomId,
|
||||||
isModerator: participantRole === 'moderator',
|
showOnlyRecordings: showOnlyRecordings || false
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error joining room:', error);
|
console.error('Error joining room:', error);
|
||||||
@ -36,11 +39,7 @@ export const joinRoom = (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleWebhook = async (
|
export const handleWebhook = async (req: Request, res: Response, io: IOServer): Promise<void> => {
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
io: IOServer
|
|
||||||
): Promise<void> => {
|
|
||||||
try {
|
try {
|
||||||
const webhookEvent = req.body as MeetWebhookEvent;
|
const webhookEvent = req.body as MeetWebhookEvent;
|
||||||
|
|
||||||
@ -54,7 +53,7 @@ export const handleWebhook = async (
|
|||||||
console.error('Error handling webhook:', error);
|
console.error('Error handling webhook:', error);
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
message: 'Error handling webhook',
|
message: 'Error handling webhook',
|
||||||
error: (error as Error).message,
|
error: (error as Error).message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import { Server as IOServer } from 'socket.io';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { Server as IOServer } from 'socket.io';
|
||||||
import {
|
import {
|
||||||
getHome,
|
|
||||||
postCreateRoom,
|
|
||||||
deleteRoomCtrl,
|
|
||||||
deleteAllRoomsCtrl,
|
|
||||||
deleteAllRecordingsCtrl,
|
deleteAllRecordingsCtrl,
|
||||||
|
deleteAllRoomsCtrl,
|
||||||
|
deleteRoomCtrl,
|
||||||
|
getHome,
|
||||||
|
postCreateRoom
|
||||||
} from './controllers/homeController';
|
} from './controllers/homeController';
|
||||||
import { handleWebhook, joinRoom } from './controllers/roomController';
|
import { handleWebhook, joinRoom } from './controllers/roomController';
|
||||||
import { configService } from './services/configService';
|
import { configService } from './services/configService';
|
||||||
@ -31,7 +31,6 @@ app.use(express.json());
|
|||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.get('/', getHome);
|
app.get('/', getHome);
|
||||||
app.get('/room', joinRoom);
|
|
||||||
app.post('/room', postCreateRoom);
|
app.post('/room', postCreateRoom);
|
||||||
app.post('/room/delete', deleteRoomCtrl);
|
app.post('/room/delete', deleteRoomCtrl);
|
||||||
app.post('/delete-all-rooms', deleteAllRoomsCtrl);
|
app.post('/delete-all-rooms', deleteAllRoomsCtrl);
|
||||||
@ -45,13 +44,11 @@ const PORT = configService.serverPort;
|
|||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log('-----------------------------------------');
|
console.log('-----------------------------------------');
|
||||||
console.log(`Server running on port ${PORT}`);
|
console.log(`Server running on port ${PORT}`);
|
||||||
console.log(`Meet API URL: ${configService.meetApiUrl}`);
|
console.log(`Visit http://localhost:${PORT}/ to access the app`);
|
||||||
console.log('-----------------------------------------');
|
console.log('-----------------------------------------');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log(`Visit http://localhost:${PORT}/ to access the app`);
|
|
||||||
|
|
||||||
console.log('Environment variables:');
|
console.log('OpenVidu Meet Configuration:');
|
||||||
console.log(`OPENVIDU_MEET_URL: ${process.env.OPENVIDU_MEET_URL}`);
|
console.log(`Meet API URL: ${configService.meetApiUrl}`);
|
||||||
console.log(`MEET_API_KEY: ${process.env.MEET_API_KEY} `);
|
console.log(`Meet API key: ${configService.meetApiKey}`);
|
||||||
console.log(`PORT: ${process.env.PORT}`);
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { del, get } from '../utils/http';
|
import { del, get } from '../utils/http';
|
||||||
|
// @ts-ignore
|
||||||
import { MeetRecordingInfo } from '../../../typings/src/recording.model';
|
import { MeetRecordingInfo } from '../../../typings/src/recording.model';
|
||||||
import { configService } from './configService';
|
import { configService } from './configService';
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ export const getAllRecordings = async (): Promise<{
|
|||||||
pagination: any;
|
pagination: any;
|
||||||
recordings: MeetRecordingInfo[];
|
recordings: MeetRecordingInfo[];
|
||||||
}>(url, {
|
}>(url, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey }
|
||||||
});
|
});
|
||||||
|
|
||||||
while (pagination.isTruncated) {
|
while (pagination.isTruncated) {
|
||||||
@ -21,21 +22,18 @@ export const getAllRecordings = async (): Promise<{
|
|||||||
pagination: any;
|
pagination: any;
|
||||||
recordings: MeetRecordingInfo[];
|
recordings: MeetRecordingInfo[];
|
||||||
}>(nextPageUrl, {
|
}>(nextPageUrl, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey }
|
||||||
});
|
});
|
||||||
recordings.push(...nextPageResult.recordings);
|
recordings.push(...nextPageResult.recordings);
|
||||||
pagination = nextPageResult.pagination;
|
pagination = nextPageResult.pagination;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { pagination, recordings };
|
return { pagination, recordings };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteAllRecordings = async (
|
export const deleteAllRecordings = async (recordingIds: string[]): Promise<void> => {
|
||||||
recordingIds: string[]
|
const url = `${configService.meetApiUrl}/recordings?recordingIds=${recordingIds.join(',')}`;
|
||||||
): Promise<void> => {
|
|
||||||
const url = `${
|
|
||||||
configService.meetApiUrl
|
|
||||||
}/recordings?recordingIds=${recordingIds.join(',')}`;
|
|
||||||
await del<void>(url, {
|
await del<void>(url, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { get, post, del } from '../utils/http';
|
import { del, get, post } from '../utils/http';
|
||||||
import { configService } from './configService';
|
import { configService } from './configService';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { MeetRoom, MeetRoomOptions } from '../../../typings/src/room';
|
import { MeetRoom, MeetRoomOptions } from '../../../typings/src/room';
|
||||||
@ -9,33 +9,37 @@ export async function getAllRooms(): Promise<{
|
|||||||
}> {
|
}> {
|
||||||
const url = `${configService.meetApiUrl}/rooms`;
|
const url = `${configService.meetApiUrl}/rooms`;
|
||||||
return get<{ pagination: any; rooms: MeetRoom[] }>(url, {
|
return get<{ pagination: any; rooms: MeetRoom[] }>(url, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createRoom(roomData: MeetRoomOptions): Promise<MeetRoom> {
|
export async function createRoom(roomData: MeetRoomOptions): Promise<MeetRoom> {
|
||||||
const url = `${configService.meetApiUrl}/rooms`;
|
const url = `${configService.meetApiUrl}/rooms`;
|
||||||
// Default to 1 hour if autoDeletionDate is not provided
|
// Default to 1 hour if autoDeletionDate is not provided
|
||||||
if (!roomData.autoDeletionDate)
|
if (!roomData.autoDeletionDate) {
|
||||||
roomData.autoDeletionDate = new Date(Date.now() + 60 * 61 * 1000).getTime();
|
roomData.autoDeletionDate = new Date(Date.now() + 60 * 61 * 1000).getTime();
|
||||||
|
} else {
|
||||||
|
// Ensure autoDeletionDate is a timestamp
|
||||||
|
roomData.autoDeletionDate = new Date(roomData.autoDeletionDate).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Creating room with options:', roomData);
|
console.log('Creating room with options:', roomData);
|
||||||
return post<MeetRoom>(url, {
|
return post<MeetRoom>(url, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey },
|
||||||
body: roomData,
|
body: roomData
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteRoom(roomId: string): Promise<void> {
|
export async function deleteRoom(roomId: string): Promise<void> {
|
||||||
const url = `${configService.meetApiUrl}/rooms/${roomId}`;
|
const url = `${configService.meetApiUrl}/rooms/${roomId}`;
|
||||||
await del<void>(url, {
|
await del<void>(url, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteAllRooms(roomIds: string[]): Promise<void> {
|
export async function deleteAllRooms(roomIds: string[]): Promise<void> {
|
||||||
const url = `${configService.meetApiUrl}/rooms?roomIds=${roomIds.join(',')}`;
|
const url = `${configService.meetApiUrl}/rooms?roomIds=${roomIds.join(',')}`;
|
||||||
|
|
||||||
await del<void>(url, {
|
await del<void>(url, {
|
||||||
headers: { 'x-api-key': configService.meetApiKey },
|
headers: { 'x-api-key': configService.meetApiKey }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,28 +4,20 @@ export interface RequestOptions {
|
|||||||
body?: any;
|
body?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildUrl(
|
async function buildUrl(url: string, queryParams?: Record<string, string>): Promise<string> {
|
||||||
url: string,
|
|
||||||
queryParams?: Record<string, string>
|
|
||||||
): Promise<string> {
|
|
||||||
if (!queryParams) return url;
|
if (!queryParams) return url;
|
||||||
const params = new URLSearchParams(
|
const params = new URLSearchParams(queryParams as Record<string, string>).toString();
|
||||||
queryParams as Record<string, string>
|
|
||||||
).toString();
|
|
||||||
return `${url}?${params}`;
|
return `${url}?${params}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function request<T>(
|
async function request<T>(method: string, url: string, options: RequestOptions = {}): Promise<T> {
|
||||||
method: string,
|
|
||||||
url: string,
|
|
||||||
options: RequestOptions = {}
|
|
||||||
): Promise<T> {
|
|
||||||
const fullUrl = await buildUrl(url, options.queryParams);
|
const fullUrl = await buildUrl(url, options.queryParams);
|
||||||
const fetchOptions: RequestInit = {
|
const fetchOptions: RequestInit = {
|
||||||
method,
|
method,
|
||||||
headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
|
headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
|
||||||
body: options.body ? JSON.stringify(options.body) : undefined,
|
body: options.body ? JSON.stringify(options.body) : undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(fullUrl, fetchOptions);
|
const response = await fetch(fullUrl, fetchOptions);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
@ -41,30 +33,18 @@ async function request<T>(
|
|||||||
return JSON.parse(text) as T;
|
return JSON.parse(text) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get<T>(
|
export function get<T>(url: string, options?: Omit<RequestOptions, 'body'>): Promise<T> {
|
||||||
url: string,
|
|
||||||
options?: Omit<RequestOptions, 'body'>
|
|
||||||
): Promise<T> {
|
|
||||||
return request<T>('GET', url, options || {});
|
return request<T>('GET', url, options || {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function post<T>(
|
export function post<T>(url: string, options?: Omit<RequestOptions, 'body'> & { body: any }): Promise<T> {
|
||||||
url: string,
|
|
||||||
options?: Omit<RequestOptions, 'body'> & { body: any }
|
|
||||||
): Promise<T> {
|
|
||||||
return request<T>('POST', url, options as RequestOptions);
|
return request<T>('POST', url, options as RequestOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function put<T>(
|
export function put<T>(url: string, options?: Omit<RequestOptions, 'body'> & { body: any }): Promise<T> {
|
||||||
url: string,
|
|
||||||
options?: Omit<RequestOptions, 'body'> & { body: any }
|
|
||||||
): Promise<T> {
|
|
||||||
return request<T>('PUT', url, options as RequestOptions);
|
return request<T>('PUT', url, options as RequestOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function del<T>(
|
export function del<T>(url: string, options?: Omit<RequestOptions, 'body'>): Promise<T> {
|
||||||
url: string,
|
|
||||||
options?: Omit<RequestOptions, 'body'>
|
|
||||||
): Promise<T> {
|
|
||||||
return request<T>('DELETE', url, options || {});
|
return request<T>('DELETE', url, options || {});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user