Admin Dashboard Backend (Phases 1-4) (#5)
Some checks failed
Deploy Apartment API / deploy (push) Failing after 5m1s
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:
@ -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
|
||||
|
||||
Reference in New Issue
Block a user