mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
137 lines
4.9 KiB
JavaScript
137 lines
4.9 KiB
JavaScript
/***********************************************************************************************************************************************************************
|
|
* File Name: user_activity.controller.js (admin)
|
|
* Type of Program: Controller
|
|
* Description: Admin-only view of the user_activity log.
|
|
*
|
|
* GET /api/admin/activity → global paginated activity feed (all users)
|
|
* GET /api/admin/users/:id/activity → paginated activity for a single user
|
|
*
|
|
* Author: Kenneth Obsequio (@lash0000)
|
|
* Date Created: Jun. 21, 2026
|
|
***********************************************************************************************************************************************************************/
|
|
const { Op } = require('sequelize');
|
|
const mdl_UserActivity = require('../../models/users/user_activity.mdl');
|
|
const mdl_Users = require('../../models/users/users.mdl');
|
|
const R = require('../../utils/response.util');
|
|
|
|
const USER_ATTRS = [
|
|
'user_id', 'email', 'acc_type',
|
|
// full_name from JSONB — resolved in the association below
|
|
];
|
|
|
|
// ─── Shared query builder ─────────────────────────────────────────────────────
|
|
|
|
function buildWhere(query, extraWhere = {}) {
|
|
const where = { ...extraWhere };
|
|
|
|
if (query.action)
|
|
where.action = query.action;
|
|
|
|
if (query.from || query.to) {
|
|
where.created_at = {};
|
|
if (query.from) where.created_at[Op.gte] = new Date(query.from);
|
|
if (query.to) {
|
|
// `to` arrives as a date-only string (e.g. "2026-06-04"), which parses
|
|
// to that day's UTC midnight — an Op.lte against midnight excludes
|
|
// every event that happened later the same day. Push it to the last
|
|
// instant of that calendar day instead.
|
|
const to = new Date(query.to);
|
|
to.setUTCHours(23, 59, 59, 999);
|
|
where.created_at[Op.lte] = to;
|
|
}
|
|
}
|
|
|
|
return where;
|
|
}
|
|
|
|
// ─── GET GLOBAL ACTIVITY FEED ─────────────────────────────────────────────────
|
|
|
|
exports.getActivity = async (req, res) => {
|
|
try {
|
|
const page = Math.max(1, parseInt(req.query.page) || 1);
|
|
const limit = Math.min(100, parseInt(req.query.limit) || 20);
|
|
const offset = (page - 1) * limit;
|
|
|
|
const where = buildWhere(req.query);
|
|
|
|
const { count, rows } = await mdl_UserActivity.findAndCountAll({
|
|
where,
|
|
include: [{
|
|
model: mdl_Users,
|
|
as: 'user',
|
|
attributes: ['user_id', 'email', 'acc_type', 'personal_info'],
|
|
}],
|
|
order: [['created_at', 'DESC']],
|
|
limit,
|
|
offset,
|
|
});
|
|
|
|
const data = rows.map(formatRow);
|
|
|
|
return R.success(res, 'Activity feed retrieved.', {
|
|
total: count,
|
|
page,
|
|
totalPages: Math.ceil(count / limit),
|
|
activities: data,
|
|
});
|
|
} catch (err) {
|
|
console.error('[ADMIN][GET ACTIVITY FEED]', err);
|
|
return R.error(res, 'Could not retrieve activity feed.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── GET PER-USER ACTIVITY ────────────────────────────────────────────────────
|
|
|
|
exports.getUserActivity = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
if (!id || id === 'undefined') return R.error(res, 'Invalid User ID.', 400);
|
|
|
|
const user = await mdl_Users.findByPk(id, { attributes: ['user_id'] });
|
|
if (!user) return R.error(res, 'User not found.', 404);
|
|
|
|
const page = Math.max(1, parseInt(req.query.page) || 1);
|
|
const limit = Math.min(100, parseInt(req.query.limit) || 20);
|
|
const offset = (page - 1) * limit;
|
|
|
|
const where = buildWhere(req.query, { user_id: id });
|
|
|
|
const { count, rows } = await mdl_UserActivity.findAndCountAll({
|
|
where,
|
|
order: [['created_at', 'DESC']],
|
|
limit,
|
|
offset,
|
|
});
|
|
|
|
return R.success(res, 'User activity retrieved.', {
|
|
total: count,
|
|
page,
|
|
totalPages: Math.ceil(count / limit),
|
|
activities: rows,
|
|
});
|
|
} catch (err) {
|
|
console.error('[ADMIN][GET USER ACTIVITY]', err);
|
|
return R.error(res, 'Could not retrieve user activity.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
function formatRow(row) {
|
|
const r = row.toJSON();
|
|
const info = r.user?.personal_info;
|
|
return {
|
|
activity_id: r.activity_id,
|
|
user_id: r.user_id,
|
|
email: r.user?.email ?? null,
|
|
full_name: info?.name?.full_name ?? null,
|
|
avatar_url: info?.avatar?.url ?? null,
|
|
acc_type: r.user?.acc_type ?? null,
|
|
action: r.action,
|
|
entity_type: r.entity_type,
|
|
entity_id: r.entity_id,
|
|
details: r.details,
|
|
created_at: r.created_at,
|
|
};
|
|
}
|