From 471990080e54e4e97d80e0c420c77d659c2bad49 Mon Sep 17 00:00:00 2001 From: Aaron Ashby <101434393+aaronashby@users.noreply.github.com> Date: Wed, 5 Nov 2025 23:37:38 -0500 Subject: [PATCH] Initial commit for branch --- .../__test__/notification.service.test.ts | 50 +++++++++++++++++++ .../src/notifications/notifcation.service.ts | 25 ++++++++++ .../notifications/notification.controller.ts | 12 ++++- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/backend/src/notifications/__test__/notification.service.test.ts b/backend/src/notifications/__test__/notification.service.test.ts index 1f32e0ed..b42d4658 100644 --- a/backend/src/notifications/__test__/notification.service.test.ts +++ b/backend/src/notifications/__test__/notification.service.test.ts @@ -11,6 +11,7 @@ const mockScan = vi.fn().mockReturnThis(); const mockGet = vi.fn().mockReturnThis(); const mockSend = vi.fn().mockReturnThis(); // for SES const mockPut = vi.fn().mockReturnThis(); +const mockDelete = vi.fn().mockReturnThis(); const mockQuery = vi.fn().mockReturnThis(); const mockSendEmail = vi.fn().mockReturnThis(); @@ -18,6 +19,7 @@ const mockDocumentClient = { scan: mockScan, get: mockGet, put : mockPut, + delete : mockDelete, promise: mockPromise, query : mockQuery }; @@ -330,5 +332,53 @@ describe('NotificationController', () => { }); }); + describe('deleteNotification', () => { + it('should successfully delete a notification given a valid id', async () => { + mockPromise.mockResolvedValueOnce({}) + const result = await notificationService.deleteNotification('0') + + expect(mockDelete).toHaveBeenCalledTimes(1) + + expect(mockDelete).toHaveBeenCalledWith({ + TableName: 'BCANNotifications', + Key: { + notificationId: '0', + }, + ConditionExpression: 'attribute_exists(notificationId)' + }) + + expect(result).toEqual('Notification with id 0 successfully deleted') + }) + + it('uses the fallback table when the environment variable is not set', async () => { + delete process.env.DYNAMODB_NOTIFICATION_TABLE_NAME + mockPromise.mockResolvedValueOnce({}) + + const result = await notificationService.deleteNotification('0') + + expect(mockDelete).toHaveBeenCalledWith({ + TableName: 'TABLE_FAILURE', + Key: { + notificationId: '0', + }, + ConditionExpression: 'attribute_exists(notificationId)' + }) + }) + + it('throws an error when the given notification id does not exist', async () => { + mockPromise.mockRejectedValueOnce({ + code: 'ConditionalCheckFailedException', + message: 'The item does not exist' + }); + + try { + await notificationService.deleteNotification('999'); + throw new Error('Expected deleteNotification to throw'); + } catch (err: any) { + expect(err).toBeInstanceOf(Error); + expect(err.message).toContain('Notification with id 999 not found'); + } + }) + }) }); \ No newline at end of file diff --git a/backend/src/notifications/notifcation.service.ts b/backend/src/notifications/notifcation.service.ts index 3fcc0e07..9dede1e0 100644 --- a/backend/src/notifications/notifcation.service.ts +++ b/backend/src/notifications/notifcation.service.ts @@ -132,4 +132,29 @@ export class NotificationService { } } + /** + * Deletes the notification with the given id from the database and returns a success message if the deletion was successful + * @param notificationId the id of the notification to delete + */ + async deleteNotification(notificationId: string): Promise { + const params = { + TableName: process.env.DYNAMODB_NOTIFICATION_TABLE_NAME || 'TABLE_FAILURE', + Key: { + notificationId, + }, + ConditionExpression: 'attribute_exists(notificationId)' + } + + try { + await this.dynamoDb.delete(params).promise() + return `Notification with id ${notificationId} successfully deleted` + } catch (error: any) { + if (error.code === "ConditionalCheckFailedException") { + throw new Error(`Notification with id ${notificationId} not found`) + } + + console.error(error) + throw new Error(`Failed to delete notification with id ${notificationId}`) + } + } } \ No newline at end of file diff --git a/backend/src/notifications/notification.controller.ts b/backend/src/notifications/notification.controller.ts index 3f589a7f..7eaf3d8b 100644 --- a/backend/src/notifications/notification.controller.ts +++ b/backend/src/notifications/notification.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Post, Body, Get, Query, Param } from '@nestjs/common'; +import { Controller, Post, Body, Get, Query, Param, Delete } from '@nestjs/common'; import { NotificationService } from './notifcation.service'; import { Notification } from '../../../middle-layer/types/Notification'; @@ -28,5 +28,13 @@ export class NotificationController { return await this.notificationService.getNotificationByUserId(userId); } - + /** + * Deletes the notification with the given id from the database, if it exists. + * + * @param notificationId the id of the notification to delete + */ + @Delete(':notificationId') + async deleteNotification(@Param('notificationId') notificationId: string) { + return await this.notificationService.deleteNotification(notificationId); + } } \ No newline at end of file