feat: implement comprehensive admin functionality
- Add admin role system with role and isAdmin fields to users table - Create admin_actions audit log table for tracking all admin operations - Implement admin CLI tool for user management (create, promote, demote, list, check) - Add admin authentication with role-based access control - Create admin service layer with system statistics and user management - Implement user impersonation system with proper security checks - Add admin API endpoints for user management and system statistics - Create admin dashboard UI with overview, users, and action logs - Fix admin stats endpoint and user deletion with proper foreign key handling - Add admin link to navigation bar for admin users Database: - Add role and isAdmin columns to users table - Create admin_actions table for audit trail - Migration script: add-admin-functionality.js CLI: - src/backend/scripts/admin-cli.js - Admin user management tool Backend: - src/backend/services/admin.service.js - Admin business logic - Updated auth.service.js with admin helper functions - Enhanced index.js with admin routes and middleware - Export sqlite connection from config for raw SQL operations Frontend: - src/frontend/src/routes/admin/+page.svelte - Admin dashboard - Updated api.js with adminAPI functions - Added Admin link to navigation bar Security: - Admin-only endpoints with role verification - Audit logging for all admin actions - Impersonation with 1-hour token expiration - Foreign key constraint handling for user deletion - Cannot delete self or other admins - Last admin protection
This commit is contained in:
@@ -142,3 +142,102 @@ export async function updateDCLCredentials(userId, dclApiKey) {
|
||||
})
|
||||
.where(eq(users.id, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is admin
|
||||
* @param {number} userId - User ID
|
||||
* @returns {Promise<boolean>} True if user is admin
|
||||
*/
|
||||
export async function isAdmin(userId) {
|
||||
const [user] = await db
|
||||
.select({ isAdmin: users.isAdmin })
|
||||
.from(users)
|
||||
.where(eq(users.id, userId))
|
||||
.limit(1);
|
||||
|
||||
return user?.isAdmin === true || user?.isAdmin === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all admin users
|
||||
* @returns {Promise<Array>} Array of admin users (without passwords)
|
||||
*/
|
||||
export async function getAdminUsers() {
|
||||
const adminUsers = await db
|
||||
.select({
|
||||
id: users.id,
|
||||
email: users.email,
|
||||
callsign: users.callsign,
|
||||
role: users.role,
|
||||
isAdmin: users.isAdmin,
|
||||
createdAt: users.createdAt,
|
||||
})
|
||||
.from(users)
|
||||
.where(eq(users.isAdmin, 1));
|
||||
|
||||
return adminUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user role
|
||||
* @param {number} userId - User ID
|
||||
* @param {string} role - New role ('user' or 'admin')
|
||||
* @param {boolean} isAdmin - Admin flag
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function updateUserRole(userId, role, isAdmin) {
|
||||
await db
|
||||
.update(users)
|
||||
.set({
|
||||
role,
|
||||
isAdmin: isAdmin ? 1 : 0,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(users.id, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users (for admin use)
|
||||
* @returns {Promise<Array>} Array of all users (without passwords)
|
||||
*/
|
||||
export async function getAllUsers() {
|
||||
const allUsers = await db
|
||||
.select({
|
||||
id: users.id,
|
||||
email: users.email,
|
||||
callsign: users.callsign,
|
||||
role: users.role,
|
||||
isAdmin: users.isAdmin,
|
||||
createdAt: users.createdAt,
|
||||
updatedAt: users.updatedAt,
|
||||
})
|
||||
.from(users)
|
||||
.orderBy(users.createdAt);
|
||||
|
||||
return allUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user by ID (for admin use)
|
||||
* @param {number} userId - User ID
|
||||
* @returns {Promise<Object|null>} Full user object (without password) or null
|
||||
*/
|
||||
export async function getUserByIdFull(userId) {
|
||||
const [user] = await db
|
||||
.select({
|
||||
id: users.id,
|
||||
email: users.email,
|
||||
callsign: users.callsign,
|
||||
role: users.role,
|
||||
isAdmin: users.isAdmin,
|
||||
lotwUsername: users.lotwUsername,
|
||||
dclApiKey: users.dclApiKey,
|
||||
createdAt: users.createdAt,
|
||||
updatedAt: users.updatedAt,
|
||||
})
|
||||
.from(users)
|
||||
.where(eq(users.id, userId))
|
||||
.limit(1);
|
||||
|
||||
return user || null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user