add avatar support for BBB
All checks were successful
Build & Push Docker Image / build (push) Successful in 1m10s
All checks were successful
Build & Push Docker Image / build (push) Successful in 1m10s
This commit is contained in:
BIN
redlight.db-shm
BIN
redlight.db-shm
Binary file not shown.
BIN
redlight.db-wal
BIN
redlight.db-wal
Binary file not shown.
@@ -66,7 +66,7 @@ export async function createMeeting(room, logoutURL) {
|
|||||||
return apiCall('create', params);
|
return apiCall('create', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function joinMeeting(uid, name, isModerator = false) {
|
export async function joinMeeting(uid, name, isModerator = false, avatarURL = null) {
|
||||||
const { moderatorPW, attendeePW } = getRoomPasswords(uid);
|
const { moderatorPW, attendeePW } = getRoomPasswords(uid);
|
||||||
const params = {
|
const params = {
|
||||||
meetingID: uid,
|
meetingID: uid,
|
||||||
@@ -74,6 +74,9 @@ export async function joinMeeting(uid, name, isModerator = false) {
|
|||||||
password: isModerator ? moderatorPW : attendeePW,
|
password: isModerator ? moderatorPW : attendeePW,
|
||||||
redirect: 'true',
|
redirect: 'true',
|
||||||
};
|
};
|
||||||
|
if (avatarURL) {
|
||||||
|
params.avatarURL = avatarURL;
|
||||||
|
}
|
||||||
return buildUrl('join', params);
|
return buildUrl('join', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,36 @@ router.delete('/avatar', authenticateToken, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// GET /api/auth/avatar/initials/:name - Generate SVG avatar from initials (public, BBB fetches this)
|
||||||
|
router.get('/avatar/initials/:name', (req, res) => {
|
||||||
|
const name = decodeURIComponent(req.params.name).trim();
|
||||||
|
const color = req.query.color || generateColorFromName(name);
|
||||||
|
const initials = name
|
||||||
|
.split(' ')
|
||||||
|
.map(n => n[0])
|
||||||
|
.join('')
|
||||||
|
.toUpperCase()
|
||||||
|
.slice(0, 2) || '?';
|
||||||
|
|
||||||
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
|
||||||
|
<rect width="128" height="128" rx="64" fill="${color}"/>
|
||||||
|
<text x="64" y="64" dy=".35em" text-anchor="middle" fill="white" font-family="Arial, sans-serif" font-size="52" font-weight="bold">${initials}</text>
|
||||||
|
</svg>`;
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'image/svg+xml');
|
||||||
|
res.setHeader('Cache-Control', 'public, max-age=3600');
|
||||||
|
res.send(svg);
|
||||||
|
});
|
||||||
|
|
||||||
|
function generateColorFromName(name) {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < name.length; i++) {
|
||||||
|
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
const hue = Math.abs(hash) % 360;
|
||||||
|
return `hsl(${hue}, 55%, 45%)`;
|
||||||
|
}
|
||||||
|
|
||||||
// GET /api/auth/avatar/:filename - Serve avatar image
|
// GET /api/auth/avatar/:filename - Serve avatar image
|
||||||
router.get('/avatar/:filename', (req, res) => {
|
router.get('/avatar/:filename', (req, res) => {
|
||||||
const filepath = path.join(uploadsDir, req.params.filename);
|
const filepath = path.join(uploadsDir, req.params.filename);
|
||||||
|
|||||||
@@ -12,6 +12,16 @@ import {
|
|||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
// Build avatar URL for a user (uploaded image or generated initials)
|
||||||
|
function getUserAvatarURL(req, user) {
|
||||||
|
const baseUrl = `${req.protocol}://${req.get('host')}`;
|
||||||
|
if (user.avatar_image) {
|
||||||
|
return `${baseUrl}/api/auth/avatar/${user.avatar_image}`;
|
||||||
|
}
|
||||||
|
const color = user.avatar_color ? `?color=${encodeURIComponent(user.avatar_color)}` : '';
|
||||||
|
return `${baseUrl}/api/auth/avatar/initials/${encodeURIComponent(user.name)}${color}`;
|
||||||
|
}
|
||||||
|
|
||||||
// GET /api/rooms - List user's rooms
|
// GET /api/rooms - List user's rooms
|
||||||
router.get('/', authenticateToken, async (req, res) => {
|
router.get('/', authenticateToken, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@@ -199,7 +209,8 @@ router.post('/:uid/start', authenticateToken, async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await createMeeting(room, `${req.protocol}://${req.get('host')}`);
|
await createMeeting(room, `${req.protocol}://${req.get('host')}`);
|
||||||
const joinUrl = await joinMeeting(room.uid, req.user.name, true);
|
const avatarURL = getUserAvatarURL(req, req.user);
|
||||||
|
const joinUrl = await joinMeeting(room.uid, req.user.name, true, avatarURL);
|
||||||
res.json({ joinUrl });
|
res.json({ joinUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Start meeting error:', err);
|
console.error('Start meeting error:', err);
|
||||||
@@ -229,7 +240,8 @@ router.post('/:uid/join', authenticateToken, async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isModerator = room.user_id === req.user.id || room.all_join_moderator;
|
const isModerator = room.user_id === req.user.id || room.all_join_moderator;
|
||||||
const joinUrl = await joinMeeting(room.uid, req.user.name, isModerator);
|
const avatarURL = getUserAvatarURL(req, req.user);
|
||||||
|
const joinUrl = await joinMeeting(room.uid, req.user.name, isModerator, avatarURL);
|
||||||
res.json({ joinUrl });
|
res.json({ joinUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Join meeting error:', err);
|
console.error('Join meeting error:', err);
|
||||||
@@ -335,7 +347,9 @@ router.post('/:uid/guest-join', async (req, res) => {
|
|||||||
isModerator = true;
|
isModerator = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const joinUrl = await joinMeeting(room.uid, name.trim(), isModerator);
|
const baseUrl = `${req.protocol}://${req.get('host')}`;
|
||||||
|
const guestAvatarURL = `${baseUrl}/api/auth/avatar/initials/${encodeURIComponent(name.trim())}`;
|
||||||
|
const joinUrl = await joinMeeting(room.uid, name.trim(), isModerator, guestAvatarURL);
|
||||||
res.json({ joinUrl });
|
res.json({ joinUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Guest join error:', err);
|
console.error('Guest join error:', err);
|
||||||
|
|||||||
Reference in New Issue
Block a user