Some checks failed
CI/CD Pipeline - Xpeditis PreProd / Frontend - Docker Build & Push (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Deploy to PreProd Server (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Run Smoke Tests (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Backend - Build & Test (push) Failing after 5m53s
CI/CD Pipeline - Xpeditis PreProd / Backend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Frontend - Build & Test (push) Has been cancelled
- Replace all ../../domain/ imports with @domain/ across 67 files - Configure NestJS to use tsconfig.build.json with rootDir - Add tsc-alias to resolve path aliases after build - This fixes 'Cannot find module' TypeScript compilation errors Fixed files: - 30 files in application layer - 37 files in infrastructure layer
208 lines
6.2 KiB
TypeScript
208 lines
6.2 KiB
TypeScript
/**
|
|
* Notifications Controller
|
|
*
|
|
* REST API endpoints for managing notifications
|
|
*/
|
|
|
|
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Patch,
|
|
Delete,
|
|
Param,
|
|
Query,
|
|
UseGuards,
|
|
ParseIntPipe,
|
|
DefaultValuePipe,
|
|
NotFoundException,
|
|
} from '@nestjs/common';
|
|
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@nestjs/swagger';
|
|
import { NotificationService } from '../services/notification.service';
|
|
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
|
|
import { CurrentUser, UserPayload } from '../decorators/current-user.decorator';
|
|
import { Notification } from '@domain/entities/notification.entity';
|
|
|
|
class NotificationResponseDto {
|
|
id: string;
|
|
type: string;
|
|
priority: string;
|
|
title: string;
|
|
message: string;
|
|
metadata?: Record<string, any>;
|
|
read: boolean;
|
|
readAt?: string;
|
|
actionUrl?: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
@ApiTags('Notifications')
|
|
@ApiBearerAuth()
|
|
@Controller('notifications')
|
|
@UseGuards(JwtAuthGuard)
|
|
export class NotificationsController {
|
|
constructor(private readonly notificationService: NotificationService) {}
|
|
|
|
/**
|
|
* Get user's notifications
|
|
*/
|
|
@Get()
|
|
@ApiOperation({ summary: 'Get user notifications' })
|
|
@ApiResponse({ status: 200, description: 'Notifications retrieved successfully' })
|
|
@ApiQuery({ name: 'read', required: false, description: 'Filter by read status' })
|
|
@ApiQuery({ name: 'page', required: false, description: 'Page number (default: 1)' })
|
|
@ApiQuery({ name: 'limit', required: false, description: 'Items per page (default: 20)' })
|
|
async getNotifications(
|
|
@CurrentUser() user: UserPayload,
|
|
@Query('read') read?: string,
|
|
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page?: number,
|
|
@Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit?: number
|
|
): Promise<{
|
|
notifications: NotificationResponseDto[];
|
|
total: number;
|
|
page: number;
|
|
pageSize: number;
|
|
}> {
|
|
page = page || 1;
|
|
limit = limit || 20;
|
|
|
|
const filters: any = {
|
|
userId: user.id,
|
|
read: read !== undefined ? read === 'true' : undefined,
|
|
offset: (page - 1) * limit,
|
|
limit,
|
|
};
|
|
|
|
const { notifications, total } = await this.notificationService.getNotifications(filters);
|
|
|
|
return {
|
|
notifications: notifications.map(n => this.mapToDto(n)),
|
|
total,
|
|
page,
|
|
pageSize: limit,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get unread notifications
|
|
*/
|
|
@Get('unread')
|
|
@ApiOperation({ summary: 'Get unread notifications' })
|
|
@ApiResponse({ status: 200, description: 'Unread notifications retrieved successfully' })
|
|
@ApiQuery({
|
|
name: 'limit',
|
|
required: false,
|
|
description: 'Number of notifications (default: 50)',
|
|
})
|
|
async getUnreadNotifications(
|
|
@CurrentUser() user: UserPayload,
|
|
@Query('limit', new DefaultValuePipe(50), ParseIntPipe) limit?: number
|
|
): Promise<NotificationResponseDto[]> {
|
|
limit = limit || 50;
|
|
const notifications = await this.notificationService.getUnreadNotifications(user.id, limit);
|
|
return notifications.map(n => this.mapToDto(n));
|
|
}
|
|
|
|
/**
|
|
* Get unread count
|
|
*/
|
|
@Get('unread/count')
|
|
@ApiOperation({ summary: 'Get unread notifications count' })
|
|
@ApiResponse({ status: 200, description: 'Unread count retrieved successfully' })
|
|
async getUnreadCount(@CurrentUser() user: UserPayload): Promise<{ count: number }> {
|
|
const count = await this.notificationService.getUnreadCount(user.id);
|
|
return { count };
|
|
}
|
|
|
|
/**
|
|
* Get notification by ID
|
|
*/
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get notification by ID' })
|
|
@ApiResponse({ status: 200, description: 'Notification retrieved successfully' })
|
|
@ApiResponse({ status: 404, description: 'Notification not found' })
|
|
async getNotificationById(
|
|
@CurrentUser() user: UserPayload,
|
|
@Param('id') id: string
|
|
): Promise<NotificationResponseDto> {
|
|
const notification = await this.notificationService.getNotificationById(id);
|
|
|
|
if (!notification || notification.userId !== user.id) {
|
|
throw new NotFoundException('Notification not found');
|
|
}
|
|
|
|
return this.mapToDto(notification);
|
|
}
|
|
|
|
/**
|
|
* Mark notification as read
|
|
*/
|
|
@Patch(':id/read')
|
|
@ApiOperation({ summary: 'Mark notification as read' })
|
|
@ApiResponse({ status: 200, description: 'Notification marked as read' })
|
|
@ApiResponse({ status: 404, description: 'Notification not found' })
|
|
async markAsRead(
|
|
@CurrentUser() user: UserPayload,
|
|
@Param('id') id: string
|
|
): Promise<{ success: boolean }> {
|
|
const notification = await this.notificationService.getNotificationById(id);
|
|
|
|
if (!notification || notification.userId !== user.id) {
|
|
throw new NotFoundException('Notification not found');
|
|
}
|
|
|
|
await this.notificationService.markAsRead(id);
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Mark all notifications as read
|
|
*/
|
|
@Post('read-all')
|
|
@ApiOperation({ summary: 'Mark all notifications as read' })
|
|
@ApiResponse({ status: 200, description: 'All notifications marked as read' })
|
|
async markAllAsRead(@CurrentUser() user: UserPayload): Promise<{ success: boolean }> {
|
|
await this.notificationService.markAllAsRead(user.id);
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Delete notification
|
|
*/
|
|
@Delete(':id')
|
|
@ApiOperation({ summary: 'Delete notification' })
|
|
@ApiResponse({ status: 200, description: 'Notification deleted' })
|
|
@ApiResponse({ status: 404, description: 'Notification not found' })
|
|
async deleteNotification(
|
|
@CurrentUser() user: UserPayload,
|
|
@Param('id') id: string
|
|
): Promise<{ success: boolean }> {
|
|
const notification = await this.notificationService.getNotificationById(id);
|
|
|
|
if (!notification || notification.userId !== user.id) {
|
|
throw new NotFoundException('Notification not found');
|
|
}
|
|
|
|
await this.notificationService.deleteNotification(id);
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Map notification entity to DTO
|
|
*/
|
|
private mapToDto(notification: Notification): NotificationResponseDto {
|
|
return {
|
|
id: notification.id,
|
|
type: notification.type,
|
|
priority: notification.priority,
|
|
title: notification.title,
|
|
message: notification.message,
|
|
metadata: notification.metadata,
|
|
read: notification.read,
|
|
readAt: notification.readAt?.toISOString(),
|
|
actionUrl: notification.actionUrl,
|
|
createdAt: notification.createdAt.toISOString(),
|
|
};
|
|
}
|
|
}
|