Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/constants/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ export const RETRY_COMMAND =
export const ROLE_ADDED = "Role added successfully";

export const NAME_CHANGED = "User nickname changed successfully";

export const ROLE_REMOVED = "Role Removed successfully";

export const VERIFICATION_STRING =
"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.";

export const ROLE_FETCH_FAILED =
"Oops! We are experiencing an issue fetching roles.";

export const BAD_REQUEST = {
error: "Oops! This is not a proper request.",
};
104 changes: 103 additions & 1 deletion src/controllers/guildRoleHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import * as response from "../constants/responses";
import { env } from "../typeDefinitions/default.types";
import JSONResponse from "../utils/JsonResponse";
import { IRequest } from "itty-router";
import { addGroupRole, createGuildRole } from "../utils/guildRole";
import {
addGroupRole,
createGuildRole,
removeGuildRole,
getGuildRoleByName,
getGuildRoles,
} from "../utils/guildRole";
import {
createNewRole,
memberGroupRole,
Expand Down Expand Up @@ -39,3 +45,99 @@ export async function addGroupRoleHandler(request: IRequest, env: env) {
return new JSONResponse(response.BAD_SIGNATURE);
}
}

export async function removeGuildRoleHandler(request: IRequest, env: env) {
const authHeader = request.headers.get("Authorization");
if (!authHeader) {
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
}
try {
await verifyAuthToken(authHeader, env);
const body: memberGroupRole = await request.json();
const res = await removeGuildRole(body, env);
return new JSONResponse(res, {
status: 200,
headers: {
"content-type": "application/json;charset=UTF-8",
},
});
} catch (err) {
return new JSONResponse(response.INTERNAL_SERVER_ERROR, {
status: 500,
headers: {
"content-type": "application/json;charset=UTF-8",
},
});
}
}
export async function getGuildRolesHandler(request: IRequest, env: env) {
const authHeader = request.headers.get("Authorization");

if (!authHeader) {
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
}
try {
await verifyAuthToken(authHeader, env);
const roles = await getGuildRoles(env);
return new JSONResponse({ roles });
} catch (err: any) {
const error =
err?.message === response.ROLE_FETCH_FAILED
? response.ROLE_FETCH_FAILED
: response.INTERNAL_SERVER_ERROR;
return new JSONResponse(
{
error,
},
{
status: 500,
headers: {
"content-type": "application/json;charset=UTF-8",
},
}
);
}
}

export async function getGuildRoleByRoleNameHandler(
request: IRequest,
env: env
) {
const authHeader = request.headers.get("Authorization");
const roleName = decodeURI(request.params?.roleName ?? "");

if (!authHeader) {
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
}

if (!roleName) {
return new JSONResponse(response.BAD_REQUEST, { status: 404 });
}
try {
await verifyAuthToken(authHeader, env);
const role = await getGuildRoleByName(roleName, env);
if (!role) {
return new JSONResponse(response.NOT_FOUND, {
status: 404,
headers: {
"content-type": "application/json;charset=UTF-8",
},
});
}
return new JSONResponse(role);
} catch (err: any) {
const error =
err?.message === response.ROLE_FETCH_FAILED
? response.ROLE_FETCH_FAILED
: response.INTERNAL_SERVER_ERROR;
return new JSONResponse(
{ error },
{
status: 500,
headers: {
"content-type": "application/json;charset=UTF-8",
},
}
);
}
}
4 changes: 2 additions & 2 deletions src/controllers/verifyCommand.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import config from "../../config/config";
import { RETRY_COMMAND } from "../constants/responses";
import { RETRY_COMMAND, VERIFICATION_STRING } from "../constants/responses";
import { env } from "../typeDefinitions/default.types";
import { discordEphemeralResponse } from "../utils/discordEphemeralResponse";
import { generateUniqueToken } from "../utils/generateUniqueToken";
Expand All @@ -24,7 +24,7 @@ export async function verifyCommand(
);
if (response?.status === 201 || response?.status === 200) {
const verificationSiteURL = config(env).VERIFICATION_SITE_URL;
const message = `${verificationSiteURL}/discord?token=${token}`;
const message = `${verificationSiteURL}/discord?token=${token}\n${VERIFICATION_STRING}`;
return discordEphemeralResponse(message);
} else {
return discordEphemeralResponse(RETRY_COMMAND);
Expand Down
9 changes: 9 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { verifyBot } from "./utils/verifyBot";
import {
addGroupRoleHandler,
createGuildRoleHandler,
removeGuildRoleHandler,
getGuildRoleByRoleNameHandler,
getGuildRolesHandler,
} from "./controllers/guildRoleHandler";
import { getMembersInServerHandler } from "./controllers/getMembersInServer";
import { changeNickname } from "./controllers/changeNickname";
Expand All @@ -28,6 +31,12 @@ router.put("/roles/create", createGuildRoleHandler);

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

router.delete("/roles", removeGuildRoleHandler);

router.get("/roles", getGuildRolesHandler);

router.get("/roles/:roleName", getGuildRoleByRoleNameHandler);

router.get("/discord-members", getMembersInServerHandler);

router.get("/member/:id", getGuildMemberDetailsHandler);
Expand Down
12 changes: 12 additions & 0 deletions src/typeDefinitions/role.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type GuildRole = {
id: string;
name: string;
color: string;
hoist: boolean;
icon?: string;
position?: integer;
managed?: boolean;
mentionable?: boolean;
};

export type Role = Pick<GuildRole, "id" | "name">;
68 changes: 67 additions & 1 deletion src/utils/guildRole.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { INTERNAL_SERVER_ERROR, ROLE_ADDED } from "../constants/responses";
import {
INTERNAL_SERVER_ERROR,
ROLE_ADDED,
ROLE_FETCH_FAILED,
ROLE_REMOVED,
} from "../constants/responses";
import { DISCORD_BASE_URL } from "../constants/urls";
import { env } from "../typeDefinitions/default.types";
import {
createNewRole,
guildRoleResponse,
memberGroupRole,
} from "../typeDefinitions/discordMessage.types";
import { GuildRole, Role } from "../typeDefinitions/role.types";

export async function createGuildRole(
body: createNewRole,
Expand Down Expand Up @@ -55,3 +61,63 @@ export async function addGroupRole(body: memberGroupRole, env: env) {
return INTERNAL_SERVER_ERROR;
}
}

export async function removeGuildRole(details: memberGroupRole, env: env) {
const { userid, roleid } = details;
const removeGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
try {
const response = await fetch(removeGuildRoleUrl, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
});
if (response.ok) {
return {
message: ROLE_REMOVED,
userAffected: {
userid,
roleid,
},
};
}
} catch (err) {
return INTERNAL_SERVER_ERROR;
}
}

export async function getGuildRoles(env: env): Promise<Array<Role>> {
const guildRolesUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`;

try {
const response = await fetch(guildRolesUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
});

if (!response.ok) {
throw new Error(ROLE_FETCH_FAILED);
}

const guildRoles: Array<GuildRole> = await response.json();

return guildRoles.map((role) => ({
id: role.id,
name: role.name,
}));
} catch (err) {
throw new Error(ROLE_FETCH_FAILED);
}
}

export async function getGuildRoleByName(
roleName: string,
env: env
): Promise<Role | undefined> {
const roles = await getGuildRoles(env);
return roles?.find((role) => role.name === roleName);
}
40 changes: 40 additions & 0 deletions tests/fixtures/fixture.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IRequest } from "itty-router";
import {
createNewRole,
discordMessageRequest,
Expand Down Expand Up @@ -95,3 +96,42 @@ export const onlyRoleToBeTagged = {
value: "1118201414078976192",
},
};

export const generateDummyRequestObject = ({
url,
method,
params,
query,
headers, // Object of key value pair
}: Partial<IRequest>): IRequest => {
return {
method: method ?? "GET",
url: url ?? "/roles",
params: params ?? {},
query: query ?? {},
headers: new Map(Object.entries(headers ?? {})),
};
};

export const rolesMock = [
{
id: "1234567889",
name: "@everyone",
permissions: "",
position: 2,
color: 2,
hoist: true,
managed: true,
mentionable: true,
},
{
id: "12344567",
name: "bot one",
permissions: "",
position: 2,
color: 2,
hoist: true,
managed: true,
mentionable: true,
},
];
Loading