Skip to content

Commit

Permalink
Merge branch 'develop' into grant-aws-access
Browse files Browse the repository at this point in the history
  • Loading branch information
vikhyat187 authored Nov 12, 2024
2 parents cb6770b + 79dd9ba commit b70a6b6
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/constants/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ export const INVALID_TOKEN_FORMAT =
export const AUTHENTICATION_ERROR = "Invalid Authentication token";
export const TASK_UPDATE_SENT_MESSAGE =
"Task update sent on Discord's tracking-updates channel.";
export const NOT_IMPLEMENTED = "Feature not implemented";
44 changes: 44 additions & 0 deletions src/controllers/deleteGuildRoleHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { IRequest } from "itty-router";
import JSONResponse from "../utils/JsonResponse";
import { env } from "../typeDefinitions/default.types";
import * as response from "../constants/responses";
import { verifyNodejsBackendAuthToken } from "../utils/verifyAuthToken";
import { deleteGuildRole } from "../utils/deleteGuildRole";

export async function deleteGuildRoleHandler(request: IRequest, env: env) {
const authHeader = request.headers.get("Authorization");
const reason = request.headers.get("X-Audit-Log-Reason");
const roleId = decodeURI(request.params?.roleId ?? "");
const { dev } = request.query;
const devFlag = dev === "true";

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

if (!devFlag) {
return new JSONResponse(response.NOT_IMPLEMENTED, { status: 501 });
}

if (!roleId) {
return new JSONResponse(response.BAD_REQUEST, { status: 400 });
}

try {
await verifyNodejsBackendAuthToken(authHeader, env);
const result = await deleteGuildRole(env, roleId, reason);

if (result === response.ROLE_REMOVED) {
return new Response(null, { status: 204 });
} else {
return new JSONResponse(response.INTERNAL_SERVER_ERROR, {
status: 500,
});
}
} catch (err) {
console.error("An error occurred while deleting discord role:", err);
return new JSONResponse(response.INTERNAL_SERVER_ERROR, {
status: 500,
});
}
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { sendProfileBlockedMessage } from "./controllers/profileHandler";
import { sendTaskUpdatesHandler } from "./controllers/taskUpdatesHandler";

import config, { loadEnv } from "./../config/config";
import { deleteGuildRoleHandler } from "./controllers/deleteGuildRoleHandler";

const router = Router();

Expand All @@ -34,6 +35,8 @@ router.get("/", async () => {

router.patch("/guild/member", changeNickname);

router.delete("/roles/:roleId", deleteGuildRoleHandler);

router.put("/roles/create", createGuildRoleHandler);

router.put("/roles/add", addGroupRoleHandler);
Expand Down
30 changes: 30 additions & 0 deletions src/utils/deleteGuildRole.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { INTERNAL_SERVER_ERROR, ROLE_REMOVED } from "../constants/responses";
import { DISCORD_BASE_URL } from "../constants/urls";
import { env } from "../typeDefinitions/default.types";
import createDiscordHeaders from "./createDiscordHeaders";

export async function deleteGuildRole(
env: env,
roleId: string,
reason?: string
) {
const deleteGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles/${roleId}`;
const headers: HeadersInit = createDiscordHeaders({
token: env.DISCORD_TOKEN,
reason: reason,
});
try {
const response = await fetch(deleteGuildRoleUrl, {
method: "DELETE",
headers,
});
if (response.ok) {
return ROLE_REMOVED;
} else {
return INTERNAL_SERVER_ERROR;
}
} catch (err) {
console.error("An error occurred while deleting discord role:", err);
return INTERNAL_SERVER_ERROR;
}
}
129 changes: 129 additions & 0 deletions tests/unit/handlers/deleteGuildRoleHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { generateDummyRequestObject, guildEnv } from "../../fixtures/fixture";
import * as responseConstants from "../../../src/constants/responses";
import * as verifyTokenUtils from "../../../src/utils/verifyAuthToken";
import { deleteGuildRoleHandler } from "../../../src/controllers/deleteGuildRoleHandler";
import * as deleteGuildRoleUtils from "../../../src/utils/deleteGuildRole";

describe("deleteGuildRoleHandler", () => {
afterEach(() => {
jest.restoreAllMocks();
});
beforeEach(() => {
jest.clearAllMocks();
});
const roleId = "1A32BEX04";
it("should return NOT_IMPLEMENTED when dev is false", async () => {
const mockRequest = generateDummyRequestObject({
url: "/roles",
params: {
roleId: roleId,
},
query: {
dev: "false",
},
method: "DELETE",
headers: { Authorization: "Bearer testtoken" },
});
const response = await deleteGuildRoleHandler(mockRequest, guildEnv);
const jsonResponse = await response.json();
expect(jsonResponse).toEqual(responseConstants.NOT_IMPLEMENTED);
});
it("should return BAD_REQUEST when roleId is not valid", async () => {
const mockRequest = generateDummyRequestObject({
url: "/roles",
params: {
roleId: "",
},
query: {
dev: "true",
},
method: "DELETE",
headers: { Authorization: "Bearer testtoken" },
});
const response = await deleteGuildRoleHandler(mockRequest, guildEnv);
const jsonResponse = await response.json();
expect(jsonResponse).toEqual(responseConstants.BAD_REQUEST);
});
it("should return BAD_SIGNATURE when authorization header is not provided", async () => {
const mockRequest = generateDummyRequestObject({
url: "/roles",
params: {
roleId: roleId,
},
query: {
dev: "true",
},
method: "DELETE",
});
const response = await deleteGuildRoleHandler(mockRequest, guildEnv);
const jsonResponse = await response.json();
expect(jsonResponse).toEqual(responseConstants.BAD_SIGNATURE);
});
it("should return INTERNAL_SERVER_ERROR when response is not ok", async () => {
const expectedResponse = responseConstants.INTERNAL_SERVER_ERROR;
const mockRequest = generateDummyRequestObject({
url: "/roles",
params: {
roleId: roleId,
},
query: {
dev: "true",
},
method: "DELETE",
headers: { Authorization: "Bearer testtoken" },
});
jest
.spyOn(deleteGuildRoleUtils, "deleteGuildRole")
.mockResolvedValue(expectedResponse);
const response = await deleteGuildRoleHandler(mockRequest, guildEnv);
const jsonResponse = await response.json();
expect(jsonResponse).toEqual(expectedResponse);
});
it("should return INTERNAL_SERVER_ERROR when token is not verified", async () => {
const expectedResponse = responseConstants.INTERNAL_SERVER_ERROR;
const mockRequest = generateDummyRequestObject({
url: "/roles",
method: "DELETE",
params: {
roleId: roleId,
},
query: {
dev: "true",
},
headers: { Authorization: "Bearer testtoken" },
});
jest
.spyOn(verifyTokenUtils, "verifyNodejsBackendAuthToken")
.mockRejectedValue(expectedResponse);
const response = await deleteGuildRoleHandler(mockRequest, guildEnv);
const jsonResponse = await response.json();
expect(jsonResponse).toEqual(expectedResponse);
});
it("should return ok response", async () => {
const expectedResponse = new Response(null, {
status: 204,
});
const mockRequest = generateDummyRequestObject({
url: "/roles",
method: "DELETE",
params: {
roleId: roleId,
},
query: {
dev: "true",
},
headers: { Authorization: "Bearer testtoken" },
});
const verifyTokenSpy = jest
.spyOn(verifyTokenUtils, "verifyNodejsBackendAuthToken")
.mockResolvedValueOnce();
const deleteGuildRoleSpy = jest
.spyOn(deleteGuildRoleUtils, "deleteGuildRole")
.mockResolvedValueOnce(responseConstants.ROLE_REMOVED);
const response = await deleteGuildRoleHandler(mockRequest, guildEnv);
expect(verifyTokenSpy).toHaveBeenCalledTimes(1);
expect(deleteGuildRoleSpy).toHaveBeenCalledTimes(1);
expect(response).toEqual(expectedResponse);
expect(response.status).toEqual(expectedResponse.status);
});
});
56 changes: 56 additions & 0 deletions tests/unit/utils/deleteGuildRole.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { DISCORD_BASE_URL } from "../../../src/constants/urls";
import { deleteGuildRole } from "../../../src/utils/deleteGuildRole";
import JSONResponse from "../../../src/utils/JsonResponse";
import { guildEnv } from "../../fixtures/fixture";
import * as response from "../../../src/constants/responses";

describe("deleteGuildRole", () => {
const roleId = "1A32BEX04";
const deleteGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${guildEnv.DISCORD_GUILD_ID}/roles/${roleId}`;
const mockRequestInit = {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`,
"X-Audit-Log-Reason": "This is reason for this action",
},
};

beforeEach(() => {
jest.clearAllMocks();
});
afterEach(() => {
jest.restoreAllMocks();
});

it("should pass the reason to discord as a X-Audit-Log-Reason header if provided", async () => {
jest
.spyOn(global, "fetch")
.mockImplementation((inp) => Promise.resolve(new JSONResponse(inp)));

await deleteGuildRole(guildEnv, roleId, "This is reason for this action");

expect(global.fetch).toHaveBeenCalledWith(
deleteGuildRoleUrl,
mockRequestInit
);
});

it("should return ROLE_REMOVED when response is ok", async () => {
const expectedResponse = new Response(null, {
status: 204,
});
jest.spyOn(global, "fetch").mockResolvedValue(expectedResponse);
const result = await deleteGuildRole(guildEnv, roleId);
expect(result).toEqual(response.ROLE_REMOVED);
expect(global.fetch).toHaveBeenCalledTimes(1);
});

it("should return INTERNAL_SERVER_ERROR when response is not ok", async () => {
const expectedErrorResponse = new Response(response.INTERNAL_SERVER_ERROR);
jest.spyOn(global, "fetch").mockRejectedValue(expectedErrorResponse);
const result = await deleteGuildRole(guildEnv, roleId);
expect(result).toEqual(response.INTERNAL_SERVER_ERROR);
expect(global.fetch).toHaveBeenCalledTimes(1);
});
});

0 comments on commit b70a6b6

Please sign in to comment.