Skip to content

Commit 4f41844

Browse files
committed
Merge branch 'develop' into #4043-NigelPurvis-credits
2 parents 8333b3e + 67e389d commit 4f41844

3 files changed

Lines changed: 50 additions & 5 deletions

File tree

src/backend/src/integrations/slack.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,23 @@ export const getChannelName = async (channelId: string) => {
271271
}
272272
};
273273

274+
/**
275+
* Checks whether the bot is a member of the given channel
276+
* @param channelId the id of the slack channel
277+
* @returns true if the bot is a member of the channel, false otherwise
278+
*/
279+
export const checkBotInChannel = async (channelId: string): Promise<boolean> => {
280+
const client = getSlackClient();
281+
if (!client) return false;
282+
283+
try {
284+
const channelRes = await client.conversations.info({ channel: channelId });
285+
return channelRes.channel?.is_member ?? false;
286+
} catch (error) {
287+
return false;
288+
}
289+
};
290+
274291
/**
275292
* Given a slack user id, prood.uces the name of the channel
276293
* @param userId the id of the slack user

src/backend/src/services/attendance.services.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ import {
1010
meetingAttendanceTransformer,
1111
meetingAttendanceWithAttendeesTransformer
1212
} from '../transformers/attendance.transformer.js';
13-
import { editMessage, getChannelName, replyToMessageInThread, sendMessage } from '../integrations/slack.js';
13+
import {
14+
checkBotInChannel,
15+
editMessage,
16+
getChannelName,
17+
replyToMessageInThread,
18+
sendMessage
19+
} from '../integrations/slack.js';
1420
import { userHasPermission } from '../utils/users.utils.js';
1521

1622
export default class AttendanceService {
@@ -215,6 +221,7 @@ export default class AttendanceService {
215221
}
216222

217223
const channelName = await getChannelName(team.slackId);
218-
return { channelName, valid: !!channelName };
224+
const botInChannel = channelName ? await checkBotInChannel(team.slackId) : false;
225+
return { channelName, valid: !!channelName && botInChannel };
219226
}
220227
}

src/backend/tests/unit/attendance.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,21 @@ import { AccessDeniedException, HttpException, NotFoundException } from '../../s
55
import { batmanAppAdmin, supermanAdmin, greenlanternHead, wonderwomanGuest, member } from '../test-data/users.test-data.js';
66
import { createTestOrganization, createTestTeam, createTestTeamType, createTestUser, resetUsers } from '../test-utils.js';
77
import prisma from '../../src/prisma/prisma.js';
8-
import { sendMessage, editMessage, replyToMessageInThread, getChannelName } from '../../src/integrations/slack.js';
8+
import {
9+
sendMessage,
10+
editMessage,
11+
replyToMessageInThread,
12+
getChannelName,
13+
checkBotInChannel
14+
} from '../../src/integrations/slack.js';
915
import { Mock } from 'vitest';
1016

1117
vi.mock('../../src/integrations/slack.js', () => ({
1218
sendMessage: vi.fn(),
1319
editMessage: vi.fn(),
1420
replyToMessageInThread: vi.fn(),
15-
getChannelName: vi.fn()
21+
getChannelName: vi.fn(),
22+
checkBotInChannel: vi.fn()
1623
}));
1724

1825
// Creates a second test org with distinct credentials (since createTestOrganization uses a hardcoded empty email)
@@ -531,11 +538,25 @@ describe('Attendance Tests', () => {
531538
expect(result.channelName).toBeUndefined();
532539
});
533540

534-
it('returns valid: true with channel name if Slack channel is found', async () => {
541+
it('returns valid: false if Slack channel is found but bot is not a member', async () => {
535542
const head = await createTestUser(greenlanternHead, orgId);
536543
const team = await createTeamInOrg(head.userId, orgId);
537544

538545
(getChannelName as Mock).mockResolvedValue('ner-software');
546+
(checkBotInChannel as Mock).mockResolvedValue(false);
547+
548+
const result = await AttendanceService.checkTeamChannel(team.teamId, organization);
549+
550+
expect(result.valid).toBe(false);
551+
expect(result.channelName).toBe('ner-software');
552+
});
553+
554+
it('returns valid: true with channel name if Slack channel is found and bot is a member', async () => {
555+
const head = await createTestUser(greenlanternHead, orgId);
556+
const team = await createTeamInOrg(head.userId, orgId);
557+
558+
(getChannelName as Mock).mockResolvedValue('ner-software');
559+
(checkBotInChannel as Mock).mockResolvedValue(true);
539560

540561
const result = await AttendanceService.checkTeamChannel(team.teamId, organization);
541562

0 commit comments

Comments
 (0)