Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-07-12 12:39:17 +08:00
parent 82ea9c77c4
commit ea3e82e54c
47 changed files with 1301 additions and 481 deletions
+57 -13
View File
@@ -12,7 +12,45 @@
* Date Created: Jun. 19, 2026
***********************************************************************************************************************************************************************/
const UserNotification = require('../../models/notifications/user_notification.mdl');
const StickyBannerSetting = require('../../models/notifications/sticky_banner_setting.mdl');
const mdl_Assets = require('../../models/assets/assets.mdl');
const mediaToken = require('../../services/mediaToken.service');
const R = require('../../utils/response.util');
const { notInFutureOrExpired } = require('../../utils/notificationVisibility.util');
const STICKY_LIMIT = 3;
const IMAGE_INCLUDE = {
model: mdl_Assets,
as: 'image',
attributes: ["asset_id", "display_name", "file_url", "thumbnail_url", "storage_provider", "storage_key", "file_type", "mime_type"],
required: false,
};
// Mirrors controllers/admin/advertisements.controller.js's attachImageStreamToken
// — kept duplicated rather than shared across the admin/client boundary.
async function attachImageStreamToken(image, req) {
if (!image || image.storage_provider !== 's3' || !mediaToken.SUPPORTED_TYPES.includes(image.file_type)) {
return image;
}
const ip = mediaToken.resolveIp(req);
const { token } = await mediaToken.issueForAsset(image, req.user?.user_id, ip);
image.stream_token = token;
image.file_url = null;
image.thumbnail_url = null;
delete image.storage_key;
return image;
}
// One shared banner image for the whole rotating sticky bar (see
// controllers/admin/notificationBroadcasts.controller.js's
// getStickyBannerSetting/updateStickyBannerSetting) — not per-announcement.
async function resolveSharedBannerImage(req) {
const setting = await StickyBannerSetting.findOne({ where: { id: 1 }, include: [IMAGE_INCLUDE] });
if (!setting?.image) return null;
const image = setting.toJSON().image;
await attachImageStreamToken(image, req);
return image;
}
// ─── GET /client/notifications ────────────────────────────────────────────────
async function list(req, res) {
@@ -23,7 +61,7 @@ async function list(req, res) {
const offset = (page - 1) * limit;
const { count, rows } = await UserNotification.findAndCountAll({
where: { user_id: userId, show_in_notifications: true },
where: { user_id: userId, show_in_notifications: true, ...notInFutureOrExpired() },
order: [['createdAt', 'DESC']],
limit,
offset,
@@ -44,7 +82,7 @@ async function unseenCount(req, res) {
if (!req.user) return R.success(res, 'Unseen count fetched.', { count: null });
try {
const count = await UserNotification.count({
where: { user_id: req.user.user_id, seen: false, show_in_notifications: true },
where: { user_id: req.user.user_id, seen: false, show_in_notifications: true, ...notInFutureOrExpired() },
});
return R.success(res, 'Unseen count fetched.', { count });
} catch (err) {
@@ -56,18 +94,24 @@ async function unseenCount(req, res) {
// ─── GET /client/notifications/sticky ─────────────────────────────────────
async function stickyAnnouncement(req, res) {
try {
const notification = await UserNotification.findOne({
where: {
user_id: req.user.user_id,
seen: false,
show_in_sticky: true,
type: "announcement",
},
order: [["createdAt", "DESC"]],
});
const [notifications, bannerImage] = await Promise.all([
UserNotification.findAll({
where: {
user_id: req.user.user_id,
seen: false,
show_in_sticky: true,
type: "announcement",
...notInFutureOrExpired(),
},
order: [["createdAt", "DESC"]],
limit: STICKY_LIMIT,
}),
resolveSharedBannerImage(req),
]);
return R.success(res, "Sticky announcement fetched.", {
announcement: notification,
return R.success(res, "Sticky announcements fetched.", {
announcements: notifications,
bannerImage,
});
} catch (err) {
console.error("[CLIENT NOTIFICATION] stickyAnnouncement error:", err);