216 lines
6.0 KiB
TypeScript
216 lines
6.0 KiB
TypeScript
import { Request, Response } from 'express';
|
|
import mongoose from 'mongoose';
|
|
import { NotificationModel as Notification } from '../models/mongoose/Notification.schema';
|
|
import logger from '../utils/logger';
|
|
import { notificationMongoService as notificationService } from '../services/notification.service';
|
|
|
|
export class NotificationController {
|
|
/**
|
|
* Get user's notifications with pagination
|
|
*/
|
|
async getUserNotifications(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const { page = 1, limit = 20, unreadOnly = false } = req.query;
|
|
|
|
if (!userId) {
|
|
res.status(401).json({ success: false, message: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
const where: any = { userId };
|
|
if (unreadOnly === 'true') {
|
|
where.isRead = false;
|
|
}
|
|
|
|
const offset = (Number(page) - 1) * Number(limit);
|
|
|
|
const rows = await Notification.find(where)
|
|
.sort({ createdAt: -1 })
|
|
.limit(Number(limit))
|
|
.skip(offset);
|
|
|
|
const count = await Notification.countDocuments(where);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
notifications: rows,
|
|
pagination: {
|
|
page: Number(page),
|
|
limit: Number(limit),
|
|
total: count,
|
|
totalPages: Math.ceil(count / Number(limit))
|
|
},
|
|
unreadCount: unreadOnly === 'true' ? count : await Notification.countDocuments({ userId, isRead: false })
|
|
}
|
|
});
|
|
} catch (error: any) {
|
|
logger.error('[Notification Controller] Error fetching notifications:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get unread notification count
|
|
*/
|
|
async getUnreadCount(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
|
|
if (!userId) {
|
|
res.status(401).json({ success: false, message: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
const count = await Notification.countDocuments({
|
|
userId, isRead: false
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
data: { unreadCount: count }
|
|
});
|
|
} catch (error: any) {
|
|
logger.error('[Notification Controller] Error fetching unread count:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark notification as read
|
|
*/
|
|
async markAsRead(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const { notificationId } = req.params;
|
|
|
|
if (!userId) {
|
|
res.status(401).json({ success: false, message: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
if (!mongoose.Types.ObjectId.isValid(notificationId)) {
|
|
res.status(400).json({ success: false, message: 'Invalid notification ID' });
|
|
return;
|
|
}
|
|
|
|
const notification = await Notification.findOne({
|
|
_id: notificationId, userId
|
|
});
|
|
|
|
if (!notification) {
|
|
res.status(404).json({ success: false, message: 'Notification not found' });
|
|
return;
|
|
}
|
|
|
|
notification.isRead = true;
|
|
notification.metadata = notification.metadata || {};
|
|
notification.metadata.readAt = new Date();
|
|
await notification.save();
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Notification marked as read',
|
|
data: { notification }
|
|
});
|
|
} catch (error: any) {
|
|
logger.error('[Notification Controller] Error marking notification as read:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark all notifications as read
|
|
*/
|
|
async markAllAsRead(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
|
|
if (!userId) {
|
|
res.status(401).json({ success: false, message: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
await Notification.updateMany(
|
|
{ userId, isRead: false },
|
|
{ $set: { isRead: true } }
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'All notifications marked as read'
|
|
});
|
|
} catch (error: any) {
|
|
logger.error('[Notification Controller] Error marking all as read:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete notification
|
|
*/
|
|
async deleteNotification(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const { notificationId } = req.params;
|
|
|
|
if (!userId) {
|
|
res.status(401).json({ success: false, message: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
if (!mongoose.Types.ObjectId.isValid(notificationId)) {
|
|
res.status(400).json({ success: false, message: 'Invalid notification ID' });
|
|
return;
|
|
}
|
|
|
|
const result = await Notification.deleteOne({
|
|
_id: notificationId, userId
|
|
});
|
|
|
|
const deleted = result.deletedCount;
|
|
|
|
if (deleted === 0) {
|
|
res.status(404).json({ success: false, message: 'Notification not found' });
|
|
return;
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Notification deleted'
|
|
});
|
|
} catch (error: any) {
|
|
logger.error('[Notification Controller] Error deleting notification:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get user's push notification subscriptions
|
|
*/
|
|
async getUserSubscriptions(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
|
|
if (!userId) {
|
|
res.status(401).json({ success: false, message: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
const subscriptions = await notificationService.getUserSubscriptions(userId);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
subscriptions,
|
|
count: subscriptions.length
|
|
}
|
|
});
|
|
} catch (error: any) {
|
|
logger.error('[Notification Controller] Error fetching subscriptions:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
}
|