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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -26,13 +28,15 @@ 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,
VERIFICATION_SITE_URL: STAGING_VERIFICATION_SITE_URL,
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,
Expand All @@ -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,
},
};

Expand Down
19 changes: 19 additions & 0 deletions src/constants/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions src/constants/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.";
Expand Down
4 changes: 4 additions & 0 deletions src/constants/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
8 changes: 8 additions & 0 deletions src/controllers/baseHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
OOO,
USER,
REMOVE,
GROUP_INVITE,
} from "../constants/commands";
import { updateNickName } from "../utils/updateNickname";
import { discordEphemeralResponse } from "../utils/discordEphemeralResponse";
Expand All @@ -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,
Expand Down Expand Up @@ -156,6 +158,12 @@ export async function baseHandler(
const data = message.data?.options as Array<messageRequestDataOptions>;
return await userCommand(data[0].value, env);
}

case getCommandName(GROUP_INVITE): {
const data = message.data?.options as Array<messageRequestDataOptions>;

return await groupInvite(data[0].value, data[1].value, env);
}
default: {
return commandNotFound();
}
Expand Down
26 changes: 26 additions & 0 deletions src/controllers/groupInvite.ts
Original file line number Diff line number Diff line change
@@ -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<JSONResponse> {
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}`
);
}
2 changes: 2 additions & 0 deletions src/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
OOO,
USER,
REMOVE,
GROUP_INVITE,
} from "./constants/commands";
import { config } from "dotenv";
import { DISCORD_BASE_URL } from "./constants/urls";
Expand Down Expand Up @@ -39,6 +40,7 @@ async function registerGuildCommands(
NOTIFY_OVERDUE,
NOTIFY_ONBOARDING,
REMOVE,
GROUP_INVITE,
];

try {
Expand Down
1 change: 1 addition & 0 deletions src/typeDefinitions/default.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions src/typeDefinitions/group.types.d.ts
Original file line number Diff line number Diff line change
@@ -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[];
};
23 changes: 23 additions & 0 deletions src/utils/fetchDiscordGroups.ts
Original file line number Diff line number Diff line change
@@ -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<GroupResponseType> {
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 };
46 changes: 46 additions & 0 deletions tests/fixtures/groups.ts
Original file line number Diff line number Diff line change
@@ -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,
},
],
};
40 changes: 40 additions & 0 deletions tests/unit/handlers/groupInvite.test.ts
Original file line number Diff line number Diff line change
@@ -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());
});
});
Loading