From 64462020de458e05b01175eddf22ffb78811c448 Mon Sep 17 00:00:00 2001 From: caiodasilva2005 Date: Tue, 17 Dec 2024 23:54:43 -0500 Subject: [PATCH 1/5] #3075-created get unread announcements endpoint --- .../src/controllers/users.controllers.ts | 13 +++++++++ src/backend/src/routes/users.routes.ts | 5 ++++ src/backend/src/services/users.services.ts | 29 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/backend/src/controllers/users.controllers.ts b/src/backend/src/controllers/users.controllers.ts index cc084c714e..2f39b8ad29 100644 --- a/src/backend/src/controllers/users.controllers.ts +++ b/src/backend/src/controllers/users.controllers.ts @@ -228,4 +228,17 @@ export default class UsersController { next(error); } } + + static async removeUserAnnouncement(req: Request, res: Response, next: NextFunction) { + try { + const { userId } = req.params; + const { announcementId } = req.body; + const { organization } = req; + + const unreadAnnouncements = await UsersService.removeUserAnnouncement(userId, announcementId, organization); + res.status(200).json(unreadAnnouncements); + } catch (error: unknown) { + next(error); + } + } } diff --git a/src/backend/src/routes/users.routes.ts b/src/backend/src/routes/users.routes.ts index 802d586500..9c8be506d3 100644 --- a/src/backend/src/routes/users.routes.ts +++ b/src/backend/src/routes/users.routes.ts @@ -61,5 +61,10 @@ userRouter.post( nonEmptyString(body('notificationId')), UsersController.removeUserNotification ); +userRouter.post( + '/:userId/announcements/remove', + nonEmptyString(body('announcementId')), + UsersController.removeUserAnnouncement +); export default userRouter; diff --git a/src/backend/src/services/users.services.ts b/src/backend/src/services/users.services.ts index fff25ef56b..7ddcabcc06 100644 --- a/src/backend/src/services/users.services.ts +++ b/src/backend/src/services/users.services.ts @@ -631,4 +631,33 @@ export default class UsersService { return updatedUser.unreadNotifications.map(notificationTransformer); } + + /** + * Removes a announcement from the user's unread announcement + * @param userId id of the user to remove announcement from + * @param announcementId id of the announcement to remove + * @param organization the user's organization + * @returns the user's updated unread announcement + */ + static async removeUserAnnouncement(userId: string, announcementId: string, organization: Organization) { + const requestedUser = await prisma.user.findUnique({ + where: { userId } + }); + + if (!requestedUser) throw new NotFoundException('User', userId); + + const updatedUser = await prisma.user.update({ + where: { userId }, + data: { + unreadAnnouncements: { + disconnect: { + announcementId + } + } + }, + include: { unreadAnnouncements: getAnnouncementQueryArgs(organization.organizationId) } + }); + + return updatedUser.unreadAnnouncements.map(announcementTransformer); + } } From 8cf7ff171decb91573bb4604eb74c1e5c0f86655 Mon Sep 17 00:00:00 2001 From: caiodasilva2005 Date: Fri, 20 Dec 2024 07:45:48 -0500 Subject: [PATCH 2/5] #3075-added test --- src/backend/tests/unmocked/users.test.ts | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/backend/tests/unmocked/users.test.ts b/src/backend/tests/unmocked/users.test.ts index 789109a2ae..154a2d057a 100644 --- a/src/backend/tests/unmocked/users.test.ts +++ b/src/backend/tests/unmocked/users.test.ts @@ -139,4 +139,61 @@ describe('User Tests', () => { expect(announcements[1].text).toBe('test2'); }); }); + + describe('Remove Announcement', () => { + it('Fails with invalid user', async () => { + const testBatman = await createTestUser(batmanAppAdmin, orgId); + await AnnouncementService.createAnnouncement( + 'test1', + [testBatman.userId], + new Date(), + 'Thomas Emrax', + '1', + 'software', + organization.organizationId + ); + const announcements = await UsersService.getUserUnreadAnnouncements(testBatman.userId, organization); + + await expect( + async () => await UsersService.removeUserAnnouncement('1', announcements[0].announcementId, organization) + ).rejects.toThrow(new NotFoundException('User', '1')); + }); + + it('Succeeds and removes user announcement', async () => { + const testBatman = await createTestUser(batmanAppAdmin, orgId); + await AnnouncementService.createAnnouncement( + 'test1', + [testBatman.userId], + new Date(), + 'Thomas Emrax', + '1', + 'software', + organization.organizationId + ); + await AnnouncementService.createAnnouncement( + 'test2', + [testBatman.userId], + new Date(), + 'Superman', + '50', + 'mechanical', + organization.organizationId + ); + + const announcements = await UsersService.getUserUnreadAnnouncements(testBatman.userId, organization); + + expect(announcements).toHaveLength(2); + expect(announcements[0].text).toBe('test1'); + expect(announcements[1].text).toBe('test2'); + + const updatedAnnouncements = await UsersService.removeUserAnnouncement( + testBatman.userId, + announcements[0].announcementId, + organization + ); + + expect(updatedAnnouncements).toHaveLength(1); + expect(updatedAnnouncements[0].text).toBe('test2'); + }); + }); }); From 9d8ed90379e727c14b6aeb939973dc689cb2b79d Mon Sep 17 00:00:00 2001 From: caiodasilva2005 Date: Sat, 21 Dec 2024 19:45:28 -0500 Subject: [PATCH 3/5] #3075-moved to announcements router --- .../controllers/announcements.controllers.ts | 16 ++++++++ .../src/routes/announcements.routes.ts | 7 ++++ .../src/services/announcement.service.ts | 31 +++++++++++++- .../tests/unmocked/announcements.test.ts | 40 +++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/backend/src/controllers/announcements.controllers.ts b/src/backend/src/controllers/announcements.controllers.ts index e5ccafbe06..3c21f8e877 100644 --- a/src/backend/src/controllers/announcements.controllers.ts +++ b/src/backend/src/controllers/announcements.controllers.ts @@ -15,4 +15,20 @@ export default class AnnouncementController { next(error); } } + + static async removeUserAnnouncement(req: Request, res: Response, next: NextFunction) { + try { + const { announcementId } = req.body; + const { organization, currentUser } = req; + + const unreadAnnouncements = await AnnouncementService.removeUserAnnouncement( + currentUser.userId, + announcementId, + organization.organizationId + ); + res.status(200).json(unreadAnnouncements); + } catch (error: unknown) { + next(error); + } + } } diff --git a/src/backend/src/routes/announcements.routes.ts b/src/backend/src/routes/announcements.routes.ts index b772f09fbb..0efa847c13 100644 --- a/src/backend/src/routes/announcements.routes.ts +++ b/src/backend/src/routes/announcements.routes.ts @@ -1,8 +1,15 @@ import express from 'express'; import AnnouncementController from '../controllers/announcements.controllers'; +import { nonEmptyString } from '../utils/validation.utils'; +import { body } from 'express-validator'; const announcementsRouter = express.Router(); announcementsRouter.get('/current-user', AnnouncementController.getUserUnreadAnnouncements); +announcementsRouter.post( + '/current-user/remove', + nonEmptyString(body('announcementId')), + AnnouncementController.removeUserAnnouncement +); export default announcementsRouter; diff --git a/src/backend/src/services/announcement.service.ts b/src/backend/src/services/announcement.service.ts index 7562755f01..b05a29d444 100644 --- a/src/backend/src/services/announcement.service.ts +++ b/src/backend/src/services/announcement.service.ts @@ -2,7 +2,7 @@ import { Announcement } from 'shared'; import prisma from '../prisma/prisma'; import { getAnnouncementQueryArgs } from '../prisma-query-args/announcements.query.args'; import announcementTransformer from '../transformers/announcements.transformer'; -import { HttpException } from '../utils/errors.utils'; +import { HttpException, NotFoundException } from '../utils/errors.utils'; export default class AnnouncementService { /** @@ -63,4 +63,33 @@ export default class AnnouncementService { return unreadAnnouncements.map(announcementTransformer); } + + /** + * Removes a announcement from the user's unread announcement + * @param userId id of the user to remove announcement from + * @param announcementId id of the announcement to remove + * @param organization the user's organization + * @returns the user's updated unread announcement + */ + static async removeUserAnnouncement(userId: string, announcementId: string, organizationId: string) { + const requestedUser = await prisma.user.findUnique({ + where: { userId } + }); + + if (!requestedUser) throw new NotFoundException('User', userId); + + const updatedUser = await prisma.user.update({ + where: { userId }, + data: { + unreadAnnouncements: { + disconnect: { + announcementId + } + } + }, + include: { unreadAnnouncements: getAnnouncementQueryArgs(organizationId) } + }); + + return updatedUser.unreadAnnouncements.map(announcementTransformer); + } } diff --git a/src/backend/tests/unmocked/announcements.test.ts b/src/backend/tests/unmocked/announcements.test.ts index 534b546edb..21c521d83d 100644 --- a/src/backend/tests/unmocked/announcements.test.ts +++ b/src/backend/tests/unmocked/announcements.test.ts @@ -44,4 +44,44 @@ describe('Announcemnts Tests', () => { expect(announcements[1].text).toBe('test2'); }); }); + + describe('Remove Announcement', () => { + it('Succeeds and removes user announcement', async () => { + const testBatman = await createTestUser(batmanAppAdmin, orgId); + await AnnouncementService.createAnnouncement( + 'test1', + [testBatman.userId], + 'Thomas Emrax', + '1', + 'software', + organization.organizationId + ); + await AnnouncementService.createAnnouncement( + 'test2', + [testBatman.userId], + 'Superman', + '50', + 'mechanical', + organization.organizationId + ); + + const announcements = await AnnouncementService.getUserUnreadAnnouncements( + testBatman.userId, + organization.organizationId + ); + + expect(announcements).toHaveLength(2); + expect(announcements[0].text).toBe('test1'); + expect(announcements[1].text).toBe('test2'); + + const updatedAnnouncements = await AnnouncementService.removeUserAnnouncement( + testBatman.userId, + announcements[0].announcementId, + organization.organizationId + ); + + expect(updatedAnnouncements).toHaveLength(1); + expect(updatedAnnouncements[0].text).toBe('test2'); + }); + }); }); From ecc5609c44e560a435a4855d7e097b4508d29004 Mon Sep 17 00:00:00 2001 From: caiodasilva2005 Date: Sun, 22 Dec 2024 07:51:31 -0500 Subject: [PATCH 4/5] #3075-fixed endpoint --- src/backend/src/controllers/announcements.controllers.ts | 2 +- src/backend/src/routes/announcements.routes.ts | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/backend/src/controllers/announcements.controllers.ts b/src/backend/src/controllers/announcements.controllers.ts index 3c21f8e877..ec18d65538 100644 --- a/src/backend/src/controllers/announcements.controllers.ts +++ b/src/backend/src/controllers/announcements.controllers.ts @@ -18,7 +18,7 @@ export default class AnnouncementController { static async removeUserAnnouncement(req: Request, res: Response, next: NextFunction) { try { - const { announcementId } = req.body; + const { announcementId } = req.params; const { organization, currentUser } = req; const unreadAnnouncements = await AnnouncementService.removeUserAnnouncement( diff --git a/src/backend/src/routes/announcements.routes.ts b/src/backend/src/routes/announcements.routes.ts index 0efa847c13..9a5cabc913 100644 --- a/src/backend/src/routes/announcements.routes.ts +++ b/src/backend/src/routes/announcements.routes.ts @@ -1,15 +1,9 @@ import express from 'express'; import AnnouncementController from '../controllers/announcements.controllers'; -import { nonEmptyString } from '../utils/validation.utils'; -import { body } from 'express-validator'; const announcementsRouter = express.Router(); announcementsRouter.get('/current-user', AnnouncementController.getUserUnreadAnnouncements); -announcementsRouter.post( - '/current-user/remove', - nonEmptyString(body('announcementId')), - AnnouncementController.removeUserAnnouncement -); +announcementsRouter.post('/:announcementId/remove', AnnouncementController.removeUserAnnouncement); export default announcementsRouter; From c8392e96bbe996ec0bee13bdcace3d746e7d1257 Mon Sep 17 00:00:00 2001 From: caiodasilva2005 Date: Sun, 22 Dec 2024 11:09:31 -0500 Subject: [PATCH 5/5] #3075-fixed tests --- src/backend/tests/unmocked/announcements.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/tests/unmocked/announcements.test.ts b/src/backend/tests/unmocked/announcements.test.ts index 74cf8d689c..3981d1feb9 100644 --- a/src/backend/tests/unmocked/announcements.test.ts +++ b/src/backend/tests/unmocked/announcements.test.ts @@ -53,6 +53,7 @@ describe('Announcemnts Tests', () => { await AnnouncementService.createAnnouncement( 'test1', [testBatman.userId], + new Date(), 'Thomas Emrax', '1', 'software', @@ -61,6 +62,7 @@ describe('Announcemnts Tests', () => { await AnnouncementService.createAnnouncement( 'test2', [testBatman.userId], + new Date(), 'Superman', '50', 'mechanical',