Skip to content

Commit dd9624e

Browse files
committed
improved the removeUsers functionality
1 parent f425132 commit dd9624e

File tree

5 files changed

+67
-20
lines changed

5 files changed

+67
-20
lines changed

src/controllers/baseHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export async function baseHandler(
8383
const data = message.data?.options as Array<messageRequestDataOptions>;
8484
const transformedArgument = {
8585
roleToBeRemovedObj: data[0],
86+
channelId: message.channel_id,
8687
};
8788
return await kickEachUser(transformedArgument, env, ctx);
8889
}

src/controllers/kickEachUser.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { removeUsers } from "../utils/removeUsers";
1111
export async function kickEachUser(
1212
transformedArgument: {
1313
roleToBeRemovedObj: MentionEachUserOptions;
14+
channelId: number;
1415
},
1516
env: env,
1617
ctx: ExecutionContext
@@ -34,8 +35,10 @@ export async function kickEachUser(
3435
`We couldn't find any user(s) assigned to <@&${roleId}> role.`
3536
);
3637
} else {
37-
ctx.waitUntil(removeUsers(env, usersWithMatchingRole));
38-
const responseText = `Following users are removed:\n${usersText}`;
38+
ctx.waitUntil(
39+
removeUsers(env, usersWithMatchingRole, transformedArgument.channelId)
40+
);
41+
const responseText = `Following users will be removed shortly ..... :\n${usersText}`;
3942
return discordTextResponse(responseText);
4043
}
4144
}

src/utils/removeUsers.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@ import {
44
parseRateLimitRemaining,
55
parseResetAfter,
66
} from "./batchDiscordRequests";
7+
import {
8+
discordMessageRequest,
9+
discordMessageError,
10+
} from "../typeDefinitions/discordMessage.types";
711

8-
export async function removeUsers(env: env, usersWithMatchingRole: string[]) {
12+
export async function removeUsers(
13+
env: env,
14+
usersWithMatchingRole: string[],
15+
channelId: number
16+
) {
917
const batchSize = 4;
1018
let waitTillNextAPICall = 0;
1119

1220
try {
21+
const failedUsers: Array<string> = [];
1322
for (let i = 0; i < usersWithMatchingRole.length; i += batchSize) {
1423
const batchwiseUsers = usersWithMatchingRole.slice(i, i + batchSize);
1524
const deleteRequests = batchwiseUsers.map((mention) => {
@@ -22,32 +31,41 @@ export async function removeUsers(env: env, usersWithMatchingRole: string[]) {
2231
"Content-Type": "application/json",
2332
Authorization: `Bot ${env.DISCORD_TOKEN}`,
2433
},
25-
}).then(async (response) => {
34+
}).then((response) => {
2635
const rateLimitRemaining = parseRateLimitRemaining(response);
27-
2836
if (rateLimitRemaining === 0) {
2937
waitTillNextAPICall = Math.max(
3038
parseResetAfter(response),
3139
waitTillNextAPICall
3240
);
3341
}
34-
35-
// Check if response status is 204 (No Content) indicating success
36-
if (response.status === 204) {
37-
return { success: true };
38-
} else {
39-
throw new Error(`Failed to remove user ${userId}.`);
40-
}
41-
});
42+
return response.json();
43+
}) as Promise<discordMessageRequest | discordMessageError>;
4244
});
4345

44-
// Wait for all delete requests in the batch to complete
45-
await Promise.all(deleteRequests);
46-
47-
// Wait until the next API call is allowed based on rate limits
46+
const responses = await Promise.all(deleteRequests);
47+
responses.forEach((response, i) => {
48+
if (response && "message" in response) {
49+
failedUsers.push(batchwiseUsers[i]);
50+
console.error(`Failed to remove a user`);
51+
}
52+
});
4853
await sleep(waitTillNextAPICall * 1000);
4954
waitTillNextAPICall = 0;
5055
}
56+
57+
if (failedUsers.length > 0) {
58+
await fetch(`${DISCORD_BASE_URL}/channels/${channelId}/messages`, {
59+
method: "POST",
60+
headers: {
61+
"Content-Type": "application/json",
62+
Authorization: `Bot ${env.DISCORD_TOKEN}`,
63+
},
64+
body: JSON.stringify({
65+
content: `Failed to remove ${failedUsers}.`,
66+
}),
67+
});
68+
}
5169
} catch (error) {
5270
console.error("Error occurred while removing users:", error);
5371
}

tests/unit/handlers/kickEachUser.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ describe("kickEachUser", () => {
1111

1212
const { roleToBeTaggedObj } = transformedArgument; // Extracting roleToBeTaggedObj
1313
const response = kickEachUser(
14-
{ roleToBeRemovedObj: roleToBeTaggedObj },
14+
{ roleToBeRemovedObj: roleToBeTaggedObj, channelId: 12345 },
1515
env,
1616
ctx
1717
);

tests/unit/utils/removeUsers.test.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ describe("removeUsers", () => {
99
DISCORD_TOKEN: "abc",
1010
};
1111

12+
beforeEach(() => {
13+
jest.clearAllMocks();
14+
});
15+
afterEach(() => {
16+
jest.clearAllMocks();
17+
jest.resetAllMocks();
18+
});
19+
1220
test("removes users successfully", async () => {
1321
const usersWithMatchingRole = ["<@userId1>", "<@userId2>"];
1422

@@ -17,7 +25,7 @@ describe("removeUsers", () => {
1725
.mockImplementation(() =>
1826
Promise.resolve(new Response(null, { status: 204 }))
1927
);
20-
await removeUsers(mockEnv, usersWithMatchingRole);
28+
await removeUsers(mockEnv, usersWithMatchingRole, 21121);
2129

2230
expect(fetch).toHaveBeenCalledTimes(2);
2331
expect(fetch).toHaveBeenCalledWith(
@@ -52,7 +60,7 @@ describe("removeUsers", () => {
5260
);
5361

5462
// Calling the function under test
55-
await removeUsers(mockEnv, usersWithMatchingRole);
63+
await removeUsers(mockEnv, usersWithMatchingRole, 23231);
5664

5765
// Expectations
5866
expect(fetch).toHaveBeenCalledWith(
@@ -66,4 +74,21 @@ describe("removeUsers", () => {
6674
}
6775
);
6876
});
77+
78+
it("should send a message of failed api calls at the end", async () => {
79+
let fetchCallCount = 0;
80+
const usersWithMatchingRole = ["<@userId1>", "<@userId2>", "<@userId3>"];
81+
82+
jest.spyOn(global, "fetch").mockImplementation(async () => {
83+
if (fetchCallCount < 3) {
84+
fetchCallCount++;
85+
return Promise.resolve(new JSONResponse({ message: "404: Not Found" }));
86+
} else {
87+
return Promise.resolve(new JSONResponse({ ok: true }));
88+
}
89+
});
90+
91+
await removeUsers(mockEnv, usersWithMatchingRole, 23231);
92+
expect(fetch).toHaveBeenCalledTimes(4); // should send a message of failed api calls at the end
93+
});
6994
});

0 commit comments

Comments
 (0)