101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
/**
|
|
* Application Use Case: MarkNotificationReadUseCase
|
|
*
|
|
* Marks a notification as read.
|
|
*/
|
|
|
|
import type { AsyncUseCase } from '@core/shared/application';
|
|
import type { INotificationRepository } from '../../domain/repositories/INotificationRepository';
|
|
import { NotificationDomainError } from '../../domain/errors/NotificationDomainError';
|
|
import type { Logger } from '../../../shared/src/logging/Logger';
|
|
|
|
export interface MarkNotificationReadCommand {
|
|
notificationId: string;
|
|
recipientId: string; // For validation
|
|
}
|
|
|
|
export class MarkNotificationReadUseCase implements AsyncUseCase<MarkNotificationReadCommand, void> {
|
|
constructor(
|
|
private readonly notificationRepository: INotificationRepository,
|
|
private readonly logger: Logger,
|
|
) {}
|
|
|
|
async execute(command: MarkNotificationReadCommand): Promise<void> {
|
|
this.logger.debug(`Attempting to mark notification ${command.notificationId} as read for recipient ${command.recipientId}`);
|
|
try {
|
|
const notification = await this.notificationRepository.findById(command.notificationId);
|
|
|
|
if (!notification) {
|
|
this.logger.warn(`Notification not found for ID: ${command.notificationId}`);
|
|
throw new NotificationDomainError('Notification not found');
|
|
}
|
|
|
|
if (notification.recipientId !== command.recipientId) {
|
|
this.logger.warn(`Unauthorized attempt to mark notification ${command.notificationId}. Recipient ID mismatch.`);
|
|
throw new NotificationDomainError('Cannot mark another user\'s notification as read');
|
|
}
|
|
|
|
if (!notification.isUnread()) {
|
|
this.logger.info(`Notification ${command.notificationId} is already read. Skipping update.`);
|
|
return; // Already read, nothing to do
|
|
}
|
|
|
|
const updatedNotification = notification.markAsRead();
|
|
await this.notificationRepository.update(updatedNotification);
|
|
this.logger.info(`Notification ${command.notificationId} successfully marked as read.`);
|
|
} catch (error) {
|
|
this.logger.error(`Failed to mark notification ${command.notificationId} as read: ${error.message}`);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Application Use Case: MarkAllNotificationsReadUseCase
|
|
*
|
|
* Marks all notifications as read for a recipient.
|
|
*/
|
|
export class MarkAllNotificationsReadUseCase implements AsyncUseCase<string, void> {
|
|
constructor(
|
|
private readonly notificationRepository: INotificationRepository,
|
|
) {}
|
|
|
|
async execute(recipientId: string): Promise<void> {
|
|
await this.notificationRepository.markAllAsReadByRecipientId(recipientId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Application Use Case: DismissNotificationUseCase
|
|
*
|
|
* Dismisses a notification.
|
|
*/
|
|
export interface DismissNotificationCommand {
|
|
notificationId: string;
|
|
recipientId: string;
|
|
}
|
|
|
|
export class DismissNotificationUseCase implements AsyncUseCase<DismissNotificationCommand, void> {
|
|
constructor(
|
|
private readonly notificationRepository: INotificationRepository,
|
|
) {}
|
|
|
|
async execute(command: DismissNotificationCommand): Promise<void> {
|
|
const notification = await this.notificationRepository.findById(command.notificationId);
|
|
|
|
if (!notification) {
|
|
throw new NotificationDomainError('Notification not found');
|
|
}
|
|
|
|
if (notification.recipientId !== command.recipientId) {
|
|
throw new NotificationDomainError('Cannot dismiss another user\'s notification');
|
|
}
|
|
|
|
if (notification.isDismissed()) {
|
|
return; // Already dismissed
|
|
}
|
|
|
|
const updatedNotification = notification.dismiss();
|
|
await this.notificationRepository.update(updatedNotification);
|
|
}
|
|
} |