Admin Dashboard Backend (Phases 1-4) (#5)
Some checks failed
Deploy Apartment API / deploy (push) Failing after 5m1s

Co-authored-by: Stephen Minakian <stephenminakian@gmail.com>
Co-committed-by: Stephen Minakian <stephenminakian@gmail.com>
This commit is contained in:
2026-01-22 14:11:43 -07:00
committed by stephen
parent d6e56a6e40
commit 81e5682ab1
16 changed files with 11215 additions and 31 deletions

View File

@ -69,37 +69,68 @@ function shouldLog(action) {
return allowedActions.includes(action);
}
/**
* Check if an action is an admin action (always logged regardless of log level)
* @param {string} action - Action to check
* @returns {boolean} True if admin action
*/
function isAdminAction(action) {
return action && action.startsWith('ADMIN_');
}
/**
* Log a user activity to the database
* Supports two calling conventions:
* 1. logActivity(db, userId, action, metadata, req) - positional parameters
* 2. logActivity(db, { userId, action, metadata }) - object parameter for admin actions
*
* @param {Db} db - MongoDB database instance
* @param {string} userId - User ID (will be converted to ObjectId)
* @param {string} action - Action type (use ACTIONS constants)
* @param {Object} metadata - Additional action-specific data
* @param {Object} req - Express request object (for IP and user agent)
* @param {string|Object} userIdOrOptions - User ID string or options object
* @param {string} [action] - Action type (use ACTIONS constants)
* @param {Object} [metadata] - Additional action-specific data
* @param {Object} [req] - Express request object (for IP and user agent)
* @returns {Promise<void>}
*/
async function logActivity(db, userId, action, metadata = {}, req = null) {
// Only log if this action type is enabled at current log level
if (!shouldLog(action)) {
async function logActivity(db, userIdOrOptions, action, metadata = {}, req = null) {
let userId;
let actualAction;
let actualMetadata;
let actualReq;
// Support object-based call for admin actions
if (typeof userIdOrOptions === 'object' && userIdOrOptions !== null) {
userId = userIdOrOptions.userId;
actualAction = userIdOrOptions.action;
actualMetadata = userIdOrOptions.metadata || {};
actualReq = userIdOrOptions.req || null;
} else {
userId = userIdOrOptions;
actualAction = action;
actualMetadata = metadata;
actualReq = req;
}
// Admin actions bypass log level filtering
if (!isAdminAction(actualAction) && !shouldLog(actualAction)) {
return;
}
try {
// Extract IP address (handle proxy forwarding)
let ip = null;
if (req) {
ip = req.ip || req.headers?.['x-forwarded-for']?.split(',')[0] || null;
if (actualReq) {
ip = actualReq.ip || actualReq.headers?.['x-forwarded-for']?.split(',')[0] || null;
}
// Extract user agent
const userAgent = req?.headers?.['user-agent'] || null;
const userAgent = actualReq?.headers?.['user-agent'] || null;
// Create activity document
const activityDoc = {
userId: new ObjectId(userId),
action: action,
metadata: metadata || {},
page: metadata?.page || null,
action: actualAction,
metadata: actualMetadata || {},
page: actualMetadata?.page || null,
timestamp: new Date(),
userAgent: userAgent,
ip: ip