Skip to content

Commit b12b711

Browse files
shreya-mishrabksh05RitikJaiswal75sahsisunny
authored
Dev to main sync (#96)
* adding tests for roles endpoint * 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 * adding tests for roles endpoint * [Feature] Add APIs for fetching role information * removing unnecessary constants * Adding headers in response objects * Adding extra try blocks in utils to handle errors * Throwing errors when something goes wrong * moving test constants to fixtures * changing error type thrown on bad request * Using roles url of discord to get roles details * Raising different PR for /verify string (#94) * raising different PR for /verify string * resolved the comment * fix lint issue * fix lint issue --------- Co-authored-by: Bikash Singh <[email protected]> Co-authored-by: Ritik Jaiswal <[email protected]> Co-authored-by: Sunny Sahsi <[email protected]>
1 parent df717e8 commit b12b711

File tree

9 files changed

+626
-5
lines changed

9 files changed

+626
-5
lines changed

src/constants/responses.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,15 @@ 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";
30+
31+
export const VERIFICATION_STRING =
32+
"Please verify your identity by clicking the link above and granting authorization to the Real Dev Squad. This will allow us to manage your Discord data.";
33+
34+
export const ROLE_FETCH_FAILED =
35+
"Oops! We are experiencing an issue fetching roles.";
36+
37+
export const BAD_REQUEST = {
38+
error: "Oops! This is not a proper request.",
39+
};

src/controllers/guildRoleHandler.ts

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ 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+
getGuildRoleByName,
10+
getGuildRoles,
11+
} from "../utils/guildRole";
612
import {
713
createNewRole,
814
memberGroupRole,
@@ -39,3 +45,99 @@ export async function addGroupRoleHandler(request: IRequest, env: env) {
3945
return new JSONResponse(response.BAD_SIGNATURE);
4046
}
4147
}
48+
49+
export async function removeGuildRoleHandler(request: IRequest, env: env) {
50+
const authHeader = request.headers.get("Authorization");
51+
if (!authHeader) {
52+
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
53+
}
54+
try {
55+
await verifyAuthToken(authHeader, env);
56+
const body: memberGroupRole = await request.json();
57+
const res = await removeGuildRole(body, env);
58+
return new JSONResponse(res, {
59+
status: 200,
60+
headers: {
61+
"content-type": "application/json;charset=UTF-8",
62+
},
63+
});
64+
} catch (err) {
65+
return new JSONResponse(response.INTERNAL_SERVER_ERROR, {
66+
status: 500,
67+
headers: {
68+
"content-type": "application/json;charset=UTF-8",
69+
},
70+
});
71+
}
72+
}
73+
export async function getGuildRolesHandler(request: IRequest, env: env) {
74+
const authHeader = request.headers.get("Authorization");
75+
76+
if (!authHeader) {
77+
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
78+
}
79+
try {
80+
await verifyAuthToken(authHeader, env);
81+
const roles = await getGuildRoles(env);
82+
return new JSONResponse({ roles });
83+
} catch (err: any) {
84+
const error =
85+
err?.message === response.ROLE_FETCH_FAILED
86+
? response.ROLE_FETCH_FAILED
87+
: response.INTERNAL_SERVER_ERROR;
88+
return new JSONResponse(
89+
{
90+
error,
91+
},
92+
{
93+
status: 500,
94+
headers: {
95+
"content-type": "application/json;charset=UTF-8",
96+
},
97+
}
98+
);
99+
}
100+
}
101+
102+
export async function getGuildRoleByRoleNameHandler(
103+
request: IRequest,
104+
env: env
105+
) {
106+
const authHeader = request.headers.get("Authorization");
107+
const roleName = decodeURI(request.params?.roleName ?? "");
108+
109+
if (!authHeader) {
110+
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
111+
}
112+
113+
if (!roleName) {
114+
return new JSONResponse(response.BAD_REQUEST, { status: 404 });
115+
}
116+
try {
117+
await verifyAuthToken(authHeader, env);
118+
const role = await getGuildRoleByName(roleName, env);
119+
if (!role) {
120+
return new JSONResponse(response.NOT_FOUND, {
121+
status: 404,
122+
headers: {
123+
"content-type": "application/json;charset=UTF-8",
124+
},
125+
});
126+
}
127+
return new JSONResponse(role);
128+
} catch (err: any) {
129+
const error =
130+
err?.message === response.ROLE_FETCH_FAILED
131+
? response.ROLE_FETCH_FAILED
132+
: response.INTERNAL_SERVER_ERROR;
133+
return new JSONResponse(
134+
{ error },
135+
{
136+
status: 500,
137+
headers: {
138+
"content-type": "application/json;charset=UTF-8",
139+
},
140+
}
141+
);
142+
}
143+
}

src/controllers/verifyCommand.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import config from "../../config/config";
2-
import { RETRY_COMMAND } from "../constants/responses";
2+
import { RETRY_COMMAND, VERIFICATION_STRING } from "../constants/responses";
33
import { env } from "../typeDefinitions/default.types";
44
import { discordEphemeralResponse } from "../utils/discordEphemeralResponse";
55
import { generateUniqueToken } from "../utils/generateUniqueToken";
@@ -24,7 +24,7 @@ export async function verifyCommand(
2424
);
2525
if (response?.status === 201 || response?.status === 200) {
2626
const verificationSiteURL = config(env).VERIFICATION_SITE_URL;
27-
const message = `${verificationSiteURL}/discord?token=${token}`;
27+
const message = `${verificationSiteURL}/discord?token=${token}\n${VERIFICATION_STRING}`;
2828
return discordEphemeralResponse(message);
2929
} else {
3030
return discordEphemeralResponse(RETRY_COMMAND);

src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { verifyBot } from "./utils/verifyBot";
99
import {
1010
addGroupRoleHandler,
1111
createGuildRoleHandler,
12+
removeGuildRoleHandler,
13+
getGuildRoleByRoleNameHandler,
14+
getGuildRolesHandler,
1215
} from "./controllers/guildRoleHandler";
1316
import { getMembersInServerHandler } from "./controllers/getMembersInServer";
1417
import { changeNickname } from "./controllers/changeNickname";
@@ -28,6 +31,12 @@ router.put("/roles/create", createGuildRoleHandler);
2831

2932
router.put("/roles/add", addGroupRoleHandler);
3033

34+
router.delete("/roles", removeGuildRoleHandler);
35+
36+
router.get("/roles", getGuildRolesHandler);
37+
38+
router.get("/roles/:roleName", getGuildRoleByRoleNameHandler);
39+
3140
router.get("/discord-members", getMembersInServerHandler);
3241

3342
router.get("/member/:id", getGuildMemberDetailsHandler);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export type GuildRole = {
2+
id: string;
3+
name: string;
4+
color: string;
5+
hoist: boolean;
6+
icon?: string;
7+
position?: integer;
8+
managed?: boolean;
9+
mentionable?: boolean;
10+
};
11+
12+
export type Role = Pick<GuildRole, "id" | "name">;

src/utils/guildRole.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import { INTERNAL_SERVER_ERROR, ROLE_ADDED } from "../constants/responses";
1+
import {
2+
INTERNAL_SERVER_ERROR,
3+
ROLE_ADDED,
4+
ROLE_FETCH_FAILED,
5+
ROLE_REMOVED,
6+
} from "../constants/responses";
27
import { DISCORD_BASE_URL } from "../constants/urls";
38
import { env } from "../typeDefinitions/default.types";
49
import {
510
createNewRole,
611
guildRoleResponse,
712
memberGroupRole,
813
} from "../typeDefinitions/discordMessage.types";
14+
import { GuildRole, Role } from "../typeDefinitions/role.types";
915

1016
export async function createGuildRole(
1117
body: createNewRole,
@@ -55,3 +61,63 @@ export async function addGroupRole(body: memberGroupRole, env: env) {
5561
return INTERNAL_SERVER_ERROR;
5662
}
5763
}
64+
65+
export async function removeGuildRole(details: memberGroupRole, env: env) {
66+
const { userid, roleid } = details;
67+
const removeGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
68+
try {
69+
const response = await fetch(removeGuildRoleUrl, {
70+
method: "DELETE",
71+
headers: {
72+
"Content-Type": "application/json",
73+
Authorization: `Bot ${env.DISCORD_TOKEN}`,
74+
},
75+
});
76+
if (response.ok) {
77+
return {
78+
message: ROLE_REMOVED,
79+
userAffected: {
80+
userid,
81+
roleid,
82+
},
83+
};
84+
}
85+
} catch (err) {
86+
return INTERNAL_SERVER_ERROR;
87+
}
88+
}
89+
90+
export async function getGuildRoles(env: env): Promise<Array<Role>> {
91+
const guildRolesUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`;
92+
93+
try {
94+
const response = await fetch(guildRolesUrl, {
95+
method: "GET",
96+
headers: {
97+
"Content-Type": "application/json",
98+
Authorization: `Bot ${env.DISCORD_TOKEN}`,
99+
},
100+
});
101+
102+
if (!response.ok) {
103+
throw new Error(ROLE_FETCH_FAILED);
104+
}
105+
106+
const guildRoles: Array<GuildRole> = await response.json();
107+
108+
return guildRoles.map((role) => ({
109+
id: role.id,
110+
name: role.name,
111+
}));
112+
} catch (err) {
113+
throw new Error(ROLE_FETCH_FAILED);
114+
}
115+
}
116+
117+
export async function getGuildRoleByName(
118+
roleName: string,
119+
env: env
120+
): Promise<Role | undefined> {
121+
const roles = await getGuildRoles(env);
122+
return roles?.find((role) => role.name === roleName);
123+
}

tests/fixtures/fixture.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { IRequest } from "itty-router";
12
import {
23
createNewRole,
34
discordMessageRequest,
@@ -95,3 +96,42 @@ export const onlyRoleToBeTagged = {
9596
value: "1118201414078976192",
9697
},
9798
};
99+
100+
export const generateDummyRequestObject = ({
101+
url,
102+
method,
103+
params,
104+
query,
105+
headers, // Object of key value pair
106+
}: Partial<IRequest>): IRequest => {
107+
return {
108+
method: method ?? "GET",
109+
url: url ?? "/roles",
110+
params: params ?? {},
111+
query: query ?? {},
112+
headers: new Map(Object.entries(headers ?? {})),
113+
};
114+
};
115+
116+
export const rolesMock = [
117+
{
118+
id: "1234567889",
119+
name: "@everyone",
120+
permissions: "",
121+
position: 2,
122+
color: 2,
123+
hoist: true,
124+
managed: true,
125+
mentionable: true,
126+
},
127+
{
128+
id: "12344567",
129+
name: "bot one",
130+
permissions: "",
131+
position: 2,
132+
color: 2,
133+
hoist: true,
134+
managed: true,
135+
mentionable: true,
136+
},
137+
];

0 commit comments

Comments
 (0)