mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -1,8 +1,8 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* File Name : issue_certificates.cron.js
|
||||
* Type : Cron Job
|
||||
* Description : Issues certificates for users who passed a course assessment
|
||||
* 45 minutes ago. Runs every 5 minutes and processes any
|
||||
* Description : Issues certificates for users who passed a course assessment.
|
||||
* Runs every hour on the hour and processes any
|
||||
* pending_certificates row where issue_at <= NOW() and
|
||||
* processed_at IS NULL.
|
||||
*
|
||||
@@ -16,7 +16,7 @@
|
||||
* step 2 succeed. If the process restarts mid-run the row will be
|
||||
* picked up again on the next tick — both DB writes are idempotent.
|
||||
*
|
||||
* Schedule : Every hour at minute 5 ("5 * * * *"). Registered by
|
||||
* Schedule : Every hour on the hour ("0 * * * *"). Registered by
|
||||
* cron/client.cron.js.
|
||||
*
|
||||
* Author: Kenneth Obsequio (@lash0000)
|
||||
@@ -30,8 +30,6 @@ const mdl_Achievements = require('../../models/users/achievements.mdl');
|
||||
const UserNotification = require('../../models/notifications/user_notification.mdl');
|
||||
const { NOTIFICATION_REGISTRY } = require('../../data/notifications.data');
|
||||
|
||||
const DELAY_MS = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
async function run() {
|
||||
// ── 1. Fetch all rows ready to process ────────────────────────────────────
|
||||
let rows;
|
||||
@@ -104,6 +102,6 @@ async function run() {
|
||||
|
||||
module.exports = {
|
||||
name: 'issueCertificates',
|
||||
schedule: '5 * * * *',
|
||||
schedule: '0 * * * *',
|
||||
run,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* File Name : lift_expired_bans.cron.js
|
||||
* Type : Cron Job
|
||||
* Description : Automatically lifts temporary bans whose expires_at has passed.
|
||||
* Clears is_banned + ban_expires_at on the user record and marks
|
||||
* the ban row as lifted with a system lift_reason.
|
||||
*
|
||||
* Note: The auth middleware also auto-lifts expired bans inline on
|
||||
* the next login attempt, so this cron is a safety net — it keeps
|
||||
* the DB state clean even if a user never logs in again.
|
||||
*
|
||||
* Schedule : Every hour, on the hour ("0 * * * *"). Registered by
|
||||
* cron/admin.cron.js.
|
||||
*
|
||||
* Author: Kenneth Obsequio
|
||||
* Date Created: Jun. 27, 2026
|
||||
***********************************************************************************************************************************************************************/
|
||||
const { Op } = require('sequelize');
|
||||
const sequelize = require('../../config/db.config');
|
||||
const mdl_Users = require('../../models/users/users.mdl');
|
||||
const mdl_UserBans = require('../../models/users/user_bans.mdl');
|
||||
const { sendEmail } = require('../../services/email.service');
|
||||
const { fmtDate } = require('../../utils/datetime.util');
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
const expiredBans = await mdl_UserBans.findAll({
|
||||
where: {
|
||||
ban_type: 'temporary',
|
||||
is_lifted: false,
|
||||
expires_at: { [Op.lte]: new Date() },
|
||||
},
|
||||
});
|
||||
|
||||
if (!expiredBans.length) return;
|
||||
|
||||
const banIds = expiredBans.map((b) => b.ban_id);
|
||||
const userIds = [...new Set(expiredBans.map((b) => Number(b.user_id)))];
|
||||
const usersMap = await mdl_Users.findAll({
|
||||
where: { user_id: userIds },
|
||||
attributes: ['user_id', 'email', 'personal_info'],
|
||||
}).then((rows) => Object.fromEntries(rows.map((u) => [u.user_id, u])));
|
||||
|
||||
await sequelize.transaction(async (t) => {
|
||||
await mdl_UserBans.update(
|
||||
{
|
||||
is_lifted: true,
|
||||
lifted_at: new Date(),
|
||||
lift_reason: 'Automatically lifted — ban period expired.',
|
||||
},
|
||||
{ where: { ban_id: banIds }, transaction: t }
|
||||
);
|
||||
|
||||
await mdl_Users.update(
|
||||
{ is_banned: false, ban_expires_at: null },
|
||||
{ where: { user_id: userIds }, transaction: t }
|
||||
);
|
||||
});
|
||||
|
||||
const dateStr = fmtDate(new Date());
|
||||
userIds.forEach((uid) => {
|
||||
const u = usersMap[uid];
|
||||
if (!u) return;
|
||||
sendEmail({
|
||||
to: u.email,
|
||||
type: 'BAN_LIFTED',
|
||||
data: {
|
||||
name: u.personal_info?.name?.full_name ?? 'User',
|
||||
email: u.email,
|
||||
date: dateStr,
|
||||
},
|
||||
}).catch((err) => console.error('[CRON][LIFT EXPIRED BANS] Email failed:', u.email, err));
|
||||
});
|
||||
|
||||
console.log(`[CRON][LIFT EXPIRED BANS] Lifted ${expiredBans.length} ban(s) for ${userIds.length} user(s).`);
|
||||
} catch (err) {
|
||||
console.error('[CRON][LIFT EXPIRED BANS] Failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
name: 'liftExpiredBans',
|
||||
schedule: '0 * * * *',
|
||||
run,
|
||||
};
|
||||
Reference in New Issue
Block a user