From 0a450492c31446ff9bf260e924a50b3c504cc6fd Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Mon, 26 Jun 2023 20:01:29 +0530 Subject: [PATCH 01/28] adding tests for roles endpoint --- src/controllers/guildRoleHandler.ts | 13 ++ src/index.ts | 3 + src/typeDefinitions/role.types.d.ts | 4 + src/utils/guildRole.ts | 15 +++ tests/fixtures/fixture.ts | 17 +++ tests/unit/handlers/guildRoleHandler.test.ts | 119 +++++++++++++++++++ 6 files changed, 171 insertions(+) create mode 100644 src/typeDefinitions/role.types.d.ts create mode 100644 tests/unit/handlers/guildRoleHandler.test.ts diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index 84375a06..e3db57f0 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -39,3 +39,16 @@ export async function addGroupRoleHandler(request: IRequest, env: env) { return new JSONResponse(response.BAD_SIGNATURE); } } + +export async function getGuildRolesHandler(request: IRequest, env: env) { + // To be implemented + return new JSONResponse(response.NOT_FOUND); +} + +export async function getGuildRoleByRoleNameHandler( + request: IRequest, + env: env +) { + // To be implemented + return new JSONResponse(response.NOT_FOUND); +} diff --git a/src/index.ts b/src/index.ts index 43b1021e..66e06687 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import { verifyBot } from "./utils/verifyBot"; import { addGroupRoleHandler, createGuildRoleHandler, + getGuildRolesHandler, } from "./controllers/guildRoleHandler"; import { getMembersInServerHandler } from "./controllers/getMembersInServer"; import { changeNickname } from "./controllers/changeNickname"; @@ -28,6 +29,8 @@ router.put("/roles/create", createGuildRoleHandler); router.put("/roles/add", addGroupRoleHandler); +router.get("/roles", getGuildRolesHandler); + router.get("/discord-members", getMembersInServerHandler); router.get("/member/:id", getGuildMemberDetailsHandler); diff --git a/src/typeDefinitions/role.types.d.ts b/src/typeDefinitions/role.types.d.ts new file mode 100644 index 00000000..8861cde7 --- /dev/null +++ b/src/typeDefinitions/role.types.d.ts @@ -0,0 +1,4 @@ +export type GuildRole = { + id: string; + name: string; +}; diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index 63fb36da..2bee1901 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -6,6 +6,7 @@ import { guildRoleResponse, memberGroupRole, } from "../typeDefinitions/discordMessage.types"; +import { GuildRole } from "../typeDefinitions/role.types"; export async function createGuildRole( body: createNewRole, @@ -55,3 +56,17 @@ export async function addGroupRole(body: memberGroupRole, env: env) { return INTERNAL_SERVER_ERROR; } } + +export async function getGuildRoles(env: env): Promise> { + return []; +} + +export async function getGuildRoleByName( + roleName: string, + env: env +): Promise { + return { + id: "dummy-id", + name: "dummy-name", + }; +} diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index 43597fbd..5c38f365 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -1,3 +1,4 @@ +import { IRequest } from "itty-router"; import { createNewRole, discordMessageRequest, @@ -95,3 +96,19 @@ export const onlyRoleToBeTagged = { value: "1118201414078976192", }, }; + +export const generateDummyRequestObject = ({ + url, + method, + params, + query, + headers, // Object of key value pair +}: Partial): IRequest => { + return { + method: method ?? "GET", + url: url ?? "/roles", + params: params ?? {}, + query: query ?? {}, + headers: new Map(Object.entries(headers ?? {})), + }; +}; diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts new file mode 100644 index 00000000..bc355336 --- /dev/null +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -0,0 +1,119 @@ +import { + getGuildRoleByRoleNameHandler, + getGuildRolesHandler, +} from "../../../src/controllers/guildRoleHandler"; +import { GuildRole } from "../../../src/typeDefinitions/role.types"; +import JSONResponse from "../../../src/utils/JsonResponse"; +import { generateDummyRequestObject } from "../../fixtures/fixture"; +import * as responseConstants from "../../../src/constants/responses"; + +jest.mock("../../../src/utils/verifyAuthToken", () => ({ + verifyAuthToken: jest.fn().mockReturnValue(true), +})); + +describe.skip("get roles", () => { + it("should return a instance of JSONResponse", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles" }); + const response = await getGuildRolesHandler(mockRequest, {}); + expect(response).toBeInstanceOf(JSONResponse); + }); + + it("should return Bad Signature object if no auth headers provided", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles" }); + const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const jsonResponse: { error: string } = await response.json(); + expect(response.status).toBe(401); + expect(jsonResponse.error).toBe(responseConstants.BAD_SIGNATURE); + }); + + it("should return empty array if there is no roles in guild", async () => { + const mockRequest = generateDummyRequestObject({ + url: "/roles", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const jsonRespose: { roles: Array<{ id: string; name: string }> } = + await response.json(); + expect(response.status).toBe(200); + expect(Array.isArray(jsonRespose.roles)).toBeTruthy(); + expect(jsonRespose.roles.length).toBe(0); + }); + + it("should return array of id and name of roles present in guild", async () => { + const expectedResponse = [ + { + id: "role_id_one", + name: "role_name_one", + }, + { + id: "role_id_two", + name: "role_name_two", + }, + ]; + const mockRequest = generateDummyRequestObject({ + url: "/roles", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const jsonRespose: { roles: Array } = await response.json(); + expect(response.status).toBe(200); + expect(Array.isArray(jsonRespose.roles)).toBeTruthy(); + expect(jsonRespose.roles).toEqual(expectedResponse); + }); +}); + +describe.skip("get role by role name", () => { + it("should return a instance of JSONResponse", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles/everyone" }); + const response = await getGuildRoleByRoleNameHandler(mockRequest, {}); + expect(response).toBeInstanceOf(JSONResponse); + }); + + it("should return Bad Signature object if no auth headers provided", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles/everyone" }); + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + {} + ); + const jsonResponse: { error: string } = await response.json(); + expect(response.status).toBe(401); + expect(jsonResponse.error).toBe("๐Ÿšซ Bad Request Signature"); + }); + + it("should return not found object if there is no roles with given name in guild", async () => { + const mockRequest = generateDummyRequestObject({ + url: "/roles/everyone", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + {} + ); + const jsonRespose: { error: string } = await response.json(); + expect(response.status).toBe(404); + expect(jsonRespose.error).toBe(responseConstants.NOT_FOUND); + }); + + it("should return object of id and name corresponding to the role name recieved", async () => { + const expectedResponse = { + id: "role_id_one", + name: "everyone", + }; + + const mockRequest = generateDummyRequestObject({ + url: "/roles/everyone", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + {} + ); + const jsonRespose: { roles: Array } = await response.json(); + expect(response.status).toBe(200); + expect(jsonRespose).toEqual(expectedResponse); + }); +}); From a1903ffb936dee8b14d3a97d0a263618d4e0014a Mon Sep 17 00:00:00 2001 From: Ritik Jaiswal <57758447+RitikJaiswal75@users.noreply.github.com> Date: Tue, 27 Jun 2023 19:56:43 +0530 Subject: [PATCH 02/28] 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 --- src/constants/responses.ts | 2 ++ src/controllers/guildRoleHandler.ts | 31 ++++++++++++++++++++- src/index.ts | 3 +++ src/utils/guildRole.ts | 31 ++++++++++++++++++++- tests/unit/utils/guildRole.test.ts | 42 ++++++++++++++++++++++++++++- 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 8f3832bf..a116cdd6 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -25,3 +25,5 @@ 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"; diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index 84375a06..1650ac02 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -2,7 +2,11 @@ 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, +} from "../utils/guildRole"; import { createNewRole, memberGroupRole, @@ -39,3 +43,28 @@ 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", + }, + }); + } +} diff --git a/src/index.ts b/src/index.ts index 43b1021e..7cc1ab1a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import { verifyBot } from "./utils/verifyBot"; import { addGroupRoleHandler, createGuildRoleHandler, + removeGuildRoleHandler, } from "./controllers/guildRoleHandler"; import { getMembersInServerHandler } from "./controllers/getMembersInServer"; import { changeNickname } from "./controllers/changeNickname"; @@ -28,6 +29,8 @@ router.put("/roles/create", createGuildRoleHandler); router.put("/roles/add", addGroupRoleHandler); +router.delete("/roles", removeGuildRoleHandler); + router.get("/discord-members", getMembersInServerHandler); router.get("/member/:id", getGuildMemberDetailsHandler); diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index 63fb36da..5846433e 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -1,4 +1,8 @@ -import { INTERNAL_SERVER_ERROR, ROLE_ADDED } from "../constants/responses"; +import { + INTERNAL_SERVER_ERROR, + ROLE_ADDED, + ROLE_REMOVED, +} from "../constants/responses"; import { DISCORD_BASE_URL } from "../constants/urls"; import { env } from "../typeDefinitions/default.types"; import { @@ -55,3 +59,28 @@ 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; + } +} diff --git a/tests/unit/utils/guildRole.test.ts b/tests/unit/utils/guildRole.test.ts index 63458077..82510d7c 100644 --- a/tests/unit/utils/guildRole.test.ts +++ b/tests/unit/utils/guildRole.test.ts @@ -1,6 +1,10 @@ import JSONResponse from "../../../src/utils/JsonResponse"; import * as response from "../../../src/constants/responses"; -import { createGuildRole, addGroupRole } from "../../../src/utils/guildRole"; +import { + createGuildRole, + addGroupRole, + removeGuildRole, +} from "../../../src/utils/guildRole"; import { dummyAddRoleBody, dummyCreateBody, @@ -89,3 +93,39 @@ describe("addGroupRole", () => { ); }); }); + +describe("removeGuildRole", () => { + test("Should return success message on proper response", async () => { + const mockResponse = { + ok: true, + }; + jest + .spyOn(global, "fetch") + .mockImplementation(() => + Promise.resolve(new JSONResponse(mockResponse)) + ); + const result = await removeGuildRole(dummyAddRoleBody, guildEnv); + expect(global.fetch).toHaveBeenCalledWith( + `https://discord.com/api/v10/guilds/${guildEnv.DISCORD_GUILD_ID}/members/${dummyAddRoleBody.userid}/roles/${dummyAddRoleBody.roleid}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`, + }, + } + ); + expect(result).toEqual({ + message: response.ROLE_REMOVED, + userAffected: { + userid: dummyAddRoleBody.userid, + roleid: dummyAddRoleBody.roleid, + }, + }); + }); + test("Should return internal error response on api failure", async () => { + jest.spyOn(global, "fetch").mockRejectedValue("Oops some error"); + const result = await removeGuildRole(dummyAddRoleBody, guildEnv); + expect(result).toEqual(response.INTERNAL_SERVER_ERROR); + }); +}); From 89d30d0b1711a85da17c1654fc4e2290769a0479 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Mon, 26 Jun 2023 20:01:29 +0530 Subject: [PATCH 03/28] adding tests for roles endpoint --- src/controllers/guildRoleHandler.ts | 12 ++ src/index.ts | 2 + src/typeDefinitions/role.types.d.ts | 4 + src/utils/guildRole.ts | 16 +++ tests/fixtures/fixture.ts | 17 +++ tests/unit/handlers/guildRoleHandler.test.ts | 119 +++++++++++++++++++ 6 files changed, 170 insertions(+) create mode 100644 src/typeDefinitions/role.types.d.ts create mode 100644 tests/unit/handlers/guildRoleHandler.test.ts diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index 1650ac02..b1146f1a 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -68,3 +68,15 @@ export async function removeGuildRoleHandler(request: IRequest, env: env) { }); } } +export async function getGuildRolesHandler(request: IRequest, env: env) { + // To be implemented + return new JSONResponse(response.NOT_FOUND); +} + +export async function getGuildRoleByRoleNameHandler( + request: IRequest, + env: env +) { + // To be implemented + return new JSONResponse(response.NOT_FOUND); +} diff --git a/src/index.ts b/src/index.ts index 7cc1ab1a..3565b266 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,7 @@ import { addGroupRoleHandler, createGuildRoleHandler, removeGuildRoleHandler, + getGuildRolesHandler, } from "./controllers/guildRoleHandler"; import { getMembersInServerHandler } from "./controllers/getMembersInServer"; import { changeNickname } from "./controllers/changeNickname"; @@ -30,6 +31,7 @@ router.put("/roles/create", createGuildRoleHandler); router.put("/roles/add", addGroupRoleHandler); router.delete("/roles", removeGuildRoleHandler); +router.get("/roles", getGuildRolesHandler); router.get("/discord-members", getMembersInServerHandler); diff --git a/src/typeDefinitions/role.types.d.ts b/src/typeDefinitions/role.types.d.ts new file mode 100644 index 00000000..8861cde7 --- /dev/null +++ b/src/typeDefinitions/role.types.d.ts @@ -0,0 +1,4 @@ +export type GuildRole = { + id: string; + name: string; +}; diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index 5846433e..e5d8d4f7 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -10,6 +10,7 @@ import { guildRoleResponse, memberGroupRole, } from "../typeDefinitions/discordMessage.types"; +import { GuildRole } from "../typeDefinitions/role.types"; export async function createGuildRole( body: createNewRole, @@ -84,3 +85,18 @@ export async function removeGuildRole(details: memberGroupRole, env: env) { return INTERNAL_SERVER_ERROR; } } + + +export async function getGuildRoles(env: env): Promise> { + return []; +} + +export async function getGuildRoleByName( + roleName: string, + env: env +): Promise { + return { + id: "dummy-id", + name: "dummy-name", + }; +} diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index 43597fbd..5c38f365 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -1,3 +1,4 @@ +import { IRequest } from "itty-router"; import { createNewRole, discordMessageRequest, @@ -95,3 +96,19 @@ export const onlyRoleToBeTagged = { value: "1118201414078976192", }, }; + +export const generateDummyRequestObject = ({ + url, + method, + params, + query, + headers, // Object of key value pair +}: Partial): IRequest => { + return { + method: method ?? "GET", + url: url ?? "/roles", + params: params ?? {}, + query: query ?? {}, + headers: new Map(Object.entries(headers ?? {})), + }; +}; diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts new file mode 100644 index 00000000..bc355336 --- /dev/null +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -0,0 +1,119 @@ +import { + getGuildRoleByRoleNameHandler, + getGuildRolesHandler, +} from "../../../src/controllers/guildRoleHandler"; +import { GuildRole } from "../../../src/typeDefinitions/role.types"; +import JSONResponse from "../../../src/utils/JsonResponse"; +import { generateDummyRequestObject } from "../../fixtures/fixture"; +import * as responseConstants from "../../../src/constants/responses"; + +jest.mock("../../../src/utils/verifyAuthToken", () => ({ + verifyAuthToken: jest.fn().mockReturnValue(true), +})); + +describe.skip("get roles", () => { + it("should return a instance of JSONResponse", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles" }); + const response = await getGuildRolesHandler(mockRequest, {}); + expect(response).toBeInstanceOf(JSONResponse); + }); + + it("should return Bad Signature object if no auth headers provided", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles" }); + const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const jsonResponse: { error: string } = await response.json(); + expect(response.status).toBe(401); + expect(jsonResponse.error).toBe(responseConstants.BAD_SIGNATURE); + }); + + it("should return empty array if there is no roles in guild", async () => { + const mockRequest = generateDummyRequestObject({ + url: "/roles", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const jsonRespose: { roles: Array<{ id: string; name: string }> } = + await response.json(); + expect(response.status).toBe(200); + expect(Array.isArray(jsonRespose.roles)).toBeTruthy(); + expect(jsonRespose.roles.length).toBe(0); + }); + + it("should return array of id and name of roles present in guild", async () => { + const expectedResponse = [ + { + id: "role_id_one", + name: "role_name_one", + }, + { + id: "role_id_two", + name: "role_name_two", + }, + ]; + const mockRequest = generateDummyRequestObject({ + url: "/roles", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const jsonRespose: { roles: Array } = await response.json(); + expect(response.status).toBe(200); + expect(Array.isArray(jsonRespose.roles)).toBeTruthy(); + expect(jsonRespose.roles).toEqual(expectedResponse); + }); +}); + +describe.skip("get role by role name", () => { + it("should return a instance of JSONResponse", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles/everyone" }); + const response = await getGuildRoleByRoleNameHandler(mockRequest, {}); + expect(response).toBeInstanceOf(JSONResponse); + }); + + it("should return Bad Signature object if no auth headers provided", async () => { + const mockRequest = generateDummyRequestObject({ url: "/roles/everyone" }); + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + {} + ); + const jsonResponse: { error: string } = await response.json(); + expect(response.status).toBe(401); + expect(jsonResponse.error).toBe("๐Ÿšซ Bad Request Signature"); + }); + + it("should return not found object if there is no roles with given name in guild", async () => { + const mockRequest = generateDummyRequestObject({ + url: "/roles/everyone", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + {} + ); + const jsonRespose: { error: string } = await response.json(); + expect(response.status).toBe(404); + expect(jsonRespose.error).toBe(responseConstants.NOT_FOUND); + }); + + it("should return object of id and name corresponding to the role name recieved", async () => { + const expectedResponse = { + id: "role_id_one", + name: "everyone", + }; + + const mockRequest = generateDummyRequestObject({ + url: "/roles/everyone", + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + {} + ); + const jsonRespose: { roles: Array } = await response.json(); + expect(response.status).toBe(200); + expect(jsonRespose).toEqual(expectedResponse); + }); +}); From 5730062f852a3e3a6d7301c73ad41bbdd215dc41 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Thu, 29 Jun 2023 13:40:21 +0530 Subject: [PATCH 04/28] [Feature] Add APIs for fetching role information --- src/constants/responses.ts | 7 + src/controllers/guildRoleHandler.ts | 48 ++++- src/index.ts | 4 + src/typeDefinitions/role.types.d.ts | 16 ++ src/utils/guildRole.ts | 33 +++- tests/fixtures/fixture.ts | 27 +++ tests/unit/handlers/guildRoleHandler.test.ts | 191 ++++++++++++++++--- tests/unit/utils/guildRole.test.ts | 72 +++++++ 8 files changed, 359 insertions(+), 39 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index a116cdd6..db150ecd 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -27,3 +27,10 @@ export const ROLE_ADDED = "Role added successfully"; export const NAME_CHANGED = "User nickname changed successfully"; export const ROLE_REMOVED = "Role Removed successfully"; + +export const ROLE_FETCH_FAILED_MESSAGE = + "Oops! We are experiencing an issue fetching roles."; + +export const ROLE_FETCH_FAILED_ERROR = { + error: ROLE_FETCH_FAILED_MESSAGE, +}; diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index b1146f1a..af2b4ddf 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -6,6 +6,8 @@ import { addGroupRole, createGuildRole, removeGuildRole, + getGuildRoleByName, + getGuildRoles, } from "../utils/guildRole"; import { createNewRole, @@ -69,14 +71,52 @@ export async function removeGuildRoleHandler(request: IRequest, env: env) { } } export async function getGuildRolesHandler(request: IRequest, env: env) { - // To be implemented - return new JSONResponse(response.NOT_FOUND); + 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) { + if (err.message === response.ROLE_FETCH_FAILED_MESSAGE) { + return new JSONResponse(response.ROLE_FETCH_FAILED_ERROR, { + status: 500, + }); + } + return new JSONResponse(response.INTERNAL_SERVER_ERROR, { status: 500 }); + } } export async function getGuildRoleByRoleNameHandler( request: IRequest, env: env ) { - // To be implemented - return new JSONResponse(response.NOT_FOUND); + 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.NOT_FOUND, { status: 404 }); + } + try { + await verifyAuthToken(authHeader, env); + const role = await getGuildRoleByName(roleName, env); + if (!role) { + return new JSONResponse(response.NOT_FOUND, { status: 404 }); + } + return new JSONResponse(role); + } catch (err: any) { + if (err.message === response.ROLE_FETCH_FAILED_MESSAGE) { + return new JSONResponse(response.ROLE_FETCH_FAILED_ERROR, { + status: 500, + }); + } + return new JSONResponse(response.INTERNAL_SERVER_ERROR, { status: 500 }); + } } diff --git a/src/index.ts b/src/index.ts index 3565b266..5d6a7ca9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,7 @@ import { addGroupRoleHandler, createGuildRoleHandler, removeGuildRoleHandler, + getGuildRoleByRoleNameHandler, getGuildRolesHandler, } from "./controllers/guildRoleHandler"; import { getMembersInServerHandler } from "./controllers/getMembersInServer"; @@ -31,8 +32,11 @@ 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); diff --git a/src/typeDefinitions/role.types.d.ts b/src/typeDefinitions/role.types.d.ts index 8861cde7..c7309a55 100644 --- a/src/typeDefinitions/role.types.d.ts +++ b/src/typeDefinitions/role.types.d.ts @@ -2,3 +2,19 @@ export type GuildRole = { id: string; name: string; }; + +export type GuildDetails = { + // This type defines the partial guild details response that we get from discord + id: string; + name: string; + roles: Array<{ + id: string; + name: string; + permissions: string; + position: number; + color: number; + hoist: boolean; + managed: boolean; + mentionable: boolean; + }>; +}; diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index e5d8d4f7..cfe0fcb0 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -2,6 +2,7 @@ import { INTERNAL_SERVER_ERROR, ROLE_ADDED, ROLE_REMOVED, + ROLE_FETCH_FAILED_MESSAGE, } from "../constants/responses"; import { DISCORD_BASE_URL } from "../constants/urls"; import { env } from "../typeDefinitions/default.types"; @@ -10,7 +11,7 @@ import { guildRoleResponse, memberGroupRole, } from "../typeDefinitions/discordMessage.types"; -import { GuildRole } from "../typeDefinitions/role.types"; +import { GuildDetails, GuildRole } from "../typeDefinitions/role.types"; export async function createGuildRole( body: createNewRole, @@ -86,17 +87,33 @@ export async function removeGuildRole(details: memberGroupRole, env: env) { } } - export async function getGuildRoles(env: env): Promise> { - return []; + const guildDetailsUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}`; + + const response = await fetch(guildDetailsUrl, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bot ${env.DISCORD_TOKEN}`, + }, + }); + + if (!response.ok) { + throw new Error(ROLE_FETCH_FAILED_MESSAGE); + } + + const guildDetails: GuildDetails = await response.json(); + + return guildDetails.roles.map((role) => ({ + id: role.id, + name: role.name, + })); } export async function getGuildRoleByName( roleName: string, env: env -): Promise { - return { - id: "dummy-id", - name: "dummy-name", - }; +): Promise { + const roles = await getGuildRoles(env); + return roles.find((role) => role.name === roleName); } diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index 5c38f365..785239a7 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -112,3 +112,30 @@ export const generateDummyRequestObject = ({ headers: new Map(Object.entries(headers ?? {})), }; }; + +export const guildDetailsMock = { + id: "123434232324242424", + name: "test server", + roles: [ + { + 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, + }, + ], +}; diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts index bc355336..a7537712 100644 --- a/tests/unit/handlers/guildRoleHandler.test.ts +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -4,40 +4,86 @@ import { } from "../../../src/controllers/guildRoleHandler"; import { GuildRole } from "../../../src/typeDefinitions/role.types"; import JSONResponse from "../../../src/utils/JsonResponse"; -import { generateDummyRequestObject } from "../../fixtures/fixture"; +import { generateDummyRequestObject, guildEnv } from "../../fixtures/fixture"; import * as responseConstants from "../../../src/constants/responses"; +import * as guildRoleUtils from "../../../src/utils/guildRole"; jest.mock("../../../src/utils/verifyAuthToken", () => ({ verifyAuthToken: jest.fn().mockReturnValue(true), })); -describe.skip("get roles", () => { +const getGuildRolesSpy = jest.spyOn(guildRoleUtils, "getGuildRoles"); +const getGuildRoleByNameSpy = jest.spyOn(guildRoleUtils, "getGuildRoleByName"); + +describe("get roles", () => { + beforeEach(() => { + jest.resetAllMocks(); + }); it("should return a instance of JSONResponse", async () => { const mockRequest = generateDummyRequestObject({ url: "/roles" }); - const response = await getGuildRolesHandler(mockRequest, {}); + const response = await getGuildRolesHandler(mockRequest, guildEnv); expect(response).toBeInstanceOf(JSONResponse); }); it("should return Bad Signature object if no auth headers provided", async () => { const mockRequest = generateDummyRequestObject({ url: "/roles" }); - const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); + const response: JSONResponse = await getGuildRolesHandler( + mockRequest, + guildEnv + ); const jsonResponse: { error: string } = await response.json(); expect(response.status).toBe(401); - expect(jsonResponse.error).toBe(responseConstants.BAD_SIGNATURE); + expect(jsonResponse).toEqual(responseConstants.BAD_SIGNATURE); + }); + + it("should return role fetch failed error response if it fails to fetch roles", async () => { + getGuildRolesSpy.mockRejectedValueOnce({ + message: responseConstants.ROLE_FETCH_FAILED_MESSAGE, + }); + const mockRequest = generateDummyRequestObject({ + url: "/roles", + headers: { Authorization: "Bearer testtoken" }, + }); + const response: JSONResponse = await getGuildRolesHandler( + mockRequest, + guildEnv + ); + const jsonResponse = await response.json(); + expect(response.status).toBe(500); + expect(jsonResponse).toEqual(responseConstants.ROLE_FETCH_FAILED_ERROR); + }); + + it("should return internal server error response if it fails for any other reason", async () => { + getGuildRolesSpy.mockRejectedValueOnce({}); + const mockRequest = generateDummyRequestObject({ + url: "/roles", + headers: { Authorization: "Bearer testtoken" }, + }); + const response: JSONResponse = await getGuildRolesHandler( + mockRequest, + guildEnv + ); + const jsonResponse = await response.json(); + expect(response.status).toBe(500); + expect(jsonResponse).toBe(responseConstants.INTERNAL_SERVER_ERROR); }); it("should return empty array if there is no roles in guild", async () => { + getGuildRolesSpy.mockResolvedValue([]); const mockRequest = generateDummyRequestObject({ url: "/roles", headers: { Authorization: "Bearer testtoken" }, }); - const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); - const jsonRespose: { roles: Array<{ id: string; name: string }> } = + const response: JSONResponse = await getGuildRolesHandler( + mockRequest, + guildEnv + ); + const jsonResponse: { roles: Array<{ id: string; name: string }> } = await response.json(); expect(response.status).toBe(200); - expect(Array.isArray(jsonRespose.roles)).toBeTruthy(); - expect(jsonRespose.roles.length).toBe(0); + expect(Array.isArray(jsonResponse.roles)).toBeTruthy(); + expect(jsonResponse.roles.length).toBe(0); }); it("should return array of id and name of roles present in guild", async () => { @@ -51,50 +97,136 @@ describe.skip("get roles", () => { name: "role_name_two", }, ]; + getGuildRolesSpy.mockResolvedValueOnce(expectedResponse); + const mockRequest = generateDummyRequestObject({ url: "/roles", headers: { Authorization: "Bearer testtoken" }, }); - const response: JSONResponse = await getGuildRolesHandler(mockRequest, {}); - const jsonRespose: { roles: Array } = await response.json(); + const response: JSONResponse = await getGuildRolesHandler( + mockRequest, + guildEnv + ); + const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(200); - expect(Array.isArray(jsonRespose.roles)).toBeTruthy(); - expect(jsonRespose.roles).toEqual(expectedResponse); + expect(Array.isArray(jsonResponse.roles)).toBeTruthy(); + expect(jsonResponse.roles).toEqual(expectedResponse); }); }); -describe.skip("get role by role name", () => { +describe("get role by role name", () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + it("should return a instance of JSONResponse", async () => { - const mockRequest = generateDummyRequestObject({ url: "/roles/everyone" }); - const response = await getGuildRoleByRoleNameHandler(mockRequest, {}); + getGuildRoleByNameSpy.mockResolvedValueOnce(undefined); + const mockRequest = generateDummyRequestObject({ + url: "/roles", + params: { + roleName: "everyone", + }, + headers: { Authorization: "Bearer testtoken" }, + }); + const response = await getGuildRoleByRoleNameHandler(mockRequest, guildEnv); expect(response).toBeInstanceOf(JSONResponse); }); it("should return Bad Signature object if no auth headers provided", async () => { - const mockRequest = generateDummyRequestObject({ url: "/roles/everyone" }); + getGuildRoleByNameSpy.mockResolvedValueOnce(undefined); + const mockRequest = generateDummyRequestObject({ + url: "/roles", + params: { + roleName: "everyone", + }, + }); const response: JSONResponse = await getGuildRoleByRoleNameHandler( mockRequest, - {} + guildEnv ); const jsonResponse: { error: string } = await response.json(); expect(response.status).toBe(401); - expect(jsonResponse.error).toBe("๐Ÿšซ Bad Request Signature"); + expect(jsonResponse).toEqual(responseConstants.BAD_SIGNATURE); + }); + + it("should return Not Found error if no roleName is not provided", async () => { + getGuildRoleByNameSpy.mockResolvedValueOnce(undefined); + const mockRequest = generateDummyRequestObject({ + url: "/roles", + params: {}, + + headers: { Authorization: "Bearer testtoken" }, + }); + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + guildEnv + ); + const jsonResponse: { error: string } = await response.json(); + expect(response.status).toBe(404); + expect(jsonResponse).toEqual(responseConstants.NOT_FOUND); }); it("should return not found object if there is no roles with given name in guild", async () => { + getGuildRoleByNameSpy.mockResolvedValueOnce(undefined); + const mockRequest = generateDummyRequestObject({ - url: "/roles/everyone", + url: "/roles", + params: { + roleName: "everyone", + }, headers: { Authorization: "Bearer testtoken" }, }); const response: JSONResponse = await getGuildRoleByRoleNameHandler( mockRequest, - {} + guildEnv ); - const jsonRespose: { error: string } = await response.json(); + const jsonResponse: { error: string } = await response.json(); expect(response.status).toBe(404); - expect(jsonRespose.error).toBe(responseConstants.NOT_FOUND); + expect(jsonResponse).toEqual(responseConstants.NOT_FOUND); + }); + + it("should return role fetch failed error if there was an error while fetching roles", async () => { + getGuildRoleByNameSpy.mockRejectedValueOnce({ + message: responseConstants.ROLE_FETCH_FAILED_MESSAGE, + }); + + const mockRequest = generateDummyRequestObject({ + url: "/roles", + params: { + roleName: "everyone", + }, + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + guildEnv + ); + const jsonResponse: { roles: Array } = await response.json(); + expect(response.status).toBe(500); + expect(jsonResponse).toEqual(responseConstants.ROLE_FETCH_FAILED_ERROR); + }); + + it("should return internal server error if there was any other error", async () => { + getGuildRoleByNameSpy.mockRejectedValueOnce({}); + + const mockRequest = generateDummyRequestObject({ + url: "/roles", + params: { + roleName: "everyone", + }, + headers: { Authorization: "Bearer testtoken" }, + }); + + const response: JSONResponse = await getGuildRoleByRoleNameHandler( + mockRequest, + guildEnv + ); + const jsonResponse: { roles: Array } = await response.json(); + expect(response.status).toBe(500); + expect(jsonResponse).toBe(responseConstants.INTERNAL_SERVER_ERROR); }); it("should return object of id and name corresponding to the role name recieved", async () => { @@ -103,17 +235,22 @@ describe.skip("get role by role name", () => { name: "everyone", }; + getGuildRoleByNameSpy.mockResolvedValueOnce(expectedResponse); + const mockRequest = generateDummyRequestObject({ - url: "/roles/everyone", + url: "/roles", + params: { + roleName: "everyone", + }, headers: { Authorization: "Bearer testtoken" }, }); const response: JSONResponse = await getGuildRoleByRoleNameHandler( mockRequest, - {} + guildEnv ); - const jsonRespose: { roles: Array } = await response.json(); + const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(200); - expect(jsonRespose).toEqual(expectedResponse); + expect(jsonResponse).toEqual(expectedResponse); }); }); diff --git a/tests/unit/utils/guildRole.test.ts b/tests/unit/utils/guildRole.test.ts index 82510d7c..8b234f67 100644 --- a/tests/unit/utils/guildRole.test.ts +++ b/tests/unit/utils/guildRole.test.ts @@ -4,10 +4,13 @@ import { createGuildRole, addGroupRole, removeGuildRole, + getGuildRoles, + getGuildRoleByName, } from "../../../src/utils/guildRole"; import { dummyAddRoleBody, dummyCreateBody, + guildDetailsMock, guildEnv, } from "../../fixtures/fixture"; @@ -129,3 +132,72 @@ describe("removeGuildRole", () => { expect(result).toEqual(response.INTERNAL_SERVER_ERROR); }); }); +describe("getGuildRoles", () => { + it("should throw role fetch failed message if status is not ok", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.resolve(new JSONResponse({}, { status: 500 })) + ); + await expect(getGuildRoles(guildEnv)).rejects.toThrow( + response.ROLE_FETCH_FAILED_MESSAGE + ); + }); + + it("should return array of objects containing role_id and role_name", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.resolve(new JSONResponse(guildDetailsMock)) + ); + const roles = await getGuildRoles(guildEnv); + const expectedRoles = [ + { + id: "1234567889", + name: "@everyone", + }, + { + id: "12344567", + name: "bot one", + }, + ]; + expect(roles).toEqual(expectedRoles); + }); +}); + +describe("getGuildRolesByName", () => { + it("should throw role fetch failed message if status is not ok", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.resolve(new JSONResponse({}, { status: 500 })) + ); + await expect(getGuildRoleByName("@everyone", guildEnv)).rejects.toThrow( + response.ROLE_FETCH_FAILED_MESSAGE + ); + }); + + it("should return array of objects containing role_id and role_name", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.resolve(new JSONResponse(guildDetailsMock)) + ); + const role = await getGuildRoleByName("@everyone", guildEnv); + const expectedRoles = { + id: "1234567889", + name: "@everyone", + }; + + expect(role).toEqual(expectedRoles); + }); + it("should return undefined when role name does not match any entry", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.resolve(new JSONResponse(guildDetailsMock)) + ); + const role = await getGuildRoleByName("everyone", guildEnv); + expect(role).toBeUndefined(); + }); +}); From 1a07a2361113f12745bc465b646a485f897aed75 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Sat, 1 Jul 2023 00:57:24 +0530 Subject: [PATCH 05/28] removing unnecessary constants --- src/constants/responses.ts | 6 +----- src/controllers/guildRoleHandler.ts | 22 +++++++++++++------- src/utils/guildRole.ts | 4 ++-- tests/unit/handlers/guildRoleHandler.test.ts | 12 +++++++---- tests/unit/utils/guildRole.test.ts | 4 ++-- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index db150ecd..c8cff872 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -28,9 +28,5 @@ export const NAME_CHANGED = "User nickname changed successfully"; export const ROLE_REMOVED = "Role Removed successfully"; -export const ROLE_FETCH_FAILED_MESSAGE = +export const ROLE_FETCH_FAILED = "Oops! We are experiencing an issue fetching roles."; - -export const ROLE_FETCH_FAILED_ERROR = { - error: ROLE_FETCH_FAILED_MESSAGE, -}; diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index af2b4ddf..bfc90fec 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -81,10 +81,13 @@ export async function getGuildRolesHandler(request: IRequest, env: env) { const roles = await getGuildRoles(env); return new JSONResponse({ roles }); } catch (err: any) { - if (err.message === response.ROLE_FETCH_FAILED_MESSAGE) { - return new JSONResponse(response.ROLE_FETCH_FAILED_ERROR, { - status: 500, - }); + if (err.message === response.ROLE_FETCH_FAILED) { + return new JSONResponse( + { error: response.ROLE_FETCH_FAILED }, + { + status: 500, + } + ); } return new JSONResponse(response.INTERNAL_SERVER_ERROR, { status: 500 }); } @@ -112,10 +115,13 @@ export async function getGuildRoleByRoleNameHandler( } return new JSONResponse(role); } catch (err: any) { - if (err.message === response.ROLE_FETCH_FAILED_MESSAGE) { - return new JSONResponse(response.ROLE_FETCH_FAILED_ERROR, { - status: 500, - }); + if (err.message === response.ROLE_FETCH_FAILED) { + return new JSONResponse( + { error: response.ROLE_FETCH_FAILED }, + { + status: 500, + } + ); } return new JSONResponse(response.INTERNAL_SERVER_ERROR, { status: 500 }); } diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index cfe0fcb0..79c4a52e 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -2,7 +2,7 @@ import { INTERNAL_SERVER_ERROR, ROLE_ADDED, ROLE_REMOVED, - ROLE_FETCH_FAILED_MESSAGE, + ROLE_FETCH_FAILED, } from "../constants/responses"; import { DISCORD_BASE_URL } from "../constants/urls"; import { env } from "../typeDefinitions/default.types"; @@ -99,7 +99,7 @@ export async function getGuildRoles(env: env): Promise> { }); if (!response.ok) { - throw new Error(ROLE_FETCH_FAILED_MESSAGE); + throw new Error(ROLE_FETCH_FAILED); } const guildDetails: GuildDetails = await response.json(); diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts index a7537712..9efaa413 100644 --- a/tests/unit/handlers/guildRoleHandler.test.ts +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -38,7 +38,7 @@ describe("get roles", () => { it("should return role fetch failed error response if it fails to fetch roles", async () => { getGuildRolesSpy.mockRejectedValueOnce({ - message: responseConstants.ROLE_FETCH_FAILED_MESSAGE, + message: responseConstants.ROLE_FETCH_FAILED, }); const mockRequest = generateDummyRequestObject({ url: "/roles", @@ -50,7 +50,9 @@ describe("get roles", () => { ); const jsonResponse = await response.json(); expect(response.status).toBe(500); - expect(jsonResponse).toEqual(responseConstants.ROLE_FETCH_FAILED_ERROR); + expect(jsonResponse).toEqual({ + error: responseConstants.ROLE_FETCH_FAILED, + }); }); it("should return internal server error response if it fails for any other reason", async () => { @@ -189,7 +191,7 @@ describe("get role by role name", () => { it("should return role fetch failed error if there was an error while fetching roles", async () => { getGuildRoleByNameSpy.mockRejectedValueOnce({ - message: responseConstants.ROLE_FETCH_FAILED_MESSAGE, + message: responseConstants.ROLE_FETCH_FAILED, }); const mockRequest = generateDummyRequestObject({ @@ -206,7 +208,9 @@ describe("get role by role name", () => { ); const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(500); - expect(jsonResponse).toEqual(responseConstants.ROLE_FETCH_FAILED_ERROR); + expect(jsonResponse).toEqual({ + error: responseConstants.ROLE_FETCH_FAILED, + }); }); it("should return internal server error if there was any other error", async () => { diff --git a/tests/unit/utils/guildRole.test.ts b/tests/unit/utils/guildRole.test.ts index 8b234f67..8af46d99 100644 --- a/tests/unit/utils/guildRole.test.ts +++ b/tests/unit/utils/guildRole.test.ts @@ -140,7 +140,7 @@ describe("getGuildRoles", () => { Promise.resolve(new JSONResponse({}, { status: 500 })) ); await expect(getGuildRoles(guildEnv)).rejects.toThrow( - response.ROLE_FETCH_FAILED_MESSAGE + response.ROLE_FETCH_FAILED ); }); @@ -173,7 +173,7 @@ describe("getGuildRolesByName", () => { Promise.resolve(new JSONResponse({}, { status: 500 })) ); await expect(getGuildRoleByName("@everyone", guildEnv)).rejects.toThrow( - response.ROLE_FETCH_FAILED_MESSAGE + response.ROLE_FETCH_FAILED ); }); From aaab3272fac0b960d3909814c95b5b0f876f25c2 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Sat, 1 Jul 2023 01:22:09 +0530 Subject: [PATCH 06/28] Adding headers in response objects --- src/controllers/guildRoleHandler.ts | 33 ++++++++++++++++++-- tests/unit/handlers/guildRoleHandler.test.ts | 8 +++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index bfc90fec..5d3f7aa1 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -86,10 +86,21 @@ export async function getGuildRolesHandler(request: IRequest, env: env) { { error: response.ROLE_FETCH_FAILED }, { status: 500, + headers: { + "content-type": "application/json;charset=UTF-8", + }, } ); } - return new JSONResponse(response.INTERNAL_SERVER_ERROR, { status: 500 }); + return new JSONResponse( + { error: response.INTERNAL_SERVER_ERROR }, + { + status: 500, + headers: { + "content-type": "application/json;charset=UTF-8", + }, + } + ); } } @@ -111,7 +122,12 @@ export async function getGuildRoleByRoleNameHandler( await verifyAuthToken(authHeader, env); const role = await getGuildRoleByName(roleName, env); if (!role) { - return new JSONResponse(response.NOT_FOUND, { status: 404 }); + return new JSONResponse(response.NOT_FOUND, { + status: 404, + headers: { + "content-type": "application/json;charset=UTF-8", + }, + }); } return new JSONResponse(role); } catch (err: any) { @@ -120,9 +136,20 @@ export async function getGuildRoleByRoleNameHandler( { error: response.ROLE_FETCH_FAILED }, { status: 500, + headers: { + "content-type": "application/json;charset=UTF-8", + }, } ); } - return new JSONResponse(response.INTERNAL_SERVER_ERROR, { status: 500 }); + return new JSONResponse( + { error: response.INTERNAL_SERVER_ERROR }, + { + status: 500, + headers: { + "content-type": "application/json;charset=UTF-8", + }, + } + ); } } diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts index 9efaa413..61e9ab89 100644 --- a/tests/unit/handlers/guildRoleHandler.test.ts +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -67,7 +67,9 @@ describe("get roles", () => { ); const jsonResponse = await response.json(); expect(response.status).toBe(500); - expect(jsonResponse).toBe(responseConstants.INTERNAL_SERVER_ERROR); + expect(jsonResponse).toEqual({ + error: responseConstants.INTERNAL_SERVER_ERROR, + }); }); it("should return empty array if there is no roles in guild", async () => { @@ -230,7 +232,9 @@ describe("get role by role name", () => { ); const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(500); - expect(jsonResponse).toBe(responseConstants.INTERNAL_SERVER_ERROR); + expect(jsonResponse).toEqual({ + error: responseConstants.INTERNAL_SERVER_ERROR, + }); }); it("should return object of id and name corresponding to the role name recieved", async () => { From 86c08cee380f0a2b3b1bbcda65ef25ef3a340a9a Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Sat, 1 Jul 2023 13:13:11 +0530 Subject: [PATCH 07/28] Adding extra try blocks in utils to handle errors --- src/controllers/guildRoleHandler.ts | 3 +++ src/utils/guildRole.ts | 41 ++++++++++++++++------------- tests/unit/utils/guildRole.test.ts | 13 +++++---- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index 5d3f7aa1..2c200cd3 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -79,6 +79,9 @@ export async function getGuildRolesHandler(request: IRequest, env: env) { try { await verifyAuthToken(authHeader, env); const roles = await getGuildRoles(env); + if (!roles) { + throw new Error(response.ROLE_FETCH_FAILED); + } return new JSONResponse({ roles }); } catch (err: any) { if (err.message === response.ROLE_FETCH_FAILED) { diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index 79c4a52e..2d3170e1 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -2,7 +2,6 @@ import { INTERNAL_SERVER_ERROR, ROLE_ADDED, ROLE_REMOVED, - ROLE_FETCH_FAILED, } from "../constants/responses"; import { DISCORD_BASE_URL } from "../constants/urls"; import { env } from "../typeDefinitions/default.types"; @@ -87,27 +86,33 @@ export async function removeGuildRole(details: memberGroupRole, env: env) { } } -export async function getGuildRoles(env: env): Promise> { +export async function getGuildRoles( + env: env +): Promise | undefined> { const guildDetailsUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}`; - const response = await fetch(guildDetailsUrl, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bot ${env.DISCORD_TOKEN}`, - }, - }); + try { + const response = await fetch(guildDetailsUrl, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bot ${env.DISCORD_TOKEN}`, + }, + }); - if (!response.ok) { - throw new Error(ROLE_FETCH_FAILED); - } + if (!response.ok) { + return undefined; + } - const guildDetails: GuildDetails = await response.json(); + const guildDetails: GuildDetails = await response.json(); - return guildDetails.roles.map((role) => ({ - id: role.id, - name: role.name, - })); + return guildDetails.roles.map((role) => ({ + id: role.id, + name: role.name, + })); + } catch (err) { + return undefined; + } } export async function getGuildRoleByName( @@ -115,5 +120,5 @@ export async function getGuildRoleByName( env: env ): Promise { const roles = await getGuildRoles(env); - return roles.find((role) => role.name === roleName); + return roles?.find((role) => role.name === roleName); } diff --git a/tests/unit/utils/guildRole.test.ts b/tests/unit/utils/guildRole.test.ts index 8af46d99..29f712e7 100644 --- a/tests/unit/utils/guildRole.test.ts +++ b/tests/unit/utils/guildRole.test.ts @@ -133,15 +133,15 @@ describe("removeGuildRole", () => { }); }); describe("getGuildRoles", () => { - it("should throw role fetch failed message if status is not ok", async () => { + it("should return undefined if status is not ok", async () => { jest .spyOn(global, "fetch") .mockImplementationOnce(async () => Promise.resolve(new JSONResponse({}, { status: 500 })) ); - await expect(getGuildRoles(guildEnv)).rejects.toThrow( - response.ROLE_FETCH_FAILED - ); + + const response = await getGuildRoles(guildEnv); + expect(response).toBeUndefined(); }); it("should return array of objects containing role_id and role_name", async () => { @@ -172,9 +172,8 @@ describe("getGuildRolesByName", () => { .mockImplementationOnce(async () => Promise.resolve(new JSONResponse({}, { status: 500 })) ); - await expect(getGuildRoleByName("@everyone", guildEnv)).rejects.toThrow( - response.ROLE_FETCH_FAILED - ); + const response = await getGuildRoleByName("@everyone", guildEnv); + expect(response).toBeUndefined(); }); it("should return array of objects containing role_id and role_name", async () => { From 70107608f747e15600d0f92c6f15e34974e269d7 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Tue, 4 Jul 2023 19:23:50 +0530 Subject: [PATCH 08/28] Throwing errors when something goes wrong --- src/controllers/guildRoleHandler.ts | 39 +++++++--------------- src/utils/guildRole.ts | 9 +++--- tests/unit/utils/guildRole.test.ts | 50 ++++++++++++++++++++--------- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index 2c200cd3..b7d85cc4 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -79,24 +79,16 @@ export async function getGuildRolesHandler(request: IRequest, env: env) { try { await verifyAuthToken(authHeader, env); const roles = await getGuildRoles(env); - if (!roles) { - throw new Error(response.ROLE_FETCH_FAILED); - } return new JSONResponse({ roles }); } catch (err: any) { - if (err.message === response.ROLE_FETCH_FAILED) { - return new JSONResponse( - { error: response.ROLE_FETCH_FAILED }, - { - status: 500, - headers: { - "content-type": "application/json;charset=UTF-8", - }, - } - ); - } + const error = + err?.message === response.ROLE_FETCH_FAILED + ? response.ROLE_FETCH_FAILED + : response.INTERNAL_SERVER_ERROR; return new JSONResponse( - { error: response.INTERNAL_SERVER_ERROR }, + { + error, + }, { status: 500, headers: { @@ -134,19 +126,12 @@ export async function getGuildRoleByRoleNameHandler( } return new JSONResponse(role); } catch (err: any) { - if (err.message === response.ROLE_FETCH_FAILED) { - return new JSONResponse( - { error: response.ROLE_FETCH_FAILED }, - { - status: 500, - headers: { - "content-type": "application/json;charset=UTF-8", - }, - } - ); - } + const error = + err?.message === response.ROLE_FETCH_FAILED + ? response.ROLE_FETCH_FAILED + : response.INTERNAL_SERVER_ERROR; return new JSONResponse( - { error: response.INTERNAL_SERVER_ERROR }, + { error }, { status: 500, headers: { diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index 2d3170e1..53270c7c 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -1,6 +1,7 @@ import { INTERNAL_SERVER_ERROR, ROLE_ADDED, + ROLE_FETCH_FAILED, ROLE_REMOVED, } from "../constants/responses"; import { DISCORD_BASE_URL } from "../constants/urls"; @@ -86,9 +87,7 @@ export async function removeGuildRole(details: memberGroupRole, env: env) { } } -export async function getGuildRoles( - env: env -): Promise | undefined> { +export async function getGuildRoles(env: env): Promise> { const guildDetailsUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}`; try { @@ -101,7 +100,7 @@ export async function getGuildRoles( }); if (!response.ok) { - return undefined; + throw new Error(ROLE_FETCH_FAILED); } const guildDetails: GuildDetails = await response.json(); @@ -111,7 +110,7 @@ export async function getGuildRoles( name: role.name, })); } catch (err) { - return undefined; + throw new Error(ROLE_FETCH_FAILED); } } diff --git a/tests/unit/utils/guildRole.test.ts b/tests/unit/utils/guildRole.test.ts index 29f712e7..c4624d2a 100644 --- a/tests/unit/utils/guildRole.test.ts +++ b/tests/unit/utils/guildRole.test.ts @@ -132,16 +132,30 @@ describe("removeGuildRole", () => { expect(result).toEqual(response.INTERNAL_SERVER_ERROR); }); }); + describe("getGuildRoles", () => { - it("should return undefined if status is not ok", async () => { + it("should throw role fetch failed error if status is not ok", async () => { jest .spyOn(global, "fetch") .mockImplementationOnce(async () => Promise.resolve(new JSONResponse({}, { status: 500 })) ); - const response = await getGuildRoles(guildEnv); - expect(response).toBeUndefined(); + await expect(getGuildRoles(guildEnv)).rejects.toThrow( + response.ROLE_FETCH_FAILED + ); + }); + + it("should throw role fetch failed error if discord request fails", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.reject(new JSONResponse({}, { status: 500 })) + ); + + await expect(getGuildRoles(guildEnv)).rejects.toThrow( + response.ROLE_FETCH_FAILED + ); }); it("should return array of objects containing role_id and role_name", async () => { @@ -151,16 +165,10 @@ describe("getGuildRoles", () => { Promise.resolve(new JSONResponse(guildDetailsMock)) ); const roles = await getGuildRoles(guildEnv); - const expectedRoles = [ - { - id: "1234567889", - name: "@everyone", - }, - { - id: "12344567", - name: "bot one", - }, - ]; + const expectedRoles = guildDetailsMock.roles.map(({ id, name }) => ({ + id, + name, + })); expect(roles).toEqual(expectedRoles); }); }); @@ -172,8 +180,20 @@ describe("getGuildRolesByName", () => { .mockImplementationOnce(async () => Promise.resolve(new JSONResponse({}, { status: 500 })) ); - const response = await getGuildRoleByName("@everyone", guildEnv); - expect(response).toBeUndefined(); + await expect(getGuildRoles(guildEnv)).rejects.toThrow( + response.ROLE_FETCH_FAILED + ); + }); + + it("should throw role fetch failed message if discord request fails", async () => { + jest + .spyOn(global, "fetch") + .mockImplementationOnce(async () => + Promise.reject(new JSONResponse({}, { status: 500 })) + ); + await expect(getGuildRoles(guildEnv)).rejects.toThrow( + response.ROLE_FETCH_FAILED + ); }); it("should return array of objects containing role_id and role_name", async () => { From 5800e73cbb5414b9f0449dca69b5f59afaafb0f1 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Tue, 4 Jul 2023 20:02:21 +0530 Subject: [PATCH 09/28] moving test constants to fixtures --- tests/fixtures/fixture.ts | 46 ++++++++++---------- tests/unit/handlers/guildRoleHandler.test.ts | 29 ++++-------- 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index 785239a7..8a0f3fbd 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -113,29 +113,31 @@ export const generateDummyRequestObject = ({ }; }; +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, + }, +]; + export const guildDetailsMock = { id: "123434232324242424", name: "test server", - roles: [ - { - 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, - }, - ], + roles: rolesMock, }; diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts index 61e9ab89..ddbcb1bd 100644 --- a/tests/unit/handlers/guildRoleHandler.test.ts +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -4,7 +4,11 @@ import { } from "../../../src/controllers/guildRoleHandler"; import { GuildRole } from "../../../src/typeDefinitions/role.types"; import JSONResponse from "../../../src/utils/JsonResponse"; -import { generateDummyRequestObject, guildEnv } from "../../fixtures/fixture"; +import { + generateDummyRequestObject, + guildEnv, + rolesMock, +} from "../../fixtures/fixture"; import * as responseConstants from "../../../src/constants/responses"; import * as guildRoleUtils from "../../../src/utils/guildRole"; @@ -83,24 +87,14 @@ describe("get roles", () => { mockRequest, guildEnv ); - const jsonResponse: { roles: Array<{ id: string; name: string }> } = - await response.json(); + const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(200); expect(Array.isArray(jsonResponse.roles)).toBeTruthy(); expect(jsonResponse.roles.length).toBe(0); }); it("should return array of id and name of roles present in guild", async () => { - const expectedResponse = [ - { - id: "role_id_one", - name: "role_name_one", - }, - { - id: "role_id_two", - name: "role_name_two", - }, - ]; + const expectedResponse = rolesMock; getGuildRolesSpy.mockResolvedValueOnce(expectedResponse); const mockRequest = generateDummyRequestObject({ @@ -238,12 +232,7 @@ describe("get role by role name", () => { }); it("should return object of id and name corresponding to the role name recieved", async () => { - const expectedResponse = { - id: "role_id_one", - name: "everyone", - }; - - getGuildRoleByNameSpy.mockResolvedValueOnce(expectedResponse); + getGuildRoleByNameSpy.mockResolvedValueOnce(rolesMock[0]); const mockRequest = generateDummyRequestObject({ url: "/roles", @@ -259,6 +248,6 @@ describe("get role by role name", () => { ); const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(200); - expect(jsonResponse).toEqual(expectedResponse); + expect(jsonResponse).toEqual(rolesMock[0]); }); }); From abed9b9b64dd2b41bd371da429d9bcf24c0dbcb1 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Thu, 6 Jul 2023 17:26:08 +0530 Subject: [PATCH 10/28] changing error type thrown on bad request --- src/constants/responses.ts | 4 ++++ src/controllers/guildRoleHandler.ts | 2 +- tests/unit/handlers/guildRoleHandler.test.ts | 7 ++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index c8cff872..69f20022 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -30,3 +30,7 @@ export const ROLE_REMOVED = "Role Removed successfully"; 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.", +}; diff --git a/src/controllers/guildRoleHandler.ts b/src/controllers/guildRoleHandler.ts index b7d85cc4..c52134e9 100644 --- a/src/controllers/guildRoleHandler.ts +++ b/src/controllers/guildRoleHandler.ts @@ -111,7 +111,7 @@ export async function getGuildRoleByRoleNameHandler( } if (!roleName) { - return new JSONResponse(response.NOT_FOUND, { status: 404 }); + return new JSONResponse(response.BAD_REQUEST, { status: 404 }); } try { await verifyAuthToken(authHeader, env); diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts index ddbcb1bd..3ca3c13a 100644 --- a/tests/unit/handlers/guildRoleHandler.test.ts +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -20,9 +20,6 @@ const getGuildRolesSpy = jest.spyOn(guildRoleUtils, "getGuildRoles"); const getGuildRoleByNameSpy = jest.spyOn(guildRoleUtils, "getGuildRoleByName"); describe("get roles", () => { - beforeEach(() => { - jest.resetAllMocks(); - }); it("should return a instance of JSONResponse", async () => { const mockRequest = generateDummyRequestObject({ url: "/roles" }); const response = await getGuildRolesHandler(mockRequest, guildEnv); @@ -148,7 +145,7 @@ describe("get role by role name", () => { expect(jsonResponse).toEqual(responseConstants.BAD_SIGNATURE); }); - it("should return Not Found error if no roleName is not provided", async () => { + it("should return BAD REQUEST error if roleName is not provided", async () => { getGuildRoleByNameSpy.mockResolvedValueOnce(undefined); const mockRequest = generateDummyRequestObject({ url: "/roles", @@ -162,7 +159,7 @@ describe("get role by role name", () => { ); const jsonResponse: { error: string } = await response.json(); expect(response.status).toBe(404); - expect(jsonResponse).toEqual(responseConstants.NOT_FOUND); + expect(jsonResponse).toEqual(responseConstants.BAD_REQUEST); }); it("should return not found object if there is no roles with given name in guild", async () => { From a4a190b2fdbc9524e75a221bbb892cfff6b752c4 Mon Sep 17 00:00:00 2001 From: Bikash Singh Date: Sun, 9 Jul 2023 22:14:05 +0530 Subject: [PATCH 11/28] Using roles url of discord to get roles details --- src/typeDefinitions/role.types.d.ts | 22 +++++---------- src/utils/guildRole.ts | 14 +++++----- tests/fixtures/fixture.ts | 6 ---- tests/unit/handlers/guildRoleHandler.test.ts | 29 ++++++++++---------- tests/unit/utils/guildRole.test.ts | 10 +++---- 5 files changed, 33 insertions(+), 48 deletions(-) diff --git a/src/typeDefinitions/role.types.d.ts b/src/typeDefinitions/role.types.d.ts index c7309a55..5ac98f9c 100644 --- a/src/typeDefinitions/role.types.d.ts +++ b/src/typeDefinitions/role.types.d.ts @@ -1,20 +1,12 @@ export type GuildRole = { id: string; name: string; + color: string; + hoist: boolean; + icon?: string; + position?: integer; + managed?: boolean; + mentionable?: boolean; }; -export type GuildDetails = { - // This type defines the partial guild details response that we get from discord - id: string; - name: string; - roles: Array<{ - id: string; - name: string; - permissions: string; - position: number; - color: number; - hoist: boolean; - managed: boolean; - mentionable: boolean; - }>; -}; +export type Role = Pick; diff --git a/src/utils/guildRole.ts b/src/utils/guildRole.ts index 53270c7c..b0531ffc 100644 --- a/src/utils/guildRole.ts +++ b/src/utils/guildRole.ts @@ -11,7 +11,7 @@ import { guildRoleResponse, memberGroupRole, } from "../typeDefinitions/discordMessage.types"; -import { GuildDetails, GuildRole } from "../typeDefinitions/role.types"; +import { GuildRole, Role } from "../typeDefinitions/role.types"; export async function createGuildRole( body: createNewRole, @@ -87,11 +87,11 @@ export async function removeGuildRole(details: memberGroupRole, env: env) { } } -export async function getGuildRoles(env: env): Promise> { - const guildDetailsUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}`; +export async function getGuildRoles(env: env): Promise> { + const guildRolesUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`; try { - const response = await fetch(guildDetailsUrl, { + const response = await fetch(guildRolesUrl, { method: "GET", headers: { "Content-Type": "application/json", @@ -103,9 +103,9 @@ export async function getGuildRoles(env: env): Promise> { throw new Error(ROLE_FETCH_FAILED); } - const guildDetails: GuildDetails = await response.json(); + const guildRoles: Array = await response.json(); - return guildDetails.roles.map((role) => ({ + return guildRoles.map((role) => ({ id: role.id, name: role.name, })); @@ -117,7 +117,7 @@ export async function getGuildRoles(env: env): Promise> { export async function getGuildRoleByName( roleName: string, env: env -): Promise { +): Promise { const roles = await getGuildRoles(env); return roles?.find((role) => role.name === roleName); } diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index 8a0f3fbd..b051ddf6 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -135,9 +135,3 @@ export const rolesMock = [ mentionable: true, }, ]; - -export const guildDetailsMock = { - id: "123434232324242424", - name: "test server", - roles: rolesMock, -}; diff --git a/tests/unit/handlers/guildRoleHandler.test.ts b/tests/unit/handlers/guildRoleHandler.test.ts index 3ca3c13a..ad579564 100644 --- a/tests/unit/handlers/guildRoleHandler.test.ts +++ b/tests/unit/handlers/guildRoleHandler.test.ts @@ -2,7 +2,7 @@ import { getGuildRoleByRoleNameHandler, getGuildRolesHandler, } from "../../../src/controllers/guildRoleHandler"; -import { GuildRole } from "../../../src/typeDefinitions/role.types"; +import { Role } from "../../../src/typeDefinitions/role.types"; import JSONResponse from "../../../src/utils/JsonResponse"; import { generateDummyRequestObject, @@ -84,16 +84,14 @@ describe("get roles", () => { mockRequest, guildEnv ); - const jsonResponse: { roles: Array } = await response.json(); + const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(200); expect(Array.isArray(jsonResponse.roles)).toBeTruthy(); expect(jsonResponse.roles.length).toBe(0); }); it("should return array of id and name of roles present in guild", async () => { - const expectedResponse = rolesMock; - getGuildRolesSpy.mockResolvedValueOnce(expectedResponse); - + getGuildRolesSpy.mockResolvedValueOnce(rolesMock); const mockRequest = generateDummyRequestObject({ url: "/roles", headers: { Authorization: "Bearer testtoken" }, @@ -103,15 +101,15 @@ describe("get roles", () => { mockRequest, guildEnv ); - const jsonResponse: { roles: Array } = await response.json(); + const jsonResponse: { roles: Array } = await response.json(); expect(response.status).toBe(200); expect(Array.isArray(jsonResponse.roles)).toBeTruthy(); - expect(jsonResponse.roles).toEqual(expectedResponse); + expect(jsonResponse.roles).toEqual(rolesMock); }); }); describe("get role by role name", () => { - beforeEach(() => { + afterEach(() => { jest.resetAllMocks(); }); @@ -199,9 +197,9 @@ describe("get role by role name", () => { mockRequest, guildEnv ); - const jsonResponse: { roles: Array } = await response.json(); + const role: Role = await response.json(); expect(response.status).toBe(500); - expect(jsonResponse).toEqual({ + expect(role).toEqual({ error: responseConstants.ROLE_FETCH_FAILED, }); }); @@ -221,15 +219,16 @@ describe("get role by role name", () => { mockRequest, guildEnv ); - const jsonResponse: { roles: Array } = await response.json(); + const role: Role = await response.json(); expect(response.status).toBe(500); - expect(jsonResponse).toEqual({ + expect(role).toEqual({ error: responseConstants.INTERNAL_SERVER_ERROR, }); }); it("should return object of id and name corresponding to the role name recieved", async () => { - getGuildRoleByNameSpy.mockResolvedValueOnce(rolesMock[0]); + const resultMock = { id: rolesMock[0].id, name: rolesMock[0].name }; + getGuildRoleByNameSpy.mockResolvedValueOnce(resultMock); const mockRequest = generateDummyRequestObject({ url: "/roles", @@ -243,8 +242,8 @@ describe("get role by role name", () => { mockRequest, guildEnv ); - const jsonResponse: { roles: Array } = await response.json(); + const role: Role = await response.json(); expect(response.status).toBe(200); - expect(jsonResponse).toEqual(rolesMock[0]); + expect(role).toEqual(resultMock); }); }); diff --git a/tests/unit/utils/guildRole.test.ts b/tests/unit/utils/guildRole.test.ts index c4624d2a..d518ecca 100644 --- a/tests/unit/utils/guildRole.test.ts +++ b/tests/unit/utils/guildRole.test.ts @@ -10,8 +10,8 @@ import { import { dummyAddRoleBody, dummyCreateBody, - guildDetailsMock, guildEnv, + rolesMock, } from "../../fixtures/fixture"; describe("createGuildRole", () => { @@ -162,10 +162,10 @@ describe("getGuildRoles", () => { jest .spyOn(global, "fetch") .mockImplementationOnce(async () => - Promise.resolve(new JSONResponse(guildDetailsMock)) + Promise.resolve(new JSONResponse(rolesMock)) ); const roles = await getGuildRoles(guildEnv); - const expectedRoles = guildDetailsMock.roles.map(({ id, name }) => ({ + const expectedRoles = rolesMock.map(({ id, name }) => ({ id, name, })); @@ -200,7 +200,7 @@ describe("getGuildRolesByName", () => { jest .spyOn(global, "fetch") .mockImplementationOnce(async () => - Promise.resolve(new JSONResponse(guildDetailsMock)) + Promise.resolve(new JSONResponse(rolesMock)) ); const role = await getGuildRoleByName("@everyone", guildEnv); const expectedRoles = { @@ -214,7 +214,7 @@ describe("getGuildRolesByName", () => { jest .spyOn(global, "fetch") .mockImplementationOnce(async () => - Promise.resolve(new JSONResponse(guildDetailsMock)) + Promise.resolve(new JSONResponse(rolesMock)) ); const role = await getGuildRoleByName("everyone", guildEnv); expect(role).toBeUndefined(); From efcd4d06491a81fde342b34af9693f75d6cdacbf Mon Sep 17 00:00:00 2001 From: SHREYA MISHRA <61110378+shreya-mishra@users.noreply.github.com> Date: Wed, 19 Jul 2023 05:19:21 +0530 Subject: [PATCH 12/28] Raising different PR for /verify string (#94) * raising different PR for /verify string * resolved the comment * fix lint issue * fix lint issue --- src/constants/responses.ts | 3 +++ src/controllers/verifyCommand.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 69f20022..b6317d9a 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -28,6 +28,9 @@ 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."; diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index f5816cb0..668010f3 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -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"; @@ -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); From cd7cf9a9d4f5b32f315a1954f50626b93e58927b Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Sat, 1 Jul 2023 12:35:43 +0530 Subject: [PATCH 13/28] Added description to the message after using /verify #85 --- src/controllers/verifyCommand.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 668010f3..4cda0e39 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -13,7 +13,6 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); - const response = await sendUserDiscordData( token, userId, From 9e787d89f7f1b54183e07cf9d56405d948cce985 Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Sat, 15 Jul 2023 01:57:01 +0530 Subject: [PATCH 14/28] imported crypto --- src/utils/generateUniqueToken.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/generateUniqueToken.ts b/src/utils/generateUniqueToken.ts index d7fa803c..cdfbf4ec 100644 --- a/src/utils/generateUniqueToken.ts +++ b/src/utils/generateUniqueToken.ts @@ -1,3 +1,4 @@ +const crypto = require("crypto"); export const generateUniqueToken = async () => { const uuidToken = crypto.randomUUID(); const randomNumber = Math.floor(Math.random() * 1000000); From c8076edf0f78b9ba252135a81370df2b3364ca5f Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Sat, 15 Jul 2023 01:58:23 +0530 Subject: [PATCH 15/28] Tried mocking jsonwebtoken, jwt --- __mocks__/@tsndr/cloudflare-worker-jwt.js | 10 ++ __mocks__/@tsndr/cloudflare-worker-jwt.ts | 14 +++ package-lock.json | 132 ++++++++++++++++++++++ package.json | 2 + src/controllers/verifyCommand.ts | 5 +- tests/mocks/__mocks__ | 0 tests/unit/handlers/verifyCommand.test.ts | 112 ++++++++++++++++++ 7 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 __mocks__/@tsndr/cloudflare-worker-jwt.js create mode 100644 __mocks__/@tsndr/cloudflare-worker-jwt.ts create mode 100644 tests/mocks/__mocks__ create mode 100644 tests/unit/handlers/verifyCommand.test.ts diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.js b/__mocks__/@tsndr/cloudflare-worker-jwt.js new file mode 100644 index 00000000..8e14ab3f --- /dev/null +++ b/__mocks__/@tsndr/cloudflare-worker-jwt.js @@ -0,0 +1,10 @@ +"use strict"; + +const jwt = Object.create({}); + +jwt.sign = jest.fn().mockImplementation(() => { + console.log("MOCKED PACKAGED"); + return "asdasd"; +}); + +module.exports = jwt; diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.ts b/__mocks__/@tsndr/cloudflare-worker-jwt.ts new file mode 100644 index 00000000..6bf409e1 --- /dev/null +++ b/__mocks__/@tsndr/cloudflare-worker-jwt.ts @@ -0,0 +1,14 @@ +"use strict"; +import jsonwebtoken from "jsonwebtoken"; + +const cloudflareWorkerJwt = jest.createMockFromModule("jsonwebtoken"); + +function sign() { + console.log("ASD"); + return "asd"; +} + +// @ts-ignore +cloudflareWorkerJwt.sign = sign; + +module.exports = cloudflareWorkerJwt; diff --git a/package-lock.json b/package-lock.json index 7f88fd0c..0e1e8e09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,12 +18,14 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20221111.1", "@types/jest": "^29.2.5", + "@types/jsonwebtoken": "^9.0.2", "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.2", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "eslint": "^8.31.0", "jest": "^29.3.1", + "jsonwebtoken": "^9.0.1", "ngrok": "^5.0.0-beta.2", "pre-commit": "^1.2.2", "prettier": "^2.8.1", @@ -1880,6 +1882,15 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -2571,6 +2582,12 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3073,6 +3090,15 @@ "node": ">=12" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.284", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", @@ -4952,6 +4978,43 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", + "integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==", + "dev": true, + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -5013,6 +5076,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -8372,6 +8441,15 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "@types/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -8855,6 +8933,12 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -9219,6 +9303,15 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, "electron-to-chromium": { "version": "1.4.284", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", @@ -10641,6 +10734,39 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "jsonwebtoken": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", + "integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==", + "dev": true, + "requires": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -10687,6 +10813,12 @@ "p-locate": "^5.0.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", diff --git a/package.json b/package.json index c2b1425e..3230da25 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,14 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20221111.1", "@types/jest": "^29.2.5", + "@types/jsonwebtoken": "^9.0.2", "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.2", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "eslint": "^8.31.0", "jest": "^29.3.1", + "jsonwebtoken": "^9.0.1", "ngrok": "^5.0.0-beta.2", "pre-commit": "^1.2.2", "prettier": "^2.8.1", diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 4cda0e39..d514918b 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -3,7 +3,7 @@ import { RETRY_COMMAND, VERIFICATION_STRING } from "../constants/responses"; import { env } from "../typeDefinitions/default.types"; import { discordEphemeralResponse } from "../utils/discordEphemeralResponse"; import { generateUniqueToken } from "../utils/generateUniqueToken"; -import { sendUserDiscordData } from "../utils/sendUserDiscordData"; +import {sendUserDiscordData} from "../utils/sendUserDiscordData"; export async function verifyCommand( userId: number, @@ -13,8 +13,7 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); - const response = await sendUserDiscordData( - token, + const response = await sendUserDiscordData( token, userId, userAvatarHash, userName, diff --git a/tests/mocks/__mocks__ b/tests/mocks/__mocks__ new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts new file mode 100644 index 00000000..6e461c8a --- /dev/null +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -0,0 +1,112 @@ +import * as response from "../../../src/constants/responses"; +import JSONResponse from "../../../src/utils/JsonResponse"; +import { verifyCommand } from "../../../src/controllers/verifyCommand"; +import { guildEnv } from "../../fixtures/fixture"; +import config from "../../../config/config"; + +describe("verifyCommand", () => { + test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { + + jest.mock("crypto", () => { + return { + randomUUID: jest.fn(()=>'shreya'), + subtle: { digest: jest.fn(() => "123") }, + }; + }); + + jest.mock("../../../src/utils/generateUniqueToken", () => ({ + generateUniqueToken: () => Promise.resolve("jashdkjahskajhd"), + })); + + // const mockResponse = response.INTERNAL_SERVER_ERROR; + // jest + // .spyOn(global, "fetch") + // .mockImplementation(() => + // Promise.resolve(new JSONResponse(mockResponse)) + // ); + + const env = { + BOT_PUBLIC_KEY: "xyz", + DISCORD_GUILD_ID: "123", + DISCORD_TOKEN: "abc", + }; + + const data = { + token: 1233434, + userId: "sjkhdkjashdksjh", + userAvatarHash: "test user", + userName: "sndbhsbgdj", + env: env, + }; + + const result = await verifyCommand( + 1233434, + "sjkhdkjashdksjh", + "test user", + "sndbhsbgdj", + env + ); + + // expect(result.data.content).toEqual(response.RETRY_COMMAND); + expect(global.fetch).toHaveBeenCalledWith( + `https://api.realdevsquad.com/external-accounts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`, + }, + body: JSON.stringify(data), + } + ); + }); + + test("should return JSON response when response is ok", async () => { + const mockResponse = {}; + + // jest + // .spyOn(global, "fetch") + // .mockImplementation(() => + // Promise.resolve(new JSONResponse(mockResponse)) + // ); + + const env = { + BOT_PUBLIC_KEY: "xyz", + DISCORD_GUILD_ID: "123", + DISCORD_TOKEN: "abc", + }; + + const data = { + token: 1233434, + userId: "sjkhdkjashdksjh", + userAvatarHash: "test user", + userName: "sndbhsbgdj", + env: env, + }; + + const result = await verifyCommand( + 1233434, + "sjkhdkjashdksjh", + "test user", + "sndbhsbgdj", + env + ); + + const verificationSiteURL = config(env).VERIFICATION_SITE_URL; + const message = + `${verificationSiteURL}/discord?token=${guildEnv.DISCORD_TOKEN}\n` + + response.VERIFICATION_STRING; + + expect(global.fetch).toHaveBeenCalledWith( + `https://api.realdevsquad.com/external-accounts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`, + }, + body: JSON.stringify(data), + } + ); + }); +}); From 6a988a232b02b05c5a67c582100198c86ba9b3e1 Mon Sep 17 00:00:00 2001 From: Prakash Date: Mon, 17 Jul 2023 19:27:35 +0530 Subject: [PATCH 16/28] add mock for @tsndr/cloudflare-worker-jwt and generateUniqueToken, fix test cases --- __mocks__/@tsndr/cloudflare-worker-jwt.js | 10 -- __mocks__/@tsndr/cloudflare-worker-jwt.ts | 22 ++-- package.json | 2 +- src/controllers/verifyCommand.ts | 5 +- src/utils/generateUniqueToken.ts | 1 - tests/unit/handlers/verifyCommand.test.ts | 143 ++++++++++++---------- 6 files changed, 91 insertions(+), 92 deletions(-) delete mode 100644 __mocks__/@tsndr/cloudflare-worker-jwt.js diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.js b/__mocks__/@tsndr/cloudflare-worker-jwt.js deleted file mode 100644 index 8e14ab3f..00000000 --- a/__mocks__/@tsndr/cloudflare-worker-jwt.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; - -const jwt = Object.create({}); - -jwt.sign = jest.fn().mockImplementation(() => { - console.log("MOCKED PACKAGED"); - return "asdasd"; -}); - -module.exports = jwt; diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.ts b/__mocks__/@tsndr/cloudflare-worker-jwt.ts index 6bf409e1..fdc59d3f 100644 --- a/__mocks__/@tsndr/cloudflare-worker-jwt.ts +++ b/__mocks__/@tsndr/cloudflare-worker-jwt.ts @@ -1,14 +1,8 @@ -"use strict"; -import jsonwebtoken from "jsonwebtoken"; - -const cloudflareWorkerJwt = jest.createMockFromModule("jsonwebtoken"); - -function sign() { - console.log("ASD"); - return "asd"; -} - -// @ts-ignore -cloudflareWorkerJwt.sign = sign; - -module.exports = cloudflareWorkerJwt; +// __mocks__/@tsndr/cloudflare-worker-jwt.js +const mockJwt = { + sign: jest.fn().mockImplementation(() => { + return "SIGNED_JWT"; + }), +}; + +export default mockJwt; diff --git a/package.json b/package.json index 3230da25..53780113 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "start": "wrangler dev", "test": "echo 'running tests ๐Ÿงช' && jest --coverage && echo 'โœ… All tests passed'", - "test-watch": "jest --watch", + "test-watch": "jest . --watch", "login": "wrangler login", "check": "wrangler whoami", "deploy": "wrangler deploy", diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index d514918b..4cda0e39 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -3,7 +3,7 @@ import { RETRY_COMMAND, VERIFICATION_STRING } from "../constants/responses"; import { env } from "../typeDefinitions/default.types"; import { discordEphemeralResponse } from "../utils/discordEphemeralResponse"; import { generateUniqueToken } from "../utils/generateUniqueToken"; -import {sendUserDiscordData} from "../utils/sendUserDiscordData"; +import { sendUserDiscordData } from "../utils/sendUserDiscordData"; export async function verifyCommand( userId: number, @@ -13,7 +13,8 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); - const response = await sendUserDiscordData( token, + const response = await sendUserDiscordData( + token, userId, userAvatarHash, userName, diff --git a/src/utils/generateUniqueToken.ts b/src/utils/generateUniqueToken.ts index cdfbf4ec..d7fa803c 100644 --- a/src/utils/generateUniqueToken.ts +++ b/src/utils/generateUniqueToken.ts @@ -1,4 +1,3 @@ -const crypto = require("crypto"); export const generateUniqueToken = async () => { const uuidToken = crypto.randomUUID(); const randomNumber = Math.floor(Math.random() * 1000000); diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts index 6e461c8a..be71d2fb 100644 --- a/tests/unit/handlers/verifyCommand.test.ts +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -1,89 +1,105 @@ -import * as response from "../../../src/constants/responses"; -import JSONResponse from "../../../src/utils/JsonResponse"; -import { verifyCommand } from "../../../src/controllers/verifyCommand"; -import { guildEnv } from "../../fixtures/fixture"; +import { + RETRY_COMMAND, + VERIFICATION_STRING, +} from "../../../src/constants/responses"; import config from "../../../config/config"; -describe("verifyCommand", () => { - test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { - - jest.mock("crypto", () => { - return { - randomUUID: jest.fn(()=>'shreya'), - subtle: { digest: jest.fn(() => "123") }, - }; - }); +const mockDateNow = 1626512345678; +const UNIQUE_TOKEN = "UNIQUE_TOKEN"; +const env = { + BOT_PUBLIC_KEY: "BOT_PUBLIC_KEY", + DISCORD_GUILD_ID: "DISCORD_GUILD_ID", + DISCORD_TOKEN: "SIGNED_JWT", +}; +describe("verifyCommand", () => { + beforeEach(() => { + jest.mock("@tsndr/cloudflare-worker-jwt"); + jest.spyOn(Date, "now").mockReturnValue(mockDateNow); jest.mock("../../../src/utils/generateUniqueToken", () => ({ - generateUniqueToken: () => Promise.resolve("jashdkjahskajhd"), + generateUniqueToken: () => Promise.resolve(UNIQUE_TOKEN), })); + }); - // const mockResponse = response.INTERNAL_SERVER_ERROR; - // jest - // .spyOn(global, "fetch") - // .mockImplementation(() => - // Promise.resolve(new JSONResponse(mockResponse)) - // ); - - const env = { - BOT_PUBLIC_KEY: "xyz", - DISCORD_GUILD_ID: "123", - DISCORD_TOKEN: "abc", - }; + afterEach(() => { + jest.spyOn(Date, "now").mockRestore(); + }); + test("should return JSON response when response is ok", async () => { const data = { - token: 1233434, - userId: "sjkhdkjashdksjh", - userAvatarHash: "test user", - userName: "sndbhsbgdj", - env: env, + type: "discord", + token: UNIQUE_TOKEN, + attributes: { + discordId: 1, + userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + userName: "userName", + discriminator: "discriminator", + expiry: mockDateNow + 1000 * 60 * 2, + }, }; + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + ok: true, + status: 200, + json: jest.fn().mockResolvedValueOnce(data), + } as unknown as Response); + + const { verifyCommand } = await import( + "../../../src/controllers/verifyCommand" + ); + const result = await verifyCommand( - 1233434, - "sjkhdkjashdksjh", - "test user", - "sndbhsbgdj", + 1, + "userAvatarHash", + "userName", + "discriminator", env ); - // expect(result.data.content).toEqual(response.RETRY_COMMAND); expect(global.fetch).toHaveBeenCalledWith( - `https://api.realdevsquad.com/external-accounts`, + `http://localhost:3000/external-accounts`, { method: "POST", headers: { "Content-Type": "application/json", - Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`, + Authorization: `Bearer ${env.DISCORD_TOKEN}`, }, body: JSON.stringify(data), } ); - }); - - test("should return JSON response when response is ok", async () => { - const mockResponse = {}; + const resultText = await result.text(); + const resultData = JSON.parse(resultText); - // jest - // .spyOn(global, "fetch") - // .mockImplementation(() => - // Promise.resolve(new JSONResponse(mockResponse)) - // ); + const verificationSiteURL = config(env).VERIFICATION_SITE_URL; + const message = + `${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n` + + VERIFICATION_STRING; - const env = { - BOT_PUBLIC_KEY: "xyz", - DISCORD_GUILD_ID: "123", - DISCORD_TOKEN: "abc", - }; + expect(resultData.data.content).toEqual(message); + }); + test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { const data = { - token: 1233434, - userId: "sjkhdkjashdksjh", - userAvatarHash: "test user", - userName: "sndbhsbgdj", - env: env, + type: "discord", + token: UNIQUE_TOKEN, + attributes: { + discordId: 1, + userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + userName: "userName", + discriminator: "discriminator", + expiry: mockDateNow + 1000 * 60 * 2, + }, }; + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + ok: true, + status: 400, // ERROR STATUS + json: jest.fn().mockResolvedValueOnce(data), + } as unknown as Response); + + const { verifyCommand } = await import( + "../../../src/controllers/verifyCommand" + ); const result = await verifyCommand( 1233434, "sjkhdkjashdksjh", @@ -92,21 +108,20 @@ describe("verifyCommand", () => { env ); - const verificationSiteURL = config(env).VERIFICATION_SITE_URL; - const message = - `${verificationSiteURL}/discord?token=${guildEnv.DISCORD_TOKEN}\n` + - response.VERIFICATION_STRING; - expect(global.fetch).toHaveBeenCalledWith( - `https://api.realdevsquad.com/external-accounts`, + `http://localhost:3000/external-accounts`, { method: "POST", headers: { "Content-Type": "application/json", - Authorization: `Bot ${guildEnv.DISCORD_TOKEN}`, + Authorization: `Bearer ${env.DISCORD_TOKEN}`, }, body: JSON.stringify(data), } ); + const resultText = await result.text(); + const resultData = JSON.parse(resultText); + + expect(resultData.data.content).toEqual(RETRY_COMMAND); }); }); From 51f8de0a0dbf28a0848c1f9bfe013571a319f6ab Mon Sep 17 00:00:00 2001 From: Prakash Date: Fri, 21 Jul 2023 00:42:20 +0530 Subject: [PATCH 17/28] remove jsonwebtoken from package.json --- package-lock.json | 132 ---------------------------------------------- package.json | 2 - 2 files changed, 134 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e1e8e09..7f88fd0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,14 +18,12 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20221111.1", "@types/jest": "^29.2.5", - "@types/jsonwebtoken": "^9.0.2", "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.2", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "eslint": "^8.31.0", "jest": "^29.3.1", - "jsonwebtoken": "^9.0.1", "ngrok": "^5.0.0-beta.2", "pre-commit": "^1.2.2", "prettier": "^2.8.1", @@ -1882,15 +1880,6 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -2582,12 +2571,6 @@ "node": "*" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3090,15 +3073,6 @@ "node": ">=12" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/electron-to-chromium": { "version": "1.4.284", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", @@ -4978,43 +4952,6 @@ "node": ">=6" } }, - "node_modules/jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==", - "dev": true, - "dependencies": { - "jws": "^3.2.2", - "lodash": "^4.17.21", - "ms": "^2.1.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dev": true, - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dev": true, - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -5076,12 +5013,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -8441,15 +8372,6 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, - "@types/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -8933,12 +8855,6 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true - }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -9303,15 +9219,6 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, "electron-to-chromium": { "version": "1.4.284", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", @@ -10734,39 +10641,6 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, - "jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==", - "dev": true, - "requires": { - "jws": "^3.2.2", - "lodash": "^4.17.21", - "ms": "^2.1.1", - "semver": "^7.3.8" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dev": true, - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dev": true, - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -10813,12 +10687,6 @@ "p-locate": "^5.0.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", diff --git a/package.json b/package.json index 53780113..f7b190e9 100644 --- a/package.json +++ b/package.json @@ -22,14 +22,12 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20221111.1", "@types/jest": "^29.2.5", - "@types/jsonwebtoken": "^9.0.2", "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.2", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "eslint": "^8.31.0", "jest": "^29.3.1", - "jsonwebtoken": "^9.0.1", "ngrok": "^5.0.0-beta.2", "pre-commit": "^1.2.2", "prettier": "^2.8.1", From b117aea48eee8ae7477edcc57d5fd6caf50ca594 Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Fri, 21 Jul 2023 06:04:13 +0530 Subject: [PATCH 18/28] reverted some extra changes --- __mocks__/@tsndr/cloudflare-worker-jwt.ts | 1 - src/controllers/verifyCommand.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.ts b/__mocks__/@tsndr/cloudflare-worker-jwt.ts index fdc59d3f..d90cca54 100644 --- a/__mocks__/@tsndr/cloudflare-worker-jwt.ts +++ b/__mocks__/@tsndr/cloudflare-worker-jwt.ts @@ -1,4 +1,3 @@ -// __mocks__/@tsndr/cloudflare-worker-jwt.js const mockJwt = { sign: jest.fn().mockImplementation(() => { return "SIGNED_JWT"; diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 4cda0e39..053ebb8b 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -13,6 +13,7 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); + const response = await sendUserDiscordData( token, userId, From 6321376f49e670280a0803aaae1392924c1e9c0d Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Fri, 21 Jul 2023 07:14:17 +0530 Subject: [PATCH 19/28] resolved the comments --- tests/fixtures/fixture.ts | 19 +++++++++++ tests/unit/handlers/verifyCommand.test.ts | 39 ++++------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index b051ddf6..877d5a28 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -135,3 +135,22 @@ export const rolesMock = [ mentionable: true, }, ]; +export const mockDateNow = 1626512345678; +export const UNIQUE_TOKEN = "UNIQUE_TOKEN"; +export const env = { + BOT_PUBLIC_KEY: "BOT_PUBLIC_KEY", + DISCORD_GUILD_ID: "DISCORD_GUILD_ID", + DISCORD_TOKEN: "SIGNED_JWT", +}; + +export const discordUserData = { + type: "discord", + token: UNIQUE_TOKEN, + attributes: { + discordId: 1, + userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + userName: "userName", + discriminator: "discriminator", + expiry: mockDateNow + 1000 * 60 * 2, + }, +}; diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts index be71d2fb..4a9e0181 100644 --- a/tests/unit/handlers/verifyCommand.test.ts +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -3,14 +3,9 @@ import { VERIFICATION_STRING, } from "../../../src/constants/responses"; import config from "../../../config/config"; +import { UNIQUE_TOKEN, discordUserData, env, mockDateNow } from "../../fixtures/fixture"; + -const mockDateNow = 1626512345678; -const UNIQUE_TOKEN = "UNIQUE_TOKEN"; -const env = { - BOT_PUBLIC_KEY: "BOT_PUBLIC_KEY", - DISCORD_GUILD_ID: "DISCORD_GUILD_ID", - DISCORD_TOKEN: "SIGNED_JWT", -}; describe("verifyCommand", () => { beforeEach(() => { @@ -26,22 +21,11 @@ describe("verifyCommand", () => { }); test("should return JSON response when response is ok", async () => { - const data = { - type: "discord", - token: UNIQUE_TOKEN, - attributes: { - discordId: 1, - userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", - userName: "userName", - discriminator: "discriminator", - expiry: mockDateNow + 1000 * 60 * 2, - }, - }; jest.spyOn(global, "fetch").mockResolvedValueOnce({ ok: true, status: 200, - json: jest.fn().mockResolvedValueOnce(data), + json: jest.fn().mockResolvedValueOnce(discordUserData), } as unknown as Response); const { verifyCommand } = await import( @@ -64,7 +48,7 @@ describe("verifyCommand", () => { "Content-Type": "application/json", Authorization: `Bearer ${env.DISCORD_TOKEN}`, }, - body: JSON.stringify(data), + body: JSON.stringify(discordUserData), } ); const resultText = await result.text(); @@ -79,22 +63,11 @@ describe("verifyCommand", () => { }); test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { - const data = { - type: "discord", - token: UNIQUE_TOKEN, - attributes: { - discordId: 1, - userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", - userName: "userName", - discriminator: "discriminator", - expiry: mockDateNow + 1000 * 60 * 2, - }, - }; jest.spyOn(global, "fetch").mockResolvedValueOnce({ ok: true, status: 400, // ERROR STATUS - json: jest.fn().mockResolvedValueOnce(data), + json: jest.fn().mockResolvedValueOnce(discordUserData), } as unknown as Response); const { verifyCommand } = await import( @@ -116,7 +89,7 @@ describe("verifyCommand", () => { "Content-Type": "application/json", Authorization: `Bearer ${env.DISCORD_TOKEN}`, }, - body: JSON.stringify(data), + body: JSON.stringify(discordUserData), } ); const resultText = await result.text(); From 6869787e8fe88bf8d16556eae59efa3a4dc88dff Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Fri, 21 Jul 2023 08:02:49 +0530 Subject: [PATCH 20/28] fix: prettier issue --- src/controllers/verifyCommand.ts | 2 +- tests/fixtures/fixture.ts | 2 +- tests/unit/handlers/verifyCommand.test.ts | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 053ebb8b..668010f3 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -13,7 +13,7 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); - + const response = await sendUserDiscordData( token, userId, diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index 877d5a28..ee237192 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -143,7 +143,7 @@ export const env = { DISCORD_TOKEN: "SIGNED_JWT", }; -export const discordUserData = { +export const discordUserData = { type: "discord", token: UNIQUE_TOKEN, attributes: { diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts index 4a9e0181..15d19dbc 100644 --- a/tests/unit/handlers/verifyCommand.test.ts +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -3,9 +3,12 @@ import { VERIFICATION_STRING, } from "../../../src/constants/responses"; import config from "../../../config/config"; -import { UNIQUE_TOKEN, discordUserData, env, mockDateNow } from "../../fixtures/fixture"; - - +import { + UNIQUE_TOKEN, + discordUserData, + env, + mockDateNow, +} from "../../fixtures/fixture"; describe("verifyCommand", () => { beforeEach(() => { @@ -21,7 +24,6 @@ describe("verifyCommand", () => { }); test("should return JSON response when response is ok", async () => { - jest.spyOn(global, "fetch").mockResolvedValueOnce({ ok: true, status: 200, @@ -63,7 +65,6 @@ describe("verifyCommand", () => { }); test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { - jest.spyOn(global, "fetch").mockResolvedValueOnce({ ok: true, status: 400, // ERROR STATUS From 7666e4990f9d3b9cdc3e646696360bb82b166228 Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Fri, 21 Jul 2023 23:24:32 +0530 Subject: [PATCH 21/28] fix: prettier issue --- src/controllers/verifyCommand.ts | 1 - tests/mocks/__mocks__ | 0 2 files changed, 1 deletion(-) delete mode 100644 tests/mocks/__mocks__ diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 668010f3..4cda0e39 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -13,7 +13,6 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); - const response = await sendUserDiscordData( token, userId, diff --git a/tests/mocks/__mocks__ b/tests/mocks/__mocks__ deleted file mode 100644 index e69de29b..00000000 From 886a8f15759269d18f2b39b6be2f9465c1132b04 Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Sat, 22 Jul 2023 05:22:49 +0530 Subject: [PATCH 22/28] fix: prettier issue --- src/controllers/verifyCommand.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 4cda0e39..053ebb8b 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -13,6 +13,7 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); + const response = await sendUserDiscordData( token, userId, From 26229bfe09f7e7c991f721a455bd7f564d8d1c37 Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Sat, 22 Jul 2023 05:29:07 +0530 Subject: [PATCH 23/28] lint fix --- src/controllers/verifyCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 053ebb8b..668010f3 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -13,7 +13,7 @@ export async function verifyCommand( env: env ) { const token = await generateUniqueToken(); - + const response = await sendUserDiscordData( token, userId, From 2c34c7d74ef37e73143e6fbd9e846eec49093e34 Mon Sep 17 00:00:00 2001 From: SHREYA MISHRA <61110378+shreya-mishra@users.noreply.github.com> Date: Sat, 22 Jul 2023 05:45:38 +0530 Subject: [PATCH 24/28] Issue#85 test (#98) * Added description to the message after using /verify #85 * imported crypto * Tried mocking jsonwebtoken, jwt * add mock for @tsndr/cloudflare-worker-jwt and generateUniqueToken, fix test cases * remove jsonwebtoken from package.json * reverted some extra changes * resolved the comments * fix: prettier issue * fix: prettier issue * fix: prettier issue * lint fix --------- Co-authored-by: Prakash --- __mocks__/@tsndr/cloudflare-worker-jwt.ts | 7 ++ package.json | 2 +- tests/fixtures/fixture.ts | 19 ++++ tests/unit/handlers/verifyCommand.test.ts | 101 ++++++++++++++++++++++ 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 __mocks__/@tsndr/cloudflare-worker-jwt.ts create mode 100644 tests/unit/handlers/verifyCommand.test.ts diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.ts b/__mocks__/@tsndr/cloudflare-worker-jwt.ts new file mode 100644 index 00000000..d90cca54 --- /dev/null +++ b/__mocks__/@tsndr/cloudflare-worker-jwt.ts @@ -0,0 +1,7 @@ +const mockJwt = { + sign: jest.fn().mockImplementation(() => { + return "SIGNED_JWT"; + }), +}; + +export default mockJwt; diff --git a/package.json b/package.json index c2b1425e..f7b190e9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "start": "wrangler dev", "test": "echo 'running tests ๐Ÿงช' && jest --coverage && echo 'โœ… All tests passed'", - "test-watch": "jest --watch", + "test-watch": "jest . --watch", "login": "wrangler login", "check": "wrangler whoami", "deploy": "wrangler deploy", diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index b051ddf6..ee237192 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -135,3 +135,22 @@ export const rolesMock = [ mentionable: true, }, ]; +export const mockDateNow = 1626512345678; +export const UNIQUE_TOKEN = "UNIQUE_TOKEN"; +export const env = { + BOT_PUBLIC_KEY: "BOT_PUBLIC_KEY", + DISCORD_GUILD_ID: "DISCORD_GUILD_ID", + DISCORD_TOKEN: "SIGNED_JWT", +}; + +export const discordUserData = { + type: "discord", + token: UNIQUE_TOKEN, + attributes: { + discordId: 1, + userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + userName: "userName", + discriminator: "discriminator", + expiry: mockDateNow + 1000 * 60 * 2, + }, +}; diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts new file mode 100644 index 00000000..15d19dbc --- /dev/null +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -0,0 +1,101 @@ +import { + RETRY_COMMAND, + VERIFICATION_STRING, +} from "../../../src/constants/responses"; +import config from "../../../config/config"; +import { + UNIQUE_TOKEN, + discordUserData, + env, + mockDateNow, +} from "../../fixtures/fixture"; + +describe("verifyCommand", () => { + beforeEach(() => { + jest.mock("@tsndr/cloudflare-worker-jwt"); + jest.spyOn(Date, "now").mockReturnValue(mockDateNow); + jest.mock("../../../src/utils/generateUniqueToken", () => ({ + generateUniqueToken: () => Promise.resolve(UNIQUE_TOKEN), + })); + }); + + afterEach(() => { + jest.spyOn(Date, "now").mockRestore(); + }); + + test("should return JSON response when response is ok", async () => { + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + ok: true, + status: 200, + json: jest.fn().mockResolvedValueOnce(discordUserData), + } as unknown as Response); + + const { verifyCommand } = await import( + "../../../src/controllers/verifyCommand" + ); + + const result = await verifyCommand( + 1, + "userAvatarHash", + "userName", + "discriminator", + env + ); + + expect(global.fetch).toHaveBeenCalledWith( + `http://localhost:3000/external-accounts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${env.DISCORD_TOKEN}`, + }, + body: JSON.stringify(discordUserData), + } + ); + const resultText = await result.text(); + const resultData = JSON.parse(resultText); + + const verificationSiteURL = config(env).VERIFICATION_SITE_URL; + const message = + `${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n` + + VERIFICATION_STRING; + + expect(resultData.data.content).toEqual(message); + }); + + test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + ok: true, + status: 400, // ERROR STATUS + json: jest.fn().mockResolvedValueOnce(discordUserData), + } as unknown as Response); + + const { verifyCommand } = await import( + "../../../src/controllers/verifyCommand" + ); + const result = await verifyCommand( + 1233434, + "sjkhdkjashdksjh", + "test user", + "sndbhsbgdj", + env + ); + + expect(global.fetch).toHaveBeenCalledWith( + `http://localhost:3000/external-accounts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${env.DISCORD_TOKEN}`, + }, + body: JSON.stringify(discordUserData), + } + ); + const resultText = await result.text(); + const resultData = JSON.parse(resultText); + + expect(resultData.data.content).toEqual(RETRY_COMMAND); + }); +}); From 515382d648c35f0b9885ba961e4e89d09dfbb47e Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Mon, 31 Jul 2023 06:22:58 +0530 Subject: [PATCH 25/28] updated verifications string --- src/constants/responses.ts | 2 +- src/controllers/verifyCommand.ts | 2 +- tests/unit/handlers/verifyCommand.test.ts | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index b6317d9a..77c1f3e2 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -29,7 +29,7 @@ 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."; + "Please verify your identity by clicking the link below ๐Ÿ‘‡ 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."; diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 668010f3..64b61e55 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -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}\n${VERIFICATION_STRING}`; + const message = `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${token}`; return discordEphemeralResponse(message); } else { return discordEphemeralResponse(RETRY_COMMAND); diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts index 15d19dbc..04c53884 100644 --- a/tests/unit/handlers/verifyCommand.test.ts +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -58,8 +58,7 @@ describe("verifyCommand", () => { const verificationSiteURL = config(env).VERIFICATION_SITE_URL; const message = - `${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n` + - VERIFICATION_STRING; + `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}` expect(resultData.data.content).toEqual(message); }); From 80b324bb1c0958ec59cf595f0769b4983c5851fe Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Mon, 31 Jul 2023 06:31:28 +0530 Subject: [PATCH 26/28] added the substring as well --- src/constants/responses.ts | 5 ++++- src/controllers/verifyCommand.ts | 4 ++-- tests/unit/handlers/verifyCommand.test.ts | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 77c1f3e2..1bdde1c9 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -29,7 +29,10 @@ 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 below ๐Ÿ‘‡ and granting authorization to the Real Dev Squad. This will allow us to manage your Discord data."; + "Please verify your identity by clicking the link below ๐Ÿ‘‡"; + +export const VERIFICATION_SUBSTRING = + "By granting authorization, you agree to permit us to manage your server nickname displayed ONLY in the Real Dev Squad server and to sync your joining data with your user account on our platform."; export const ROLE_FETCH_FAILED = "Oops! We are experiencing an issue fetching roles."; diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 64b61e55..6207558b 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -1,5 +1,5 @@ import config from "../../config/config"; -import { RETRY_COMMAND, VERIFICATION_STRING } from "../constants/responses"; +import { RETRY_COMMAND, VERIFICATION_STRING, VERIFICATION_SUBSTRING } from "../constants/responses"; import { env } from "../typeDefinitions/default.types"; import { discordEphemeralResponse } from "../utils/discordEphemeralResponse"; import { generateUniqueToken } from "../utils/generateUniqueToken"; @@ -24,7 +24,7 @@ export async function verifyCommand( ); if (response?.status === 201 || response?.status === 200) { const verificationSiteURL = config(env).VERIFICATION_SITE_URL; - const message = `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${token}`; + const message = `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${token}\n${VERIFICATION_SUBSTRING}`; return discordEphemeralResponse(message); } else { return discordEphemeralResponse(RETRY_COMMAND); diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts index 04c53884..89330a7e 100644 --- a/tests/unit/handlers/verifyCommand.test.ts +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -1,6 +1,7 @@ import { RETRY_COMMAND, VERIFICATION_STRING, + VERIFICATION_SUBSTRING, } from "../../../src/constants/responses"; import config from "../../../config/config"; import { @@ -58,7 +59,7 @@ describe("verifyCommand", () => { const verificationSiteURL = config(env).VERIFICATION_SITE_URL; const message = - `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}` + `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n${VERIFICATION_SUBSTRING}` expect(resultData.data.content).toEqual(message); }); From d35ee365e8e04e35f499745963091fa34d6d2f12 Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Mon, 31 Jul 2023 06:40:00 +0530 Subject: [PATCH 27/28] format-fix --- src/controllers/verifyCommand.ts | 6 +++++- tests/unit/handlers/verifyCommand.test.ts | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 6207558b..93d7a0b2 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -1,5 +1,9 @@ import config from "../../config/config"; -import { RETRY_COMMAND, VERIFICATION_STRING, VERIFICATION_SUBSTRING } from "../constants/responses"; +import { + RETRY_COMMAND, + VERIFICATION_STRING, + VERIFICATION_SUBSTRING, +} from "../constants/responses"; import { env } from "../typeDefinitions/default.types"; import { discordEphemeralResponse } from "../utils/discordEphemeralResponse"; import { generateUniqueToken } from "../utils/generateUniqueToken"; diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts index 756bcbf0..35dc831b 100644 --- a/tests/unit/handlers/verifyCommand.test.ts +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -58,8 +58,7 @@ describe("verifyCommand", () => { const resultData = JSON.parse(resultText); const verificationSiteURL = config(env).VERIFICATION_SITE_URL; - const message = - `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n${VERIFICATION_SUBSTRING}` + const message = `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n${VERIFICATION_SUBSTRING}`; expect(resultData.data.content).toEqual(message); }); From d8375116b3f79649ef639209892980062f0be76c Mon Sep 17 00:00:00 2001 From: shreya-mishra Date: Fri, 4 Aug 2023 05:23:19 +0530 Subject: [PATCH 28/28] fix te substring --- src/constants/responses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 1bdde1c9..676693dd 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -29,7 +29,7 @@ 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 below ๐Ÿ‘‡"; + "Please verify your discord account by clicking the link below ๐Ÿ‘‡"; export const VERIFICATION_SUBSTRING = "By granting authorization, you agree to permit us to manage your server nickname displayed ONLY in the Real Dev Squad server and to sync your joining data with your user account on our platform.";