From 71db764e2fb5f9c9854d8e28d9d75aad77f9a664 Mon Sep 17 00:00:00 2001 From: Prashant Peeyush Date: Thu, 26 Sep 2024 21:58:23 +0530 Subject: [PATCH 1/5] corrected user details formatting (#254) --- src/utils/formatUserDetails.ts | 46 +++++++++++++++++---- tests/fixtures/user.ts | 2 + tests/unit/utils/formatUserDetails.test.ts | 48 ++++++++++++++-------- 3 files changed, 70 insertions(+), 26 deletions(-) diff --git a/src/utils/formatUserDetails.ts b/src/utils/formatUserDetails.ts index ce345959..de80aacd 100644 --- a/src/utils/formatUserDetails.ts +++ b/src/utils/formatUserDetails.ts @@ -1,6 +1,6 @@ import { UserResponseType } from "../typeDefinitions/rdsUser"; -export function convertTimeStamp(userDetails: UserResponseType) { +export function convertTimeStamp(userDetails: UserResponseType, flag: boolean) { const timestamp = userDetails.user?.discordJoinedAt; if (timestamp) { @@ -9,27 +9,55 @@ export function convertTimeStamp(userDetails: UserResponseType) { const day = String(date.getDate()).padStart(2, "0"); const month = String(date.getMonth() + 1).padStart(2, "0"); const year = date.getFullYear(); + if (flag) { + const monthName = date.toLocaleString("default", { month: "short" }); + const formattedDate = `${day} ${monthName}, ${year}`; + return formattedDate; + } const formattedDate = `${day}/${month}/${year}`; return formattedDate; } return "N/A"; } +export function convertEpochToDate(timestamp: number | undefined) { + if (timestamp) { + const date = new Date(timestamp); + + const day = String(date.getDate()).padStart(2, "0"); + const month = date.toLocaleString("default", { month: "short" }); + const year = date.getFullYear(); + const formattedDate = `${day} ${month}, ${year}`; + + return formattedDate; + } + + return "N/A"; +} export function formatUserDetails( userDetails: UserResponseType, flag: boolean ) { - const convertedTimestamp = convertTimeStamp(userDetails); - - const userId = `**User Id :** ${userDetails.user?.id}`; - const userName = `**User Name :** ${userDetails.user?.username}`; - const userFullName = `**Full Name :** ${userDetails.user?.first_name} ${userDetails.user?.last_name}`; - const userState = `**State :** ${userDetails.user?.state}`; - const discordJoinedAt = `**Joined Server on :** ${convertedTimestamp}`; + const convertedTimestamp = convertTimeStamp(userDetails, flag); + const accountCreationDate = convertEpochToDate(userDetails.user?.created_at); + + const userId = " ".repeat(30) + `**Id:** ${userDetails.user?.id}`; + const userName = + " ".repeat(13) + `**Username:** ${userDetails.user?.username}`; + const userFullName = `${ + flag ? " ".repeat(13) + "**Full Name:**" : "**Full Name :**" + } ${userDetails.user?.first_name} ${userDetails.user?.last_name}`; + const userState = `${flag ? " ".repeat(23) + "**State:**" : "**State :**"} ${ + userDetails.user?.state + }`; + const discordJoinedAt = `${ + flag ? " ".repeat(4) + "**Joined Discord:**" : "**Joined Server on :**" + } ${convertedTimestamp}`; + const accountCreated = `**Account Created:** ${accountCreationDate}`; if (!flag) return `## User Details\n${userFullName}\n${userState}\n${discordJoinedAt}`; - return `## User Details\n${userId}\n${userName}\n${userFullName}\n${userState}\n${discordJoinedAt}`; + return `## User Details\n${userName}\n${userState}\n\n${userFullName}\n${userId}\n\n${accountCreated}\n${discordJoinedAt}`; } diff --git a/tests/fixtures/user.ts b/tests/fixtures/user.ts index ee14d5e9..ed163ad7 100644 --- a/tests/fixtures/user.ts +++ b/tests/fixtures/user.ts @@ -2,6 +2,7 @@ export const user = { id: "iODXB6ns8jaZB9p0XlBw", incompleteUserDetails: false, discordJoinedAt: "2023-08-08T11:40:42.522000+00:00", + created_at: 1692748800000, discordId: "858838385330487336", github_display_name: "John Doe", updated_at: 1694888822719, @@ -178,6 +179,7 @@ export const userWithoutDiscordJoinedAt = { id: "DWcTUhbC5lRXfDjZRp06", incompleteUserDetails: false, discordJoinedAt: "", + created_at: 1692748800000, discordId: "504855562094247953", github_display_name: "John Doe", updated_at: 1694888822719, diff --git a/tests/unit/utils/formatUserDetails.test.ts b/tests/unit/utils/formatUserDetails.test.ts index 35b26f2b..5863991c 100644 --- a/tests/unit/utils/formatUserDetails.test.ts +++ b/tests/unit/utils/formatUserDetails.test.ts @@ -4,7 +4,10 @@ import { userResponse, userWithoutDiscordJoinedAtResponse, } from "../../fixtures/user"; -import { convertTimeStamp } from "../../../src/utils/formatUserDetails"; +import { + convertTimeStamp, + convertEpochToDate, +} from "../../../src/utils/formatUserDetails"; describe("formatUserDetails function", () => { it("Should return a string", () => { @@ -16,15 +19,18 @@ describe("formatUserDetails function", () => { it("should format user details correctly in dev mode", () => { const formattedDetails = formatUserDetails(userResponse, true).trim(); - const userId = `**User Id :** iODXB6ns8jaZB9p0XlBw`; - const userName = `**User Name :** johndoe`; - const userFullName = `**Full Name :** John Doe`; - const userState = `**State :** ACTIVE`; - const discordJoinedAt = `**Joined Server on :** ${convertTimeStamp( - userResponse + const userId = " ".repeat(30) + `**Id:** iODXB6ns8jaZB9p0XlBw`; + const userName = " ".repeat(13) + `**Username:** johndoe`; + const userFullName = " ".repeat(13) + `**Full Name:** John Doe`; + const userState = " ".repeat(23) + `**State:** ACTIVE`; + const discordJoinedAt = + " ".repeat(4) + + `**Joined Discord:** ${convertTimeStamp(userResponse, true)}`; + const accountCreated = `**Account Created:** ${convertEpochToDate( + userResponse.user.created_at )}`; - const expectedFormattedDetails = `## User Details\n${userId}\n${userName}\n${userFullName}\n${userState}\n${discordJoinedAt}`; + const expectedFormattedDetails = `## User Details\n${userName}\n${userState}\n\n${userFullName}\n${userId}\n\n${accountCreated}\n${discordJoinedAt}`; expect(formattedDetails).toEqual(expectedFormattedDetails); }); @@ -34,7 +40,8 @@ describe("formatUserDetails function", () => { const userFullName = `**Full Name :** John Doe`; const userState = `**State :** ACTIVE`; const discordJoinedAt = `**Joined Server on :** ${convertTimeStamp( - userResponse + userResponse, + false )}`; const expectedFormattedDetails = `## User Details\n${userFullName}\n${userState}\n${discordJoinedAt}`; @@ -47,15 +54,21 @@ describe("formatUserDetails function", () => { true ).trim(); - const userId = `**User Id :** DWcTUhbC5lRXfDjZRp06`; - const userName = `**User Name :** johndoe`; - const userFullName = `**Full Name :** John Doe`; - const userState = `**State :** IDLE`; - const discordJoinedAt = `**Joined Server on :** ${convertTimeStamp( - userWithoutDiscordJoinedAtResponse + const userId = " ".repeat(30) + `**Id:** DWcTUhbC5lRXfDjZRp06`; + const userName = " ".repeat(13) + `**Username:** johndoe`; + const userFullName = " ".repeat(13) + `**Full Name:** John Doe`; + const userState = " ".repeat(23) + `**State:** IDLE`; + const discordJoinedAt = + " ".repeat(4) + + `**Joined Discord:** ${convertTimeStamp( + userWithoutDiscordJoinedAtResponse, + true + )}`; + const accountCreated = `**Account Created:** ${convertEpochToDate( + userResponse.user.created_at )}`; - const expectedFormattedDetails = `## User Details\n${userId}\n${userName}\n${userFullName}\n${userState}\n${discordJoinedAt}`; + const expectedFormattedDetails = `## User Details\n${userName}\n${userState}\n\n${userFullName}\n${userId}\n\n${accountCreated}\n${discordJoinedAt}`; expect(formattedDetails).toEqual(expectedFormattedDetails); }); @@ -68,7 +81,8 @@ describe("formatUserDetails function", () => { const userFullName = `**Full Name :** John Doe`; const userState = `**State :** IDLE`; const discordJoinedAt = `**Joined Server on :** ${convertTimeStamp( - userWithoutDiscordJoinedAtResponse + userWithoutDiscordJoinedAtResponse, + false )}`; const expectedFormattedDetails = `## User Details\n${userFullName}\n${userState}\n${discordJoinedAt}`; From e111a1384f5672e1f802f5ab8b4a9a6c7b9caeea Mon Sep 17 00:00:00 2001 From: Pallab Sonowal Date: Tue, 1 Oct 2024 22:17:44 +0530 Subject: [PATCH 2/5] Add group invite slash command (#259) * add group invite command * add test for group invite --- config/config.ts | 5 +++ src/constants/commands.ts | 19 ++++++++++ src/constants/responses.ts | 2 ++ src/constants/urls.ts | 4 +++ src/controllers/baseHandler.ts | 8 +++++ src/controllers/groupInvite.ts | 26 ++++++++++++++ src/register.ts | 2 ++ src/typeDefinitions/default.types.d.ts | 1 + src/typeDefinitions/group.types.d.ts | 18 ++++++++++ src/utils/fetchDiscordGroups.ts | 23 +++++++++++++ tests/fixtures/groups.ts | 46 +++++++++++++++++++++++++ tests/unit/handlers/groupInvite.test.ts | 40 +++++++++++++++++++++ 12 files changed, 194 insertions(+) create mode 100644 src/controllers/groupInvite.ts create mode 100644 src/typeDefinitions/group.types.d.ts create mode 100644 src/utils/fetchDiscordGroups.ts create mode 100644 tests/fixtures/groups.ts create mode 100644 tests/unit/handlers/groupInvite.test.ts diff --git a/config/config.ts b/config/config.ts index e594a218..1c95bcad 100644 --- a/config/config.ts +++ b/config/config.ts @@ -11,6 +11,8 @@ import { STAGING_RDS_TRACKING_CHANNEL_URL, RDS_STATUS_SITE_URL, RDS_STAGING_STATUS_SITE_URL, + RDS_DASHBOARD_SITE_URL, + RDS_STAGING_DASHBOARD_SITE_URL, } from "../src/constants/urls"; import { DISCORD_PROFILE_SERVICE_HELP_GROUP, @@ -26,6 +28,7 @@ const config = (env: env) => { TRACKING_CHANNEL_URL: RDS_TRACKING_CHANNEL_URL, PROFILE_SERVICE_HELP_GROUP_ID: DISCORD_PROFILE_SERVICE_HELP_GROUP, RDS_STATUS_SITE_URL: RDS_STATUS_SITE_URL, + DASHBOARD_SITE_URL: RDS_DASHBOARD_SITE_URL, }, staging: { RDS_BASE_API_URL: RDS_BASE_STAGING_API_URL, @@ -33,6 +36,7 @@ const config = (env: env) => { TRACKING_CHANNEL_URL: STAGING_RDS_TRACKING_CHANNEL_URL, PROFILE_SERVICE_HELP_GROUP_ID: DISCORD_PROFILE_SERVICE_STAGING_HELP_GROUP, RDS_STATUS_SITE_URL: RDS_STAGING_STATUS_SITE_URL, + DASHBOARD_SITE_URL: RDS_STAGING_DASHBOARD_SITE_URL, }, default: { RDS_BASE_API_URL: RDS_BASE_DEVELOPMENT_API_URL, @@ -41,6 +45,7 @@ const config = (env: env) => { PROFILE_SERVICE_HELP_GROUP_ID: DISCORD_PROFILE_SERVICE_DEVELOPMENT_HELP_GROUP, RDS_STATUS_SITE_URL: RDS_STATUS_SITE_URL, + DASHBOARD_SITE_URL: RDS_DASHBOARD_SITE_URL, }, }; diff --git a/src/constants/commands.ts b/src/constants/commands.ts index d2288db1..47a83d65 100644 --- a/src/constants/commands.ts +++ b/src/constants/commands.ts @@ -9,6 +9,25 @@ export const VERIFY = { "Generate a link with user specific token to link with RDS backend.", }; +export const GROUP_INVITE = { + name: "group-invite", + description: "Send group invite link for the user.", + options: [ + { + name: "name", + description: "User to send group invite link", + type: 6, + required: true, + }, + { + name: "role", + description: "Role you want to invite to the user", + type: 8, + required: true, + }, + ], +}; + export const MENTION_EACH = { name: "mention-each", description: "mention each user with this role", diff --git a/src/constants/responses.ts b/src/constants/responses.ts index bff6a2c0..59a04ff9 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -65,6 +65,8 @@ export const FAILED_TO_FETCH_TASKS = `Failed to fetch tasks for **{{assignee}}** export const USER_NOT_FOUND = `User Not Found`; export const USER_STATUS_NOT_FOUND = "No Status Found"; +export const FAILED_TO_FETCH_DISCORD_GROUPS = "Failed to fetch discord groups"; + export const OVERDUE_DEFAULT_MESSAGE = "You have overdue tasks."; export const OVERDUE_CUSTOM_MESSAGE = "Please be aware that you currently have tasks that are overdue or due within the next {{days}} day. If you require additional time to complete these tasks, kindly submit an extension request."; diff --git a/src/constants/urls.ts b/src/constants/urls.ts index e60a02d0..a86b355f 100644 --- a/src/constants/urls.ts +++ b/src/constants/urls.ts @@ -22,3 +22,7 @@ export const DEVELOPMENT_RDS_TRACKING_CHANNEL_URL = export const RDS_STATUS_SITE_URL = "https://status.realdevsquad.com"; export const RDS_STAGING_STATUS_SITE_URL = "https://staging-status.realdevsquad.com"; + +export const RDS_DASHBOARD_SITE_URL = "https://dashboard.realdevsquad.com"; +export const RDS_STAGING_DASHBOARD_SITE_URL = + "https://staging-dashboard.realdevsquad.com"; diff --git a/src/controllers/baseHandler.ts b/src/controllers/baseHandler.ts index 96cb858f..bd3ad325 100644 --- a/src/controllers/baseHandler.ts +++ b/src/controllers/baseHandler.ts @@ -28,6 +28,7 @@ import { OOO, USER, REMOVE, + GROUP_INVITE, } from "../constants/commands"; import { updateNickName } from "../utils/updateNickname"; import { discordEphemeralResponse } from "../utils/discordEphemeralResponse"; @@ -42,6 +43,7 @@ import { } from "../constants/responses"; import { DevFlag } from "../typeDefinitions/filterUsersByRole"; import { kickEachUser } from "./kickEachUser"; +import { groupInvite } from "./groupInvite"; export async function baseHandler( message: discordMessageRequest, @@ -159,6 +161,12 @@ export async function baseHandler( ) as unknown as DevFlag; return await userCommand(data[0].value, env, dev); } + + case getCommandName(GROUP_INVITE): { + const data = message.data?.options as Array; + + return await groupInvite(data[0].value, data[1].value, env); + } default: { return commandNotFound(); } diff --git a/src/controllers/groupInvite.ts b/src/controllers/groupInvite.ts new file mode 100644 index 00000000..65b91f82 --- /dev/null +++ b/src/controllers/groupInvite.ts @@ -0,0 +1,26 @@ +import config from "../../config/config"; +import { env } from "../typeDefinitions/default.types"; +import { discordTextResponse } from "../utils/discordResponse"; +import * as DiscordGroups from "../utils/fetchDiscordGroups"; +import JSONResponse from "../utils/JsonResponse"; + +export async function groupInvite( + userId: string, + roleId: string, + env: env +): Promise { + const response = await DiscordGroups.fetchDiscordGroups(env); + const group = response.groups.find((group) => group.roleid === roleId); + + if (!group) { + return discordTextResponse(`<@&${roleId}> is not a valid group.`); + } + + const groupName = group.rolename.replace(/^group-/, ""); + + return discordTextResponse( + `<@${userId}> join the group <@&${roleId}> via the link below:\n ${ + config(env).DASHBOARD_SITE_URL + }/groups/?dev=true&name=${groupName}` + ); +} diff --git a/src/register.ts b/src/register.ts index c7ca0263..6bd22737 100644 --- a/src/register.ts +++ b/src/register.ts @@ -9,6 +9,7 @@ import { OOO, USER, REMOVE, + GROUP_INVITE, } from "./constants/commands"; import { config } from "dotenv"; import { DISCORD_BASE_URL } from "./constants/urls"; @@ -39,6 +40,7 @@ async function registerGuildCommands( NOTIFY_OVERDUE, NOTIFY_ONBOARDING, REMOVE, + GROUP_INVITE, ]; try { diff --git a/src/typeDefinitions/default.types.d.ts b/src/typeDefinitions/default.types.d.ts index 3ae4f36b..b1828b20 100644 --- a/src/typeDefinitions/default.types.d.ts +++ b/src/typeDefinitions/default.types.d.ts @@ -7,6 +7,7 @@ export interface environment { } export interface variables { + DASHBOARD_SITE_URL: string; RDS_BASE_API_URL: string; VERIFICATION_SITE_URL: string; TRACKING_CHANNEL_URL: string; diff --git a/src/typeDefinitions/group.types.d.ts b/src/typeDefinitions/group.types.d.ts new file mode 100644 index 00000000..a10c92a4 --- /dev/null +++ b/src/typeDefinitions/group.types.d.ts @@ -0,0 +1,18 @@ +export type GroupType = { + id: string; + date: { + _seconds: number; + _nanoseconds: number; + }; + createdBy: string; + rolename: string; + roleid: string; + description: string; + memberCount: number; + isMember: boolean; +}; + +export type GroupResponseType = { + message: string; + groups: GroupType[]; +}; diff --git a/src/utils/fetchDiscordGroups.ts b/src/utils/fetchDiscordGroups.ts new file mode 100644 index 00000000..7469bace --- /dev/null +++ b/src/utils/fetchDiscordGroups.ts @@ -0,0 +1,23 @@ +import config from "../../config/config"; +import { FAILED_TO_FETCH_DISCORD_GROUPS } from "../constants/responses"; +import { env } from "../typeDefinitions/default.types"; +import { GroupResponseType } from "../typeDefinitions/group.types"; + +async function fetchDiscordGroups(env: env): Promise { + try { + const url = `${config(env).RDS_BASE_API_URL}/discord-actions/groups`; + const response = await fetch(url); + + if (!response.ok) { + throw new Error(FAILED_TO_FETCH_DISCORD_GROUPS); + } + + const responseData: GroupResponseType = await response.json(); + return responseData; + } catch (error) { + console.error("An error occurred while fetching discord groups:", error); + throw error; + } +} + +export { fetchDiscordGroups }; diff --git a/tests/fixtures/groups.ts b/tests/fixtures/groups.ts new file mode 100644 index 00000000..84d560d4 --- /dev/null +++ b/tests/fixtures/groups.ts @@ -0,0 +1,46 @@ +import { GroupResponseType } from "../../src/typeDefinitions/group.types"; + +export const groups: GroupResponseType = { + message: "Roles fetched successfully!", + groups: [ + { + id: "27EdauP9UmxCTgAMDPpl", + date: { + _seconds: 1719334613, + _nanoseconds: 934000000, + }, + createdBy: "zXQpimWaGWOFF2sLyrFt", + rolename: "group-testing 3", + roleid: "1255205109340573782", + description: "for testing", + memberCount: 0, + isMember: false, + }, + { + id: "ELjCeNZxhHupn8qU5pWI", + date: { + _seconds: 1718771669, + _nanoseconds: 27000000, + }, + createdBy: "zXQpimWaGWOFF2sLyrFt", + rolename: "group-testing", + roleid: "1252843931306164298", + description: "for testing", + memberCount: 0, + isMember: false, + }, + { + id: "tO4vZe5CC690yOb9Txlh", + date: { + _seconds: 1718771969, + _nanoseconds: 680000000, + }, + createdBy: "zXQpimWaGWOFF2sLyrFt", + rolename: "group-testinge", + roleid: "1252845191472087050", + description: "", + memberCount: 0, + isMember: false, + }, + ], +}; diff --git a/tests/unit/handlers/groupInvite.test.ts b/tests/unit/handlers/groupInvite.test.ts new file mode 100644 index 00000000..534ecfa9 --- /dev/null +++ b/tests/unit/handlers/groupInvite.test.ts @@ -0,0 +1,40 @@ +import { environment } from "../../fixtures/config"; +import * as DiscordGroups from "../../../src/utils/fetchDiscordGroups"; +import JSONResponse from "../../../src/utils/JsonResponse"; +import { groupInvite } from "../../../src/controllers/groupInvite"; +import { groups } from "../../fixtures/groups"; +import { discordTextResponse } from "../../../src/utils/discordResponse"; + +describe("Test /group-invite command", () => { + beforeEach(() => { + jest + .spyOn(DiscordGroups, "fetchDiscordGroups") + .mockImplementation(() => Promise.resolve(groups)); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("Should be an instance of JSONResponse", async () => { + const response = await groupInvite( + "1", + groups.groups[0].roleid, + environment[0] + ); + + expect(response).toBeInstanceOf(JSONResponse); + }); + + it("Should return a discordTextResponse if group is not found", async () => { + const invalidRoleId = "invalidRoleId"; + const expectedResponse = discordTextResponse( + `<@&${invalidRoleId}> is not a valid group.` + ); + + const response = await groupInvite("1", invalidRoleId, environment[0]); + + expect(await response.json()).toEqual(await expectedResponse.json()); + }); +}); From 12b1a7bfdb68290dd685420167e8e90d61ff4cee Mon Sep 17 00:00:00 2001 From: Pallab Sonowal Date: Thu, 3 Oct 2024 00:30:23 +0530 Subject: [PATCH 3/5] change discord group fetching logic (#261) * fix discord group not working * fix tests --- src/constants/responses.ts | 3 +- src/controllers/groupInvite.ts | 9 ++--- src/typeDefinitions/group.types.d.ts | 18 +-------- src/utils/fetchDiscordGroupById.ts | 34 ++++++++++++++++ src/utils/fetchDiscordGroups.ts | 23 ----------- tests/fixtures/groups.ts | 53 +++++-------------------- tests/unit/handlers/groupInvite.test.ts | 29 ++++++-------- 7 files changed, 64 insertions(+), 105 deletions(-) create mode 100644 src/utils/fetchDiscordGroupById.ts delete mode 100644 src/utils/fetchDiscordGroups.ts diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 59a04ff9..92dd8e2f 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -65,7 +65,8 @@ export const FAILED_TO_FETCH_TASKS = `Failed to fetch tasks for **{{assignee}}** export const USER_NOT_FOUND = `User Not Found`; export const USER_STATUS_NOT_FOUND = "No Status Found"; -export const FAILED_TO_FETCH_DISCORD_GROUPS = "Failed to fetch discord groups"; +export const FAILED_TO_FETCH_DISCORD_GUILD_ROLE = + "Failed to fetch discord guild role"; export const OVERDUE_DEFAULT_MESSAGE = "You have overdue tasks."; export const OVERDUE_CUSTOM_MESSAGE = diff --git a/src/controllers/groupInvite.ts b/src/controllers/groupInvite.ts index 65b91f82..fc8fb0dc 100644 --- a/src/controllers/groupInvite.ts +++ b/src/controllers/groupInvite.ts @@ -1,7 +1,7 @@ import config from "../../config/config"; import { env } from "../typeDefinitions/default.types"; import { discordTextResponse } from "../utils/discordResponse"; -import * as DiscordGroups from "../utils/fetchDiscordGroups"; +import * as DiscordGroups from "../utils/fetchDiscordGroupById"; import JSONResponse from "../utils/JsonResponse"; export async function groupInvite( @@ -9,14 +9,13 @@ export async function groupInvite( roleId: string, env: env ): Promise { - const response = await DiscordGroups.fetchDiscordGroups(env); - const group = response.groups.find((group) => group.roleid === roleId); + const group = await DiscordGroups.fetchDiscordGroupById(roleId, env); - if (!group) { + if (!group.name.startsWith("group-")) { return discordTextResponse(`<@&${roleId}> is not a valid group.`); } - const groupName = group.rolename.replace(/^group-/, ""); + const groupName = group.name.replace(/^group-/, ""); return discordTextResponse( `<@${userId}> join the group <@&${roleId}> via the link below:\n ${ diff --git a/src/typeDefinitions/group.types.d.ts b/src/typeDefinitions/group.types.d.ts index a10c92a4..ba52bd91 100644 --- a/src/typeDefinitions/group.types.d.ts +++ b/src/typeDefinitions/group.types.d.ts @@ -1,18 +1,4 @@ -export type GroupType = { +export type DiscordGuildRole = { + name: string; id: string; - date: { - _seconds: number; - _nanoseconds: number; - }; - createdBy: string; - rolename: string; - roleid: string; - description: string; - memberCount: number; - isMember: boolean; -}; - -export type GroupResponseType = { - message: string; - groups: GroupType[]; }; diff --git a/src/utils/fetchDiscordGroupById.ts b/src/utils/fetchDiscordGroupById.ts new file mode 100644 index 00000000..cf681e6c --- /dev/null +++ b/src/utils/fetchDiscordGroupById.ts @@ -0,0 +1,34 @@ +import { FAILED_TO_FETCH_DISCORD_GUILD_ROLE } from "../constants/responses"; +import { DISCORD_BASE_URL } from "../constants/urls"; +import { env } from "../typeDefinitions/default.types"; +import { DiscordGuildRole } from "../typeDefinitions/group.types"; +import createDiscordHeaders from "./createDiscordHeaders"; + +async function fetchDiscordGroupById( + roleId: string, + env: env +): Promise { + try { + const url = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles/${roleId}`; + const headers: HeadersInit = createDiscordHeaders({ + token: env.DISCORD_TOKEN, + }); + const options = { + method: "GET", + headers, + }; + const response = await fetch(url, options); + + if (!response.ok) { + throw new Error(FAILED_TO_FETCH_DISCORD_GUILD_ROLE); + } + + const responseData: DiscordGuildRole = await response.json(); + return responseData; + } catch (error) { + console.error("An error occurred while fetching discord groups:", error); + throw error; + } +} + +export { fetchDiscordGroupById }; diff --git a/src/utils/fetchDiscordGroups.ts b/src/utils/fetchDiscordGroups.ts deleted file mode 100644 index 7469bace..00000000 --- a/src/utils/fetchDiscordGroups.ts +++ /dev/null @@ -1,23 +0,0 @@ -import config from "../../config/config"; -import { FAILED_TO_FETCH_DISCORD_GROUPS } from "../constants/responses"; -import { env } from "../typeDefinitions/default.types"; -import { GroupResponseType } from "../typeDefinitions/group.types"; - -async function fetchDiscordGroups(env: env): Promise { - try { - const url = `${config(env).RDS_BASE_API_URL}/discord-actions/groups`; - const response = await fetch(url); - - if (!response.ok) { - throw new Error(FAILED_TO_FETCH_DISCORD_GROUPS); - } - - const responseData: GroupResponseType = await response.json(); - return responseData; - } catch (error) { - console.error("An error occurred while fetching discord groups:", error); - throw error; - } -} - -export { fetchDiscordGroups }; diff --git a/tests/fixtures/groups.ts b/tests/fixtures/groups.ts index 84d560d4..40572528 100644 --- a/tests/fixtures/groups.ts +++ b/tests/fixtures/groups.ts @@ -1,46 +1,11 @@ -import { GroupResponseType } from "../../src/typeDefinitions/group.types"; +import { DiscordGuildRole } from "../../src/typeDefinitions/group.types"; -export const groups: GroupResponseType = { - message: "Roles fetched successfully!", - groups: [ - { - id: "27EdauP9UmxCTgAMDPpl", - date: { - _seconds: 1719334613, - _nanoseconds: 934000000, - }, - createdBy: "zXQpimWaGWOFF2sLyrFt", - rolename: "group-testing 3", - roleid: "1255205109340573782", - description: "for testing", - memberCount: 0, - isMember: false, - }, - { - id: "ELjCeNZxhHupn8qU5pWI", - date: { - _seconds: 1718771669, - _nanoseconds: 27000000, - }, - createdBy: "zXQpimWaGWOFF2sLyrFt", - rolename: "group-testing", - roleid: "1252843931306164298", - description: "for testing", - memberCount: 0, - isMember: false, - }, - { - id: "tO4vZe5CC690yOb9Txlh", - date: { - _seconds: 1718771969, - _nanoseconds: 680000000, - }, - createdBy: "zXQpimWaGWOFF2sLyrFt", - rolename: "group-testinge", - roleid: "1252845191472087050", - description: "", - memberCount: 0, - isMember: false, - }, - ], +export const group: DiscordGuildRole = { + id: "1", + name: "group-frontend", +}; + +export const invalidGroup: DiscordGuildRole = { + id: "2", + name: "invalidRole", }; diff --git a/tests/unit/handlers/groupInvite.test.ts b/tests/unit/handlers/groupInvite.test.ts index 534ecfa9..b9679fc6 100644 --- a/tests/unit/handlers/groupInvite.test.ts +++ b/tests/unit/handlers/groupInvite.test.ts @@ -1,39 +1,36 @@ import { environment } from "../../fixtures/config"; -import * as DiscordGroups from "../../../src/utils/fetchDiscordGroups"; +import * as DiscordGroups from "../../../src/utils/fetchDiscordGroupById"; import JSONResponse from "../../../src/utils/JsonResponse"; import { groupInvite } from "../../../src/controllers/groupInvite"; -import { groups } from "../../fixtures/groups"; +import { group, invalidGroup } from "../../fixtures/groups"; import { discordTextResponse } from "../../../src/utils/discordResponse"; describe("Test /group-invite command", () => { - beforeEach(() => { - jest - .spyOn(DiscordGroups, "fetchDiscordGroups") - .mockImplementation(() => Promise.resolve(groups)); - }); - afterEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); }); it("Should be an instance of JSONResponse", async () => { - const response = await groupInvite( - "1", - groups.groups[0].roleid, - environment[0] - ); + jest + .spyOn(DiscordGroups, "fetchDiscordGroupById") + .mockImplementation(() => Promise.resolve(group)); + + const response = await groupInvite("1", group.id, environment[0]); expect(response).toBeInstanceOf(JSONResponse); }); it("Should return a discordTextResponse if group is not found", async () => { - const invalidRoleId = "invalidRoleId"; + jest + .spyOn(DiscordGroups, "fetchDiscordGroupById") + .mockImplementation(() => Promise.resolve(invalidGroup)); + const expectedResponse = discordTextResponse( - `<@&${invalidRoleId}> is not a valid group.` + `<@&${invalidGroup.id}> is not a valid group.` ); - const response = await groupInvite("1", invalidRoleId, environment[0]); + const response = await groupInvite("1", invalidGroup.id, environment[0]); expect(await response.json()).toEqual(await expectedResponse.json()); }); From bf0f4d22f21a49ed5df19151df4b04f604f0fb8c Mon Sep 17 00:00:00 2001 From: Pallab Sonowal Date: Sat, 5 Oct 2024 23:58:43 +0530 Subject: [PATCH 4/5] use encoded group name (#263) --- src/controllers/groupInvite.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/controllers/groupInvite.ts b/src/controllers/groupInvite.ts index fc8fb0dc..bb4c5cac 100644 --- a/src/controllers/groupInvite.ts +++ b/src/controllers/groupInvite.ts @@ -15,11 +15,12 @@ export async function groupInvite( return discordTextResponse(`<@&${roleId}> is not a valid group.`); } - const groupName = group.name.replace(/^group-/, ""); + const groupName = group.name.replace(/^group-/, "").replace(/-/g, " "); + const encodedGroupName = encodeURIComponent(groupName); return discordTextResponse( `<@${userId}> join the group <@&${roleId}> via the link below:\n ${ config(env).DASHBOARD_SITE_URL - }/groups/?dev=true&name=${groupName}` + }/groups/?dev=true&name=${encodedGroupName}` ); } From 7b8c44d845e83b008ee558346d09f29ea93f21a9 Mon Sep 17 00:00:00 2001 From: pallabez Date: Sun, 6 Oct 2024 00:08:12 +0530 Subject: [PATCH 5/5] fix lint issue --- src/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 63972db4..dba65a39 100644 --- a/src/index.ts +++ b/src/index.ts @@ -66,10 +66,12 @@ router.get("/ankush", async (request, env, ctx: ExecutionContext) => { ctx.waitUntil(send(env)); const url = config(env).TRACKING_CHANNEL_URL; - - return new JSONResponse(`CURRENT_ENVIRONMENT: ${env.CURRENT_ENVIRONMENT}, tracking url - ${url}`, { status: 200 }); -}); + return new JSONResponse( + `CURRENT_ENVIRONMENT: ${env.CURRENT_ENVIRONMENT}, tracking url - ${url}`, + { status: 200 } + ); +}); router.post("/", async (request, env, ctx: ExecutionContext) => { const message: discordMessageRequest = await request.json();