369 lines
11 KiB
JavaScript
369 lines
11 KiB
JavaScript
import { Router } from 'express';
|
|
import crypto from 'crypto';
|
|
import { getDb } from '../config/database.js';
|
|
import { authenticateToken } from '../middleware/auth.js';
|
|
import {
|
|
createMeeting,
|
|
joinMeeting,
|
|
endMeeting,
|
|
getMeetingInfo,
|
|
isMeetingRunning,
|
|
} from '../config/bbb.js';
|
|
|
|
const router = Router();
|
|
|
|
// GET /api/rooms - List user's rooms
|
|
router.get('/', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const rooms = await db.all(`
|
|
SELECT r.*, u.name as owner_name
|
|
FROM rooms r
|
|
JOIN users u ON r.user_id = u.id
|
|
WHERE r.user_id = ?
|
|
ORDER BY r.created_at DESC
|
|
`, [req.user.id]);
|
|
|
|
res.json({ rooms });
|
|
} catch (err) {
|
|
console.error('List rooms error:', err);
|
|
res.status(500).json({ error: 'Räume konnten nicht geladen werden' });
|
|
}
|
|
});
|
|
|
|
// GET /api/rooms/:uid - Get room details
|
|
router.get('/:uid', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get(`
|
|
SELECT r.*, u.name as owner_name
|
|
FROM rooms r
|
|
JOIN users u ON r.user_id = u.id
|
|
WHERE r.uid = ?
|
|
`, [req.params.uid]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden' });
|
|
}
|
|
|
|
res.json({ room });
|
|
} catch (err) {
|
|
console.error('Get room error:', err);
|
|
res.status(500).json({ error: 'Raum konnte nicht geladen werden' });
|
|
}
|
|
});
|
|
|
|
// POST /api/rooms - Create room
|
|
router.post('/', authenticateToken, async (req, res) => {
|
|
try {
|
|
const {
|
|
name,
|
|
welcome_message,
|
|
max_participants,
|
|
access_code,
|
|
mute_on_join,
|
|
require_approval,
|
|
anyone_can_start,
|
|
all_join_moderator,
|
|
record_meeting,
|
|
guest_access,
|
|
moderator_code,
|
|
} = req.body;
|
|
|
|
if (!name || name.trim().length === 0) {
|
|
return res.status(400).json({ error: 'Raumname ist erforderlich' });
|
|
}
|
|
|
|
const uid = crypto.randomBytes(8).toString('hex');
|
|
const db = getDb();
|
|
|
|
const result = await db.run(`
|
|
INSERT INTO rooms (uid, name, user_id, welcome_message, max_participants, access_code, mute_on_join, require_approval, anyone_can_start, all_join_moderator, record_meeting, guest_access, moderator_code)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`, [
|
|
uid,
|
|
name.trim(),
|
|
req.user.id,
|
|
welcome_message || 'Willkommen im Meeting!',
|
|
max_participants || 0,
|
|
access_code || null,
|
|
mute_on_join !== false ? 1 : 0,
|
|
require_approval ? 1 : 0,
|
|
anyone_can_start ? 1 : 0,
|
|
all_join_moderator ? 1 : 0,
|
|
record_meeting !== false ? 1 : 0,
|
|
guest_access ? 1 : 0,
|
|
moderator_code || null,
|
|
]);
|
|
|
|
const room = await db.get('SELECT * FROM rooms WHERE id = ?', [result.lastInsertRowid]);
|
|
res.status(201).json({ room });
|
|
} catch (err) {
|
|
console.error('Create room error:', err);
|
|
res.status(500).json({ error: 'Raum konnte nicht erstellt werden' });
|
|
}
|
|
});
|
|
|
|
// PUT /api/rooms/:uid - Update room
|
|
router.put('/:uid', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get('SELECT * FROM rooms WHERE uid = ? AND user_id = ?', [req.params.uid, req.user.id]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden oder keine Berechtigung' });
|
|
}
|
|
|
|
const {
|
|
name,
|
|
welcome_message,
|
|
max_participants,
|
|
access_code,
|
|
mute_on_join,
|
|
require_approval,
|
|
anyone_can_start,
|
|
all_join_moderator,
|
|
record_meeting,
|
|
guest_access,
|
|
moderator_code,
|
|
} = req.body;
|
|
|
|
await db.run(`
|
|
UPDATE rooms SET
|
|
name = COALESCE(?, name),
|
|
welcome_message = COALESCE(?, welcome_message),
|
|
max_participants = COALESCE(?, max_participants),
|
|
access_code = ?,
|
|
mute_on_join = COALESCE(?, mute_on_join),
|
|
require_approval = COALESCE(?, require_approval),
|
|
anyone_can_start = COALESCE(?, anyone_can_start),
|
|
all_join_moderator = COALESCE(?, all_join_moderator),
|
|
record_meeting = COALESCE(?, record_meeting),
|
|
guest_access = COALESCE(?, guest_access),
|
|
moderator_code = ?,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE uid = ?
|
|
`, [
|
|
name,
|
|
welcome_message,
|
|
max_participants,
|
|
access_code ?? room.access_code,
|
|
mute_on_join !== undefined ? (mute_on_join ? 1 : 0) : null,
|
|
require_approval !== undefined ? (require_approval ? 1 : 0) : null,
|
|
anyone_can_start !== undefined ? (anyone_can_start ? 1 : 0) : null,
|
|
all_join_moderator !== undefined ? (all_join_moderator ? 1 : 0) : null,
|
|
record_meeting !== undefined ? (record_meeting ? 1 : 0) : null,
|
|
guest_access !== undefined ? (guest_access ? 1 : 0) : null,
|
|
moderator_code !== undefined ? (moderator_code || null) : room.moderator_code,
|
|
req.params.uid,
|
|
]);
|
|
|
|
const updated = await db.get('SELECT * FROM rooms WHERE uid = ?', [req.params.uid]);
|
|
res.json({ room: updated });
|
|
} catch (err) {
|
|
console.error('Update room error:', err);
|
|
res.status(500).json({ error: 'Raum konnte nicht aktualisiert werden' });
|
|
}
|
|
});
|
|
|
|
// DELETE /api/rooms/:uid - Delete room
|
|
router.delete('/:uid', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get('SELECT * FROM rooms WHERE uid = ?', [req.params.uid]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden' });
|
|
}
|
|
|
|
if (room.user_id !== req.user.id && req.user.role !== 'admin') {
|
|
return res.status(403).json({ error: 'Keine Berechtigung' });
|
|
}
|
|
|
|
await db.run('DELETE FROM rooms WHERE uid = ?', [req.params.uid]);
|
|
res.json({ message: 'Raum erfolgreich gelöscht' });
|
|
} catch (err) {
|
|
console.error('Delete room error:', err);
|
|
res.status(500).json({ error: 'Raum konnte nicht gelöscht werden' });
|
|
}
|
|
});
|
|
|
|
// POST /api/rooms/:uid/start - Start meeting
|
|
router.post('/:uid/start', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get('SELECT * FROM rooms WHERE uid = ? AND user_id = ?', [req.params.uid, req.user.id]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden oder keine Berechtigung' });
|
|
}
|
|
|
|
await createMeeting(room);
|
|
const joinUrl = await joinMeeting(room.uid, req.user.name, true);
|
|
res.json({ joinUrl });
|
|
} catch (err) {
|
|
console.error('Start meeting error:', err);
|
|
res.status(500).json({ error: 'Meeting konnte nicht gestartet werden' });
|
|
}
|
|
});
|
|
|
|
// POST /api/rooms/:uid/join - Join meeting
|
|
router.post('/:uid/join', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get('SELECT * FROM rooms WHERE uid = ?', [req.params.uid]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden' });
|
|
}
|
|
|
|
// Check access code if set
|
|
if (room.access_code && req.body.access_code !== room.access_code) {
|
|
return res.status(403).json({ error: 'Falscher Zugangscode' });
|
|
}
|
|
|
|
// Check if meeting is running
|
|
const running = await isMeetingRunning(room.uid);
|
|
if (!running) {
|
|
return res.status(400).json({ error: 'Meeting läuft nicht. Bitte warten Sie, bis der Moderator das Meeting gestartet hat.' });
|
|
}
|
|
|
|
const isModerator = room.user_id === req.user.id || room.all_join_moderator;
|
|
const joinUrl = await joinMeeting(room.uid, req.user.name, isModerator);
|
|
res.json({ joinUrl });
|
|
} catch (err) {
|
|
console.error('Join meeting error:', err);
|
|
res.status(500).json({ error: 'Meeting konnte nicht beigetreten werden' });
|
|
}
|
|
});
|
|
|
|
// POST /api/rooms/:uid/end - End meeting
|
|
router.post('/:uid/end', authenticateToken, async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get('SELECT * FROM rooms WHERE uid = ? AND user_id = ?', [req.params.uid, req.user.id]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden oder keine Berechtigung' });
|
|
}
|
|
|
|
await endMeeting(room.uid);
|
|
res.json({ message: 'Meeting beendet' });
|
|
} catch (err) {
|
|
console.error('End meeting error:', err);
|
|
res.status(500).json({ error: 'Meeting konnte nicht beendet werden' });
|
|
}
|
|
});
|
|
|
|
// GET /api/rooms/:uid/public - Get public room info (no auth needed)
|
|
router.get('/:uid/public', async (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const room = await db.get(`
|
|
SELECT r.uid, r.name, r.guest_access, r.welcome_message, r.access_code,
|
|
u.name as owner_name
|
|
FROM rooms r
|
|
JOIN users u ON r.user_id = u.id
|
|
WHERE r.uid = ?
|
|
`, [req.params.uid]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden' });
|
|
}
|
|
|
|
if (!room.guest_access) {
|
|
return res.status(403).json({ error: 'Gastzugang ist für diesen Raum nicht aktiviert' });
|
|
}
|
|
|
|
const running = await isMeetingRunning(room.uid);
|
|
|
|
res.json({
|
|
room: {
|
|
uid: room.uid,
|
|
name: room.name,
|
|
owner_name: room.owner_name,
|
|
welcome_message: room.welcome_message,
|
|
has_access_code: !!room.access_code,
|
|
},
|
|
running,
|
|
});
|
|
} catch (err) {
|
|
console.error('Public room info error:', err);
|
|
res.status(500).json({ error: 'Rauminfos konnten nicht geladen werden' });
|
|
}
|
|
});
|
|
|
|
// POST /api/rooms/:uid/guest-join - Join meeting as guest (no auth needed)
|
|
router.post('/:uid/guest-join', async (req, res) => {
|
|
try {
|
|
const { name, access_code, moderator_code } = req.body;
|
|
|
|
if (!name || name.trim().length === 0) {
|
|
return res.status(400).json({ error: 'Name ist erforderlich' });
|
|
}
|
|
|
|
const db = getDb();
|
|
const room = await db.get('SELECT * FROM rooms WHERE uid = ?', [req.params.uid]);
|
|
|
|
if (!room) {
|
|
return res.status(404).json({ error: 'Raum nicht gefunden' });
|
|
}
|
|
|
|
if (!room.guest_access) {
|
|
return res.status(403).json({ error: 'Gastzugang ist für diesen Raum nicht aktiviert' });
|
|
}
|
|
|
|
// Check access code if set
|
|
if (room.access_code && access_code !== room.access_code) {
|
|
return res.status(403).json({ error: 'Falscher Zugangscode' });
|
|
}
|
|
|
|
// Check if meeting is running (or if anyone_can_start is enabled)
|
|
const running = await isMeetingRunning(room.uid);
|
|
if (!running && !room.anyone_can_start) {
|
|
return res.status(400).json({ error: 'Meeting läuft nicht. Bitte warten Sie, bis der Moderator das Meeting gestartet hat.' });
|
|
}
|
|
|
|
// If meeting not running but anyone_can_start, create it
|
|
if (!running && room.anyone_can_start) {
|
|
await createMeeting(room);
|
|
}
|
|
|
|
// Check moderator code
|
|
let isModerator = !!room.all_join_moderator;
|
|
if (!isModerator && moderator_code && room.moderator_code && moderator_code === room.moderator_code) {
|
|
isModerator = true;
|
|
}
|
|
|
|
const joinUrl = await joinMeeting(room.uid, name.trim(), isModerator);
|
|
res.json({ joinUrl });
|
|
} catch (err) {
|
|
console.error('Guest join error:', err);
|
|
res.status(500).json({ error: 'Beitritt als Gast fehlgeschlagen' });
|
|
}
|
|
});
|
|
|
|
// GET /api/rooms/:uid/status - Check if meeting is running (public, no guard needed)
|
|
router.get('/:uid/status', async (req, res) => {
|
|
try {
|
|
const running = await isMeetingRunning(req.params.uid);
|
|
let info = null;
|
|
if (running) {
|
|
try {
|
|
info = await getMeetingInfo(req.params.uid);
|
|
} catch (e) {
|
|
// Meeting info might fail
|
|
}
|
|
}
|
|
res.json({
|
|
running,
|
|
participantCount: info?.participantCount || 0,
|
|
moderatorCount: info?.moderatorCount || 0,
|
|
});
|
|
} catch (err) {
|
|
res.json({ running: false, participantCount: 0, moderatorCount: 0 });
|
|
}
|
|
});
|
|
|
|
export default router;
|