Skip to content

Commit 870566c

Browse files
committed
feat: send Slack notification for removed users in HackerRank queue
1 parent 97993c7 commit 870566c

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

src/cron/__tests__/checkAllUsersActive.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,46 @@ describe('checkAllUsersActive', () => {
3232
expect(userRepo.remove).toHaveBeenCalledTimes(1);
3333
expect(userRepo.remove).toHaveBeenCalledWith('B');
3434
});
35+
36+
it('should send a Slack notification when users are removed', async () => {
37+
const app = buildMockApp();
38+
userRepo.listAll = jest.fn().mockResolvedValue([
39+
{ id: 'A', name: 'Alice Smith', languages: [], lastReviewedDate: 1 },
40+
{ id: 'B', name: 'Bob Jones', languages: [], lastReviewedDate: 2 },
41+
{ id: 'C', name: 'Charlie Brown', languages: [], lastReviewedDate: 3 },
42+
]);
43+
userRepo.remove = jest.fn();
44+
// First user active, second and third inactive
45+
userService.isActive = jest
46+
.fn()
47+
.mockResolvedValueOnce(true)
48+
.mockResolvedValueOnce(false)
49+
.mockResolvedValueOnce(false);
50+
51+
await checkAllUsersActive(app);
52+
53+
// Verify users were removed
54+
expect(userRepo.remove).toHaveBeenCalledTimes(2);
55+
expect(userRepo.remove).toHaveBeenCalledWith('B');
56+
expect(userRepo.remove).toHaveBeenCalledWith('C');
57+
58+
// Verify Slack notification was sent
59+
expect(app.client.chat.postMessage).toHaveBeenCalledTimes(1);
60+
expect(app.client.chat.postMessage).toHaveBeenCalledWith(
61+
expect.objectContaining({
62+
channel: process.env.ERRORS_CHANNEL_ID,
63+
text: expect.stringContaining('User(s) removed from HackerRank queue'),
64+
}),
65+
);
66+
67+
// Verify the message contains the removed users' names
68+
const callArgs = (app.client.chat.postMessage as jest.Mock).mock.calls[0][0];
69+
expect(callArgs.text).toContain('Bob Jones');
70+
expect(callArgs.text).toContain('Charlie Brown');
71+
72+
// Verify the message contains the Confluence link
73+
expect(callArgs.text).toContain(
74+
'https://allies.atlassian.net/wiki/spaces/REI/pages/4852121601/HackerRank+Roles+and+Permissions#Deactivating-a-User',
75+
);
76+
});
3577
});

src/cron/checkAllUsersActive.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function checkAllUsersActive(app: App): Promise<void> {
1616
const allUsers = await userRepo.listAll();
1717

1818
let allActive = true;
19+
const removedUsers: string[] = [];
1920
for (const user of allUsers) {
2021
const active = await userService.isActive(app.client, user.id);
2122
if (!active) {
@@ -25,10 +26,25 @@ export async function checkAllUsersActive(app: App): Promise<void> {
2526
`Removing deactivated user (${user.name}) from user sheet.`,
2627
);
2728
await userRepo.remove(user.id);
29+
removedUsers.push(user.name);
2830
}
2931
}
3032
if (allActive) {
3133
log.d('cron.checkAllUsersActive', '✔ All users are still active');
34+
} else if (removedUsers.length > 0) {
35+
// Notify about removed users who need HackerRank account deactivation
36+
const userList = removedUsers.map(name => `• ${name}`).join('\n');
37+
const deactivationLink =
38+
'https://allies.atlassian.net/wiki/spaces/REI/pages/4852121601/HackerRank+Roles+and+Permissions#Deactivating-a-User';
39+
const message = compose(
40+
`🚨 *User(s) removed from HackerRank queue* - No longer in Slack workspace`,
41+
'',
42+
userList,
43+
'',
44+
`⚠️ *Action Required:* Lock their HackerRank account(s)`,
45+
`📖 <${deactivationLink}|Deactivation Instructions>`,
46+
);
47+
await chatService.postTextMessage(app.client, process.env.ERRORS_CHANNEL_ID, message);
3248
}
3349
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3450
} catch (err: any) {

0 commit comments

Comments
 (0)