mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -8,6 +8,7 @@
|
||||
* Currently registered:
|
||||
* - userNotifications (cron/jobs/user_notifications.cron.js)
|
||||
* - issueCertificates (cron/jobs/issue_certificates.cron.js)
|
||||
* - expireUserTiers (cron/jobs/expire_user_tiers.cron.js)
|
||||
*
|
||||
* Author: Kenneth Obsequio (@lash0000)
|
||||
* Date Created: Jun. 17, 2026
|
||||
@@ -15,11 +16,13 @@
|
||||
const cron = require('node-cron');
|
||||
const userNotifications = require('./jobs/user_notifications.cron');
|
||||
const issueCertificates = require('./jobs/issue_certificates.cron');
|
||||
const expireUserTiers = require('./jobs/expire_user_tiers.cron');
|
||||
|
||||
// ─── Registry — add future client-side cron jobs here ────────────────────────
|
||||
const jobs = [
|
||||
userNotifications,
|
||||
issueCertificates,
|
||||
expireUserTiers,
|
||||
];
|
||||
|
||||
// ─── Boot all registered client-side jobs ─────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* File Name : expire_user_tiers.cron.js
|
||||
* Type : Cron Job
|
||||
* Description : Marks active user_tiers rows as 'expired' when their expires_at
|
||||
* has passed. Runs every minute to support short-duration plans
|
||||
* (minute- and hour-level plans in addition to day/month/year).
|
||||
*
|
||||
* For each expired batch it:
|
||||
* 1. Bulk-updates matching rows to status = 'expired'.
|
||||
* 2. Sends an in-app UserNotification to each affected user.
|
||||
*
|
||||
* Safety:
|
||||
* - Only touches rows with expires_at IS NOT NULL so
|
||||
* manually-granted unlimited tiers (expires_at = NULL) are
|
||||
* never touched.
|
||||
* - Bulk update happens before notifications so a restart
|
||||
* mid-run never re-expires already-expired rows.
|
||||
*
|
||||
* Schedule : Every minute ("* * * * *"). Registered by cron/client.cron.js.
|
||||
*
|
||||
* Author: Kenneth Obsequio (@lash0000)
|
||||
* Date Created: Jun. 29, 2026
|
||||
***********************************************************************************************************************************************************************/
|
||||
'use strict';
|
||||
|
||||
const { Op } = require('sequelize');
|
||||
const mdl_UserTiers = require('../../models/tiers/user_tiers.mdl');
|
||||
const mdl_TierPlans = require('../../models/tiers/tier_plans.mdl');
|
||||
const UserNotification = require('../../models/notifications/user_notification.mdl');
|
||||
const { NOTIFICATION_REGISTRY } = require('../../data/notifications.data');
|
||||
|
||||
require('../../models/tiers/tier.associations');
|
||||
|
||||
async function run() {
|
||||
// ── 1. Find all active tiers whose expires_at has passed ──────────────────
|
||||
let expired;
|
||||
try {
|
||||
expired = await mdl_UserTiers.findAll({
|
||||
where: {
|
||||
status: 'active',
|
||||
expires_at: { [Op.ne]: null, [Op.lte]: new Date() },
|
||||
},
|
||||
include: [{
|
||||
model: mdl_TierPlans,
|
||||
as: 'plan',
|
||||
attributes: ['label', 'tier'],
|
||||
required: false,
|
||||
}],
|
||||
attributes: ['tier_id', 'user_id', 'tier'],
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[CRON][EXPIRE TIERS] Failed to query user_tiers:', err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!expired.length) return;
|
||||
|
||||
const tierIds = expired.map((t) => t.tier_id);
|
||||
|
||||
// ── 2. Bulk-update to expired ──────────────────────────────────────────────
|
||||
try {
|
||||
await mdl_UserTiers.update(
|
||||
{ status: 'expired' },
|
||||
{ where: { tier_id: tierIds } }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('[CRON][EXPIRE TIERS] Bulk update failed:', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// ── 3. Send in-app notifications (one per affected user) ──────────────────
|
||||
const notifications = expired.map((t) =>
|
||||
NOTIFICATION_REGISTRY.tier_expired.build({
|
||||
tier: t.tier,
|
||||
label: t.plan?.label ?? null,
|
||||
})
|
||||
).map((payload, i) => ({
|
||||
user_id: expired[i].user_id,
|
||||
...payload,
|
||||
}));
|
||||
|
||||
try {
|
||||
await UserNotification.bulkCreate(notifications, { ignoreDuplicates: true });
|
||||
} catch (err) {
|
||||
console.error('[CRON][EXPIRE TIERS] Notification bulkCreate failed:', err);
|
||||
}
|
||||
|
||||
console.log(`[CRON][EXPIRE TIERS] Expired ${expired.length} tier(s) for ${new Set(expired.map((t) => t.user_id)).size} user(s).`);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
name: 'expireUserTiers',
|
||||
schedule: '* * * * *',
|
||||
run,
|
||||
};
|
||||
Reference in New Issue
Block a user