From f7735ba8d9a2a06ea5d84f39620efdf7c717e6fb Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Tue, 22 Jul 2025 07:08:09 -0500 Subject: [PATCH] Add user promotion endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔧 Admin Management: - Add api/admin/promote-user.js endpoint - Allows promoting users to admin role by username or userId - Checks for existing admin status - Returns updated user info with roles - Handles database errors gracefully Usage: POST /api/admin/promote-user with { username: 'testuser' } --- api/admin/promote-user.js | 128 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 api/admin/promote-user.js diff --git a/api/admin/promote-user.js b/api/admin/promote-user.js new file mode 100644 index 0000000..303337a --- /dev/null +++ b/api/admin/promote-user.js @@ -0,0 +1,128 @@ +const { Pool } = require('pg'); + +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false, +}); + +export default async function handler(req, res) { + if (req.method !== 'POST') { + return res.status(405).json({ error: 'Method not allowed' }); + } + + try { + const body = JSON.parse(req.body || '{}'); + const { username, userId } = body; + + if (!username && !userId) { + return res.status(400).json({ + error: 'Either username or userId is required' + }); + } + + const client = await pool.connect(); + + try { + // Find the user + let userQuery; + let userParams; + + if (userId) { + userQuery = 'SELECT id, username, email FROM users WHERE id = $1'; + userParams = [userId]; + } else { + userQuery = 'SELECT id, username, email FROM users WHERE username = $1'; + userParams = [username]; + } + + const userResult = await client.query(userQuery, userParams); + + if (userResult.rows.length === 0) { + return res.status(404).json({ + error: 'User not found' + }); + } + + const user = userResult.rows[0]; + + // Check if user is already an admin + const adminCheckQuery = ` + SELECT ur.user_id + FROM user_roles ur + JOIN roles r ON ur.role_id = r.id + WHERE ur.user_id = $1 AND r.name = 'admin' + `; + + const adminCheck = await client.query(adminCheckQuery, [user.id]); + + if (adminCheck.rows.length > 0) { + return res.status(200).json({ + success: true, + message: 'User is already an admin', + user: { + id: user.id, + username: user.username, + email: user.email + } + }); + } + + // Get admin role ID + const roleResult = await client.query( + 'SELECT id FROM roles WHERE name = $1', + ['admin'] + ); + + if (roleResult.rows.length === 0) { + return res.status(500).json({ + error: 'Admin role not found in database' + }); + } + + const adminRoleId = roleResult.rows[0].id; + + // Add user to admin role + await client.query( + 'INSERT INTO user_roles (user_id, role_id) VALUES ($1, $2)', + [user.id, adminRoleId] + ); + + // Get updated user info with roles + const updatedUserQuery = ` + SELECT + u.id, u.username, u.email, u.first_name, u.last_name, + ARRAY_AGG(DISTINCT r.name) 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 + WHERE u.id = $1 + GROUP BY u.id, u.username, u.email, u.first_name, u.last_name + `; + + const updatedUser = await client.query(updatedUserQuery, [user.id]); + + res.status(200).json({ + success: true, + message: 'User successfully promoted to admin', + user: { + id: updatedUser.rows[0].id, + username: updatedUser.rows[0].username, + email: updatedUser.rows[0].email, + firstName: updatedUser.rows[0].first_name, + lastName: updatedUser.rows[0].last_name, + roles: updatedUser.rows[0].roles || [] + } + }); + + } finally { + client.release(); + } + + } catch (error) { + console.error('Promote user error:', error); + res.status(500).json({ + error: 'Internal server error', + details: error.message + }); + } +} \ No newline at end of file