Skip to content

Commit a1903ff

Browse files
Feature: Create Discord API Endpoint to Remove Role from User (#82)
* add an api endpoint to relete role on discord * revert commits to urls * add test for remove guild role api * remove unwanted changes * add proper response headers
1 parent c3febba commit a1903ff

File tree

5 files changed

+106
-3
lines changed

5 files changed

+106
-3
lines changed

src/constants/responses.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ export const RETRY_COMMAND =
2525
export const ROLE_ADDED = "Role added successfully";
2626

2727
export const NAME_CHANGED = "User nickname changed successfully";
28+
29+
export const ROLE_REMOVED = "Role Removed successfully";

src/controllers/guildRoleHandler.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import * as response from "../constants/responses";
22
import { env } from "../typeDefinitions/default.types";
33
import JSONResponse from "../utils/JsonResponse";
44
import { IRequest } from "itty-router";
5-
import { addGroupRole, createGuildRole } from "../utils/guildRole";
5+
import {
6+
addGroupRole,
7+
createGuildRole,
8+
removeGuildRole,
9+
} from "../utils/guildRole";
610
import {
711
createNewRole,
812
memberGroupRole,
@@ -39,3 +43,28 @@ export async function addGroupRoleHandler(request: IRequest, env: env) {
3943
return new JSONResponse(response.BAD_SIGNATURE);
4044
}
4145
}
46+
47+
export async function removeGuildRoleHandler(request: IRequest, env: env) {
48+
const authHeader = request.headers.get("Authorization");
49+
if (!authHeader) {
50+
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
51+
}
52+
try {
53+
await verifyAuthToken(authHeader, env);
54+
const body: memberGroupRole = await request.json();
55+
const res = await removeGuildRole(body, env);
56+
return new JSONResponse(res, {
57+
status: 200,
58+
headers: {
59+
"content-type": "application/json;charset=UTF-8",
60+
},
61+
});
62+
} catch (err) {
63+
return new JSONResponse(response.INTERNAL_SERVER_ERROR, {
64+
status: 500,
65+
headers: {
66+
"content-type": "application/json;charset=UTF-8",
67+
},
68+
});
69+
}
70+
}

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { verifyBot } from "./utils/verifyBot";
99
import {
1010
addGroupRoleHandler,
1111
createGuildRoleHandler,
12+
removeGuildRoleHandler,
1213
} from "./controllers/guildRoleHandler";
1314
import { getMembersInServerHandler } from "./controllers/getMembersInServer";
1415
import { changeNickname } from "./controllers/changeNickname";
@@ -28,6 +29,8 @@ router.put("/roles/create", createGuildRoleHandler);
2829

2930
router.put("/roles/add", addGroupRoleHandler);
3031

32+
router.delete("/roles", removeGuildRoleHandler);
33+
3134
router.get("/discord-members", getMembersInServerHandler);
3235

3336
router.get("/member/:id", getGuildMemberDetailsHandler);

src/utils/guildRole.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { INTERNAL_SERVER_ERROR, ROLE_ADDED } from "../constants/responses";
1+
import {
2+
INTERNAL_SERVER_ERROR,
3+
ROLE_ADDED,
4+
ROLE_REMOVED,
5+
} from "../constants/responses";
26
import { DISCORD_BASE_URL } from "../constants/urls";
37
import { env } from "../typeDefinitions/default.types";
48
import {
@@ -55,3 +59,28 @@ export async function addGroupRole(body: memberGroupRole, env: env) {
5559
return INTERNAL_SERVER_ERROR;
5660
}
5761
}
62+
63+
export async function removeGuildRole(details: memberGroupRole, env: env) {
64+
const { userid, roleid } = details;
65+
const removeGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
66+
try {
67+
const response = await fetch(removeGuildRoleUrl, {
68+
method: "DELETE",
69+
headers: {
70+
"Content-Type": "application/json",
71+
Authorization: `Bot ${env.DISCORD_TOKEN}`,
72+
},
73+
});
74+
if (response.ok) {
75+
return {
76+
message: ROLE_REMOVED,
77+
userAffected: {
78+
userid,
79+
roleid,
80+
},
81+
};
82+
}
83+
} catch (err) {
84+
return INTERNAL_SERVER_ERROR;
85+
}
86+
}

tests/unit/utils/guildRole.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import JSONResponse from "../../../src/utils/JsonResponse";
22
import * as response from "../../../src/constants/responses";
3-
import { createGuildRole, addGroupRole } from "../../../src/utils/guildRole";
3+
import {
4+
createGuildRole,
5+
addGroupRole,
6+
removeGuildRole,
7+
} from "../../../src/utils/guildRole";
48
import {
59
dummyAddRoleBody,
610
dummyCreateBody,
@@ -89,3 +93,39 @@ describe("addGroupRole", () => {
8993
);
9094
});
9195
});
96+
97+
describe("removeGuildRole", () => {
98+
test("Should return success message on proper response", async () => {
99+
const mockResponse = {
100+
ok: true,
101+
};
102+
jest
103+
.spyOn(global, "fetch")
104+
.mockImplementation(() =>
105+
Promise.resolve(new JSONResponse(mockResponse))
106+
);
107+
const result = await removeGuildRole(dummyAddRoleBody, guildEnv);
108+
expect(global.fetch).toHaveBeenCalledWith(
109+
`https://discord.com/api/v10/guilds/${guildEnv.DISCORD_GUILD_ID}/members/${dummyAddRoleBody.userid}/roles/${dummyAddRoleBody.roleid}`,
110+
{
111+
method: "DELETE",
112+
headers: {
113+
"Content-Type": "application/json",
114+
Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`,
115+
},
116+
}
117+
);
118+
expect(result).toEqual({
119+
message: response.ROLE_REMOVED,
120+
userAffected: {
121+
userid: dummyAddRoleBody.userid,
122+
roleid: dummyAddRoleBody.roleid,
123+
},
124+
});
125+
});
126+
test("Should return internal error response on api failure", async () => {
127+
jest.spyOn(global, "fetch").mockRejectedValue("Oops some error");
128+
const result = await removeGuildRole(dummyAddRoleBody, guildEnv);
129+
expect(result).toEqual(response.INTERNAL_SERVER_ERROR);
130+
});
131+
});

0 commit comments

Comments
 (0)