Files
DiscordClone/Backend/routes/roles.js

214 lines
7.5 KiB
JavaScript

const express = require('express');
const router = express.Router();
const db = require('../db');
// Middleware to check for permissions (simplified for now)
// In a real app, you'd check if req.user has the permission
// Middleware to check for permissions
const checkPermission = (requiredPerm) => {
return async (req, res, next) => {
const userId = req.headers['x-user-id'];
if (!userId) {
return res.status(401).json({ error: 'Unauthorized: No User ID' });
}
try {
// Fetch all roles for user and aggregate permissions
const result = await db.query(`
SELECT r.permissions
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
WHERE ur.user_id = $1
`, [userId]);
let hasPermission = false;
// Check if ANY of the user's roles has the permission
for (const row of result.rows) {
const perms = row.permissions || {};
// If Manage Roles is true, or if checking for something else and they have it
if (perms[requiredPerm] === true) {
hasPermission = true;
break;
}
// Implicit Admin/Owner check: if they have 'manage_roles' and we are checking something lower?
// For "Owner" role, we seeded it with specific true values.
// But let's check for 'administrator' equivalent if we had it.
// For now, implicit check: if we need 'manage_roles', look for it.
}
if (!hasPermission) {
return res.status(403).json({ error: `Forbidden: Missing ${requiredPerm}` });
}
next();
} catch (err) {
console.error('Permission check failed:', err);
return res.status(500).json({ error: 'Internal Server Error' });
}
};
};
// GET /api/roles/permissions - Get current user's permissions
router.get('/permissions', async (req, res) => {
const userId = req.headers['x-user-id'];
if (!userId) return res.json({}); // No perms if no ID
try {
const result = await db.query(`
SELECT r.permissions
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
WHERE ur.user_id = $1
`, [userId]);
const finalPerms = {
manage_channels: false,
manage_roles: false,
create_invite: false,
embed_links: false,
attach_files: false
};
for (const row of result.rows) {
const p = row.permissions || {};
if (p.manage_channels) finalPerms.manage_channels = true;
if (p.manage_roles) finalPerms.manage_roles = true;
if (p.create_invite) finalPerms.create_invite = true;
if (p.embed_links) finalPerms.embed_links = true;
if (p.attach_files) finalPerms.attach_files = true;
}
res.json(finalPerms);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// GET /api/roles - List all roles
router.get('/', async (req, res) => {
try {
const result = await db.query('SELECT * FROM roles ORDER BY position DESC, id ASC');
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// POST /api/roles - Create new role
router.post('/', checkPermission('manage_roles'), async (req, res) => {
const { name, color, permissions, position, is_hoist } = req.body;
try {
const result = await db.query(
'INSERT INTO roles (name, color, permissions, position, is_hoist) VALUES ($1, $2, $3, $4, $5) RETURNING *',
[name || 'new role', color || '#99aab5', permissions || {}, position || 0, is_hoist || false]
);
res.json(result.rows[0]);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// PUT /api/roles/:id - Update role
router.put('/:id', checkPermission('manage_roles'), async (req, res) => {
const { id } = req.params;
const { name, color, permissions, position, is_hoist } = req.body;
// Dynamic update query
const fields = [];
const values = [];
let idx = 1;
if (name !== undefined) { fields.push(`name = $${idx++}`); values.push(name); }
if (color !== undefined) { fields.push(`color = $${idx++}`); values.push(color); }
if (permissions !== undefined) { fields.push(`permissions = $${idx++}`); values.push(permissions); }
if (position !== undefined) { fields.push(`position = $${idx++}`); values.push(position); }
if (is_hoist !== undefined) { fields.push(`is_hoist = $${idx++}`); values.push(is_hoist); }
if (fields.length === 0) return res.json({ success: true }); // Nothing to update
values.push(id);
const query = `UPDATE roles SET ${fields.join(', ')} WHERE id = $${idx} RETURNING *`;
try {
const result = await db.query(query, values);
if (result.rows.length === 0) return res.status(404).json({ error: 'Role not found' });
res.json(result.rows[0]);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// DELETE /api/roles/:id - Delete role
router.delete('/:id', checkPermission('manage_roles'), async (req, res) => {
const { id } = req.params;
try {
// user_roles cascade handled by DB
const result = await db.query('DELETE FROM roles WHERE id = $1 RETURNING *', [id]);
if (result.rows.length === 0) return res.status(404).json({ error: 'Role not found' });
res.json({ success: true, deletedId: id });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// GET /api/roles/members - List members with roles
// (This is effectively GET /api/users but enriched with roles)
router.get('/members', async (req, res) => {
try {
const result = await db.query(`
SELECT u.id, u.username, u.public_identity_key,
json_agg(r.*) FILTER (WHERE r.id IS NOT NULL) as roles
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
GROUP BY u.id
`);
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// POST /api/roles/:id/assign - Assign role to user
router.post('/:id/assign', checkPermission('manage_roles'), async (req, res) => {
const { id } = req.params; // role id
const { userId } = req.body;
try {
await db.query(
'INSERT INTO user_roles (user_id, role_id) VALUES ($1, $2) ON CONFLICT DO NOTHING',
[userId, id]
);
res.json({ success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
// POST /api/roles/:id/remove - Remove role from user
router.post('/:id/remove', checkPermission('manage_roles'), async (req, res) => {
const { id } = req.params; // role id
const { userId } = req.body;
try {
await db.query(
'DELETE FROM user_roles WHERE user_id = $1 AND role_id = $2',
[userId, id]
);
res.json({ success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
});
module.exports = router;