Skip to content

Commit f425132

Browse files
committed
made changes in the code as per reviews
1 parent 01c526d commit f425132

File tree

6 files changed

+76
-36
lines changed

6 files changed

+76
-36
lines changed

src/constants/commands.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ export const MENTION_EACH = {
3434
],
3535
};
3636

37-
export const KICK = {
38-
name: "kick",
39-
description: "Kick a user from the server",
37+
export const REMOVE = {
38+
name: "remove",
39+
description: "remove user/users from the server",
4040
options: [
4141
{
4242
name: "role",
43-
description: "The role to kick",
43+
description: "remove developers with specific role",
4444
type: 8, // User type
45-
required: false,
45+
required: true,
4646
},
4747
],
4848
};

src/controllers/baseHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
NOTIFY_ONBOARDING,
2828
OOO,
2929
USER,
30-
KICK,
30+
REMOVE,
3131
} from "../constants/commands";
3232
import { updateNickName } from "../utils/updateNickname";
3333
import { discordEphemeralResponse } from "../utils/discordEphemeralResponse";
@@ -79,7 +79,7 @@ export async function baseHandler(
7979
return await mentionEachUser(transformedArgument, env, ctx);
8080
}
8181

82-
case getCommandName(KICK): {
82+
case getCommandName(REMOVE): {
8383
const data = message.data?.options as Array<messageRequestDataOptions>;
8484
const transformedArgument = {
8585
roleToBeRemovedObj: data[0],

src/controllers/kickEachUser.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,19 @@ export async function kickEachUser(
2323
roleId
2424
);
2525

26+
const usersText = usersWithMatchingRole
27+
.map((user) => {
28+
return user;
29+
})
30+
.join("\n");
31+
2632
if (usersWithMatchingRole.length === 0) {
27-
return discordTextResponse(`Found no users with the matched role.`);
28-
} else {
29-
ctx.waitUntil(removeUsers(env, usersWithMatchingRole));
3033
return discordTextResponse(
31-
`Found ${usersWithMatchingRole.length} users with the matched role, removing them shortly...`
34+
`We couldn't find any user(s) assigned to <@&${roleId}> role.`
3235
);
36+
} else {
37+
ctx.waitUntil(removeUsers(env, usersWithMatchingRole));
38+
const responseText = `Following users are removed:\n${usersText}`;
39+
return discordTextResponse(responseText);
3340
}
3441
}

src/register.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
NOTIFY_ONBOARDING,
99
OOO,
1010
USER,
11-
KICK,
11+
REMOVE,
1212
} from "./constants/commands";
1313
import { config } from "dotenv";
1414
import { DISCORD_BASE_URL } from "./constants/urls";
@@ -38,7 +38,7 @@ async function registerGuildCommands(
3838
USER,
3939
NOTIFY_OVERDUE,
4040
NOTIFY_ONBOARDING,
41-
KICK,
41+
REMOVE,
4242
];
4343

4444
try {

src/utils/removeUsers.ts

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,58 @@
11
import { env } from "../typeDefinitions/default.types";
22
import { DISCORD_BASE_URL } from "../constants/urls";
3+
import {
4+
parseRateLimitRemaining,
5+
parseResetAfter,
6+
} from "./batchDiscordRequests";
37

4-
export const removeUsers = async (
5-
env: env,
6-
usersWithMatchingRole: string[]
7-
) => {
8-
const baseUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members`;
9-
// Method : DELETE /guilds/{guild.id}/members/{user.id}
10-
11-
for (const mention of usersWithMatchingRole) {
12-
// Remove <@ and > symbols from the mention
13-
const userId = mention.replace(/<@!*/g, "").replace(/>/g, "");
14-
const url = `${baseUrl}/${userId}`;
15-
16-
const headers = {
17-
"Content-Type": "application/json",
18-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
19-
};
20-
21-
try {
22-
await fetch(url, { method: "DELETE", headers });
23-
} catch (error) {
24-
console.error(`Error removing user with ID ${userId}:`, error);
8+
export async function removeUsers(env: env, usersWithMatchingRole: string[]) {
9+
const batchSize = 4;
10+
let waitTillNextAPICall = 0;
11+
12+
try {
13+
for (let i = 0; i < usersWithMatchingRole.length; i += batchSize) {
14+
const batchwiseUsers = usersWithMatchingRole.slice(i, i + batchSize);
15+
const deleteRequests = batchwiseUsers.map((mention) => {
16+
const userId = mention.replace(/<@!*/g, "").replace(/>/g, "");
17+
const url = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userId}`;
18+
19+
return fetch(url, {
20+
method: "DELETE",
21+
headers: {
22+
"Content-Type": "application/json",
23+
Authorization: `Bot ${env.DISCORD_TOKEN}`,
24+
},
25+
}).then(async (response) => {
26+
const rateLimitRemaining = parseRateLimitRemaining(response);
27+
28+
if (rateLimitRemaining === 0) {
29+
waitTillNextAPICall = Math.max(
30+
parseResetAfter(response),
31+
waitTillNextAPICall
32+
);
33+
}
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+
});
43+
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
48+
await sleep(waitTillNextAPICall * 1000);
49+
waitTillNextAPICall = 0;
2550
}
51+
} catch (error) {
52+
console.error("Error occurred while removing users:", error);
2653
}
27-
};
54+
}
55+
56+
function sleep(ms: number) {
57+
return new Promise((resolve) => setTimeout(resolve, ms));
58+
}

tests/unit/handlers/kickEachUser.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ describe("kickEachUser", () => {
1616
ctx
1717
);
1818

19+
const roleID = roleToBeTaggedObj.value;
20+
1921
expect(response).toBeInstanceOf(Promise);
2022

2123
const textMessage: { data: { content: string } } = await response.then(
2224
(res) => res.json()
2325
);
2426
expect(textMessage.data.content).toBe(
25-
"Found no users with the matched role."
27+
`We couldn't find any user(s) assigned to <@&${roleID}> role.`
2628
);
2729
});
2830
});

0 commit comments

Comments
 (0)