From 1dbb5502c7cb4a040f8717a6b5e1b58de62e7408 Mon Sep 17 00:00:00 2001 From: Chris Pyle Date: Fri, 27 Dec 2024 18:53:10 -0500 Subject: [PATCH] #3044 refactoring prisma queries and misc changes --- .../src/controllers/slack.controllers.ts | 4 +- src/backend/src/integrations/slack.ts | 23 +++------- src/backend/src/routes/slack.routes.ts | 8 +--- .../src/services/announcement.service.ts | 8 ++-- src/backend/src/services/slack.services.ts | 12 +----- src/backend/src/utils/slack.utils.ts | 43 +++++++++++++------ .../tests/integration/slackMessages.test.ts | 19 +++++--- src/backend/tests/unit/announcements.test.ts | 2 - 8 files changed, 61 insertions(+), 58 deletions(-) diff --git a/src/backend/src/controllers/slack.controllers.ts b/src/backend/src/controllers/slack.controllers.ts index d90c60ac35..c16dcfeaba 100644 --- a/src/backend/src/controllers/slack.controllers.ts +++ b/src/backend/src/controllers/slack.controllers.ts @@ -11,6 +11,8 @@ export default class SlackController { if (relatedOrganization) { slackServices.processMessageSent(event, relatedOrganization.organizationId); } - } catch (error: unknown) {} + } catch (error: unknown) { + console.log(error); + } } } diff --git a/src/backend/src/integrations/slack.ts b/src/backend/src/integrations/slack.ts index b24615743e..6e855acae7 100644 --- a/src/backend/src/integrations/slack.ts +++ b/src/backend/src/integrations/slack.ts @@ -182,41 +182,35 @@ export const getUsersInChannel = async (channelId: string) => { return members; } catch (error) { - return []; + return members; } }; /** * Given a slack channel id, produces the name of the channel * @param channelId the id of the slack channel - * @returns the name of the channel + * @returns the name of the channel or undefined if it cannot be found */ export const getChannelName = async (channelId: string) => { - const { SLACK_BOT_TOKEN } = process.env; - if (!SLACK_BOT_TOKEN) return channelId; - try { const channelRes = await slack.conversations.info({ channel: channelId }); - return channelRes.channel?.name || 'Unknown Channel'; + return channelRes.channel?.name; } catch (error) { - return; + return undefined; } }; /** * Given a slack user id, prood.uces the name of the channel * @param userId the id of the slack user - * @returns the name of the user (real name if no display name) + * @returns the name of the user (real name if no display name), undefined if cannot be found */ export const getUserName = async (userId: string) => { - const { SLACK_BOT_TOKEN } = process.env; - if (!SLACK_BOT_TOKEN) return; - try { const userRes = await slack.users.info({ user: userId }); - return userRes.user?.profile?.display_name || userRes.user?.real_name || 'Unkown User'; + return userRes.user?.profile?.display_name || userRes.user?.real_name; } catch (error) { - return; + return undefined; } }; @@ -225,9 +219,6 @@ export const getUserName = async (userId: string) => { * @returns the id of the workspace */ export const getWorkspaceId = async () => { - const { SLACK_BOT_TOKEN } = process.env; - if (!SLACK_BOT_TOKEN) return; - try { const response = await slack.auth.test(); if (response.ok) { diff --git a/src/backend/src/routes/slack.routes.ts b/src/backend/src/routes/slack.routes.ts index a085ae4244..6878b176b1 100644 --- a/src/backend/src/routes/slack.routes.ts +++ b/src/backend/src/routes/slack.routes.ts @@ -3,10 +3,6 @@ import SlackController from '../controllers/slack.controllers'; export const slackEvents = createEventAdapter(process.env.SLACK_SIGNING_SECRET || ''); -slackEvents.on('message', async (event) => { - SlackController.processMessageEvent(event); -}); +slackEvents.on('message', SlackController.processMessageEvent); -slackEvents.on('error', (error) => { - console.log(error.name); -}); +slackEvents.on('error', console.log); diff --git a/src/backend/src/services/announcement.service.ts b/src/backend/src/services/announcement.service.ts index c885543059..64bb6a80da 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, NotFoundException } from '../utils/errors.utils'; +import { DeletedException, HttpException, NotFoundException } from '../utils/errors.utils'; export default class AnnouncementService { /** @@ -48,7 +48,6 @@ export default class AnnouncementService { static async updateAnnouncement( text: string, usersReceivedIds: string[], - dateMessageSent: Date, senderName: string, slackEventId: string, slackChannelName: string, @@ -62,6 +61,8 @@ export default class AnnouncementService { if (!originalAnnouncement) throw new NotFoundException('Announcement', slackEventId); + if (originalAnnouncement.dateDeleted) throw new DeletedException('Announcement', slackEventId); + const announcement = await prisma.announcement.update({ where: { announcementId: originalAnnouncement.announcementId }, data: { @@ -72,7 +73,6 @@ export default class AnnouncementService { })) }, slackEventId, - dateMessageSent, senderName, slackChannelName }, @@ -91,6 +91,8 @@ export default class AnnouncementService { if (!originalAnnouncement) throw new NotFoundException('Announcement', slackEventId); + if (originalAnnouncement.dateDeleted) throw new DeletedException('Announcement', slackEventId); + const announcement = await prisma.announcement.update({ where: { slackEventId }, data: { diff --git a/src/backend/src/services/slack.services.ts b/src/backend/src/services/slack.services.ts index 8bda71edcd..5bdafb7413 100644 --- a/src/backend/src/services/slack.services.ts +++ b/src/backend/src/services/slack.services.ts @@ -1,4 +1,3 @@ -import UsersService from './users.services'; import { getChannelName, getUserName } from '../integrations/slack'; import AnnouncementService from './announcement.service'; import { Announcement } from 'shared'; @@ -105,14 +104,6 @@ export default class slackServices { let messageText = ''; let userIdsToNotify: string[] = []; - //Get the settings of all users in this organization to compare slack ids - const users = await UsersService.getAllUsers(); - const userSettings = await Promise.all( - users.map((user) => { - return UsersService.getUserSettings(user.userId); - }) - ); - //get the name of the user that sent the message from slack let userName = (await getUserName(eventMessage.user)) ?? ''; @@ -132,7 +123,7 @@ export default class slackServices { if (richTextBlocks && richTextBlocks.length > 0 && richTextBlocks[0].elements.length > 0) { for (const element of richTextBlocks[0].elements[0].elements) { messageText += await blockToString(element); - userIdsToNotify = userIdsToNotify.concat(await blockToMentionedUsers(element, userSettings, event.channel)); + userIdsToNotify = userIdsToNotify.concat(await blockToMentionedUsers(element, organizationId, event.channel)); } } else { return; @@ -152,7 +143,6 @@ export default class slackServices { return await AnnouncementService.updateAnnouncement( messageText, userIdsToNotify, - dateCreated, userName, eventMessage.client_msg_id, slackChannelName, diff --git a/src/backend/src/utils/slack.utils.ts b/src/backend/src/utils/slack.utils.ts index ea98a1a698..4019c6d6db 100644 --- a/src/backend/src/utils/slack.utils.ts +++ b/src/backend/src/utils/slack.utils.ts @@ -1,5 +1,5 @@ import { ChangeRequest, daysBetween, Task, UserPreview, wbsPipe, calculateEndDate } from 'shared'; -import { User, User_Settings } from '@prisma/client'; +import { User } from '@prisma/client'; import { editMessage, getChannelName, @@ -20,6 +20,7 @@ import { WorkPackageQueryArgs } from '../prisma-query-args/work-packages.query-a import { Prisma } from '@prisma/client'; import { userTransformer } from '../transformers/user.transformer'; import { SlackRichTextBlock } from '../services/slack.services'; +import UsersService from '../services/users.services'; interface SlackMessageThread { messageInfoId: string; @@ -524,38 +525,54 @@ export const blockToString = async (block: SlackRichTextBlock) => { /** * Gets the users notified in a specific SlackRichTextBlock. * @param block the block that may contain mentioned user/users - * @param usersSettings the settings of all the users in prisma + * @param orgainzationId the id of the organization corresponding to this slack channel * @param channelId the id of the channel that the block is being sent in * @returns an array of prisma user ids of users to be notified */ export const blockToMentionedUsers = async ( block: SlackRichTextBlock, - usersSettings: User_Settings[], + organizationId: string, channelId: string -) => { +): Promise => { switch (block.type) { case 'broadcast': switch (block.range) { case 'everyone': - return usersSettings.map((usersSettings) => usersSettings.userId); + const usersInOrg = await UsersService.getAllUsers(organizationId); + return usersInOrg.map((user) => user.userId); case 'channel': case 'here': //@here behaves the same as @channel; notifies all the users in that channel const slackIds: string[] = await getUsersInChannel(channelId); - return usersSettings - .filter((userSettings) => { - return slackIds.some((slackId) => slackId === userSettings.slackId); - }) - .map((user) => user.userId); + const prismaIds: (string | undefined)[] = await Promise.all(slackIds.map(getUserIdFromSlackId)); + return prismaIds.filter((id): id is string => id !== undefined); default: return []; } case 'user': - return usersSettings - .filter((userSettings) => userSettings.slackId === block.user_id) - .map((userSettings) => userSettings.userId); + const prismaId = await getUserIdFromSlackId(block.user_id ?? ''); + return prismaId ? [prismaId] : []; default: //only broadcasts and specific user mentions add recievers to announcements return []; } }; + +/** + * given a slack id, produce the user id of the corresponding user + * @param slackId the slack id in the settings of the user + * @returns the user id, or undefined if no users were found + */ +export const getUserIdFromSlackId = async (slackId: string): Promise => { + const user = await prisma.user.findFirst({ + where: { + userSettings: { + slackId + } + } + }); + + if (!user) return undefined; + + return user.userId; +}; diff --git a/src/backend/tests/integration/slackMessages.test.ts b/src/backend/tests/integration/slackMessages.test.ts index f870629260..703db97c1a 100644 --- a/src/backend/tests/integration/slackMessages.test.ts +++ b/src/backend/tests/integration/slackMessages.test.ts @@ -12,6 +12,7 @@ import * as apiFunctions from '../../src/integrations/slack'; import AnnouncementService from '../../src/services/announcement.service'; import slackServices from '../../src/services/slack.services'; import { vi } from 'vitest'; +import prisma from '../../src/prisma/prisma'; vi.mock('../../src/integrations/slack', async (importOriginal) => { return { @@ -36,6 +37,16 @@ describe('Slack message tests', () => { batman = await createTestUser(batmanAppAdmin, orgId, batmanSettings); superman = await createTestUser(supermanAdmin, orgId, supermanSettings); wonderwoman = await createTestUser(wonderwomanGuest, orgId, wonderwomanSettings); + await prisma.organization.update({ + where: { + organizationId: orgId + }, + data: { + users: { + set: [{ userId: batman.userId }, { userId: superman.userId }, { userId: wonderwoman.userId }] + } + } + }); }); afterEach(async () => { @@ -58,12 +69,10 @@ describe('Slack message tests', () => { orgId ); - console.log(announcement); - expect(spy).toBeCalledTimes(1); expect(spy).toBeCalledWith( 'test with @everyone broadcast (@everyone)', - [organization.userCreatedId, batman.userId, superman.userId, wonderwoman.userId], + [batman.userId, superman.userId, wonderwoman.userId], new Date(1000), 'Slack User Name', 'id_1', @@ -76,7 +85,7 @@ describe('Slack message tests', () => { expect(announcement?.senderName).toBe('Slack User Name'); expect(announcement?.slackChannelName).toBe('Slack Channel Name'); expect(announcement?.slackEventId).toBe('id_1'); - expect(announcement?.usersReceived).toHaveLength(4); + expect(announcement?.usersReceived).toHaveLength(3); }); it('Adds message to people in channel with @channel and @mention (w/o duplicates)', async () => { @@ -256,7 +265,6 @@ describe('Slack message tests', () => { expect(updateSpy).toBeCalledWith( '@Slack User Name added text', [wonderwoman.userId], - new Date(1000), 'Slack User Name', 'id_1', 'Slack Channel Name', @@ -302,7 +310,6 @@ describe('Slack message tests', () => { expect(updateSpy).toBeCalledWith( '@Slack User Name added text', [wonderwoman.userId], - new Date(1000), 'Slack User Name', 'id_1', 'Slack Channel Name', diff --git a/src/backend/tests/unit/announcements.test.ts b/src/backend/tests/unit/announcements.test.ts index 6eb0ec5ab6..8f701ec41d 100644 --- a/src/backend/tests/unit/announcements.test.ts +++ b/src/backend/tests/unit/announcements.test.ts @@ -88,7 +88,6 @@ describe('announcement tests', () => { const updatedAnnouncement = await AnnouncementService.updateAnnouncement( 'new text', [batman.userId, wonderwoman.userId], - new Date(1000000000000), 'sender name', 'slack id', 'channel name', @@ -113,7 +112,6 @@ describe('announcement tests', () => { await AnnouncementService.updateAnnouncement( 'new text', [batman.userId, wonderwoman.userId], - new Date(1000000000000), 'sender name', 'slack id', 'channel name',