feat: Implement Phase 2 cross-cutting services with email and notification enhancements
- Refactor email verification and password reset utilities to use new email service. - Introduce email delivery queue and notification delivery model for better tracking. - Enhance file validation and storage services for improved security and ownership management. - Add cron job for cleaning inactive notifications with retention policy. - Update document worker to handle document generation and storage more efficiently. - Implement logging improvements in activity and log workers. - Create comprehensive documentation for new API endpoints and services. - Add unit tests for file validation and notification policies to ensure robustness.
This commit is contained in:
@@ -1,98 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Niolla
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is proprietary and confidential.
|
||||
* Unauthorized copying, modification, distribution, or use
|
||||
* of this file, via any medium, is strictly prohibited.
|
||||
*/
|
||||
|
||||
// cron/cleanInactiveNotifications.cron.js
|
||||
|
||||
const cron = require("node-cron");
|
||||
const { Op } = require("sequelize");
|
||||
const { sequelize, notification, userNotification } = require("../app/models");
|
||||
|
||||
const {
|
||||
sequelize,
|
||||
notification,
|
||||
userNotification,
|
||||
} = require("../app/models");
|
||||
|
||||
function startCleanInactiveNotificationsCron() {
|
||||
console.log("Inactive Notification Cleanup Cron Started");
|
||||
|
||||
const task = cron.schedule(
|
||||
"0 0 * * *", // Run every day at midnight
|
||||
async () => {
|
||||
console.log(
|
||||
`[CRON] Cleaning inactive notifications... ${new Date().toISOString()}`,
|
||||
);
|
||||
|
||||
try {
|
||||
const inactiveNotifications = await notification.findAll({
|
||||
where: {
|
||||
isActive: false,
|
||||
},
|
||||
attributes: ["notification_id"],
|
||||
});
|
||||
|
||||
if (!inactiveNotifications.length) {
|
||||
console.log("[CRON] No inactive notifications found.");
|
||||
return;
|
||||
}
|
||||
|
||||
const notificationIds = inactiveNotifications.map(
|
||||
(item) => item.notification_id,
|
||||
);
|
||||
|
||||
const transaction = await sequelize.transaction();
|
||||
|
||||
try {
|
||||
// Delete user-notification relationships first
|
||||
const deletedUserNotifications = await userNotification.destroy({
|
||||
where: {
|
||||
notification_id: notificationIds,
|
||||
},
|
||||
transaction,
|
||||
});
|
||||
|
||||
// Delete inactive notifications
|
||||
const deletedNotifications = await notification.destroy({
|
||||
where: {
|
||||
notification_id: notificationIds,
|
||||
isActive: false,
|
||||
},
|
||||
transaction,
|
||||
});
|
||||
|
||||
await transaction.commit();
|
||||
|
||||
console.log(
|
||||
`[CRON] Cleanup completed. Deleted ${deletedNotifications} notifications and ${deletedUserNotifications} user notification records.`,
|
||||
);
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
|
||||
console.error(
|
||||
"[CRON] Failed to clean inactive notifications:",
|
||||
err,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[CRON] Error while checking inactive notifications:",
|
||||
err,
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
scheduled: false,
|
||||
},
|
||||
);
|
||||
|
||||
task.start();
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
module.exports = startCleanInactiveNotificationsCron;
|
||||
|
||||
module.exports = function startCleanInactiveNotificationsCron() {
|
||||
const task = cron.schedule("0 0 * * *", async () => {
|
||||
const cutoff = new Date(Date.now() - Number(process.env.NOTIFICATION_RETENTION_DAYS || 90) * 86400000);
|
||||
for (;;) {
|
||||
const rows = await notification.findAll({ where: { isActive: false, updatedAt: { [Op.lt]: cutoff } }, attributes: ["notification_id"], limit: 500, order: [["updatedAt", "ASC"]] });
|
||||
if (!rows.length) break;
|
||||
const ids = rows.map((row) => row.notification_id);
|
||||
await sequelize.transaction(async (transaction) => { await userNotification.destroy({ where: { notification_id: { [Op.in]: ids } }, transaction }); await notification.destroy({ where: { notification_id: { [Op.in]: ids }, isActive: false }, transaction }); });
|
||||
if (rows.length < 500) break;
|
||||
}
|
||||
}, { scheduled: false });
|
||||
task.start(); return task;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user