generated from nhcarrigan/template
feat: add slash commands and context menu command #16
@@ -95,7 +95,7 @@ export const createIssue = async(
|
||||
const title = interaction.options.getString("title", true);
|
||||
const description = interaction.options.getString("description") ?? "";
|
||||
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
|
||||
try {
|
||||
const augmentedBody = await generateIssueBody(description, title);
|
||||
|
||||
@@ -98,7 +98,7 @@ export const createTask = async(
|
||||
const description = interaction.options.getString("description") ?? "";
|
||||
const priority = interaction.options.getInteger("priority") ?? 3;
|
||||
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
|
||||
try {
|
||||
const augmentedDesc = await generateTaskDescription(description, title);
|
||||
|
||||
@@ -20,7 +20,7 @@ import { logger } from "../utils/logger.js";
|
||||
const forwardToOwner = async(
|
||||
interaction: MessageContextMenuCommandInteraction,
|
||||
): Promise<void> => {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
|
||||
if (interaction.user.id !== ids.users.naomi) {
|
||||
await interaction.editReply("❌ Only Naomi can use this command.");
|
||||
|
||||
@@ -67,7 +67,7 @@ export const onboardMentee = async(
|
||||
const githubUsername = interaction.options.getString("github_username", true);
|
||||
const menteeUser = interaction.options.getUser("mentee", true);
|
||||
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
|
||||
try {
|
||||
const repoUrl = await setupMenteeRepository(amari, githubUsername);
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
type MessageActionRowComponentBuilder,
|
||||
} from "discord.js";
|
||||
import { ids } from "../config/ids.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import type { Amari } from "../interfaces/amari.js";
|
||||
|
||||
const username = "naomilgbt";
|
||||
@@ -91,28 +92,34 @@ export const checkRetroAchievements = async(
|
||||
return;
|
||||
}
|
||||
|
||||
const auth = buildAuthorization({ username, webApiKey });
|
||||
try {
|
||||
const auth = buildAuthorization({ username, webApiKey });
|
||||
|
||||
const recentAchievements = await getUserRecentAchievements(auth, {
|
||||
recentMinutes: 10,
|
||||
username: username,
|
||||
});
|
||||
|
||||
if (recentAchievements.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = amari.discord.channels.cache.get(ids.channels.gaming)
|
||||
?? await amari.discord.channels.fetch(ids.channels.gaming);
|
||||
|
||||
if (channel?.isSendable() !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(recentAchievements.map(async(achievement) => {
|
||||
await channel.send({
|
||||
components: constructComponents(achievement),
|
||||
flags: [ MessageFlags.IsComponentsV2 ],
|
||||
const recentAchievements = await getUserRecentAchievements(auth, {
|
||||
recentMinutes: 10,
|
||||
username: username,
|
||||
});
|
||||
}));
|
||||
|
||||
if (recentAchievements.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = amari.discord.channels.cache.get(ids.channels.gaming)
|
||||
?? await amari.discord.channels.fetch(ids.channels.gaming);
|
||||
|
||||
if (channel?.isSendable() !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(recentAchievements.map(async(achievement) => {
|
||||
await channel.send({
|
||||
components: constructComponents(achievement),
|
||||
flags: [ MessageFlags.IsComponentsV2 ],
|
||||
});
|
||||
}));
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await logger.error("checkRetroAchievements module", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,25 +20,31 @@ export const logMenteeJoin = async(
|
||||
amari: Amari,
|
||||
member: GuildMember,
|
||||
): Promise<void> => {
|
||||
const request = await fetch(`https://forms.nhcarrigan.com/api/database/rows/table/756/?user_field_names=true&search=${member.id}`, { headers: {
|
||||
authorization: `Token ${process.env.BASEROW_TOKEN ?? "huh"}`,
|
||||
} });
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Fetch accepts no generic here.
|
||||
const response = await request.json() as MentorshipRow;
|
||||
try {
|
||||
const request = await fetch(`https://forms.nhcarrigan.com/api/database/rows/table/756/?user_field_names=true&search=${member.id}`, { headers: {
|
||||
authorization: `Token ${process.env.BASEROW_TOKEN ?? "huh"}`,
|
||||
} });
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Fetch accepts no generic here.
|
||||
const response = await request.json() as MentorshipRow;
|
||||
|
||||
if (response.count <= 0) {
|
||||
return;
|
||||
if (response.count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = amari.discord.channels.cache.get(ids.channels.general)
|
||||
?? await amari.discord.channels.fetch(ids.channels.general);
|
||||
|
||||
if (channel?.isSendable() !== true) {
|
||||
await logger.log(
|
||||
"warn",
|
||||
"General channel does not exist or is not sendable.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
await logger.metric("processed_mentee_join", 1, { user: member.id });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await logger.error("logMenteeJoin module", error);
|
||||
}
|
||||
}
|
||||
|
||||
const channel = amari.discord.channels.cache.get(ids.channels.general)
|
||||
?? await amari.discord.channels.fetch(ids.channels.general);
|
||||
|
||||
if (channel?.isSendable() !== true) {
|
||||
await logger.log(
|
||||
"warn",
|
||||
"General channel does not exist or is not sendable.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
await logger.metric("processed_mentee_join", 1, { user: member.id });
|
||||
};
|
||||
|
||||
@@ -21,13 +21,78 @@ const isPull = (body: GithubPayload): body is PullRequestCreated => {
|
||||
return "pull_request" in body;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a newly opened GitHub issue by auto-assigning Naomi.
|
||||
* @param amari - Amari's instance.
|
||||
* @param body - The parsed issue webhook payload.
|
||||
*/
|
||||
const handleIssueOpened = async(
|
||||
amari: Amari,
|
||||
body: IssueCreated,
|
||||
): Promise<void> => {
|
||||
await logger.log("info", "Processing new issue");
|
||||
const { issue, repository } = body;
|
||||
const { number, user } = issue;
|
||||
const { owner, name } = repository;
|
||||
try {
|
||||
await amari.github.rest.issues.addAssignees({
|
||||
assignees: [ "naomi-lgbt" ],
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Github SDK requirement.
|
||||
issue_number: number,
|
||||
owner: owner.login,
|
||||
repo: name,
|
||||
});
|
||||
await logger.metric("processed_github_event", 1, {
|
||||
action: "opened",
|
||||
event: "issue",
|
||||
user: user.login,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await logger.error("processGitHubEvent module", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a newly opened GitHub pull request by requesting Naomi's review.
|
||||
* @param amari - Amari's instance.
|
||||
* @param body - The parsed pull request webhook payload.
|
||||
*/
|
||||
const handlePrOpened = async(
|
||||
amari: Amari,
|
||||
body: PullRequestCreated,
|
||||
): Promise<void> => {
|
||||
const { pull_request: pr, repository } = body;
|
||||
const { number, user } = pr;
|
||||
await logger.log("info", "Processing new PR");
|
||||
const { owner, name } = repository;
|
||||
try {
|
||||
await amari.github.rest.pulls.requestReviewers({
|
||||
owner: owner.login,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Github SDK requirement.
|
||||
pull_number: number,
|
||||
repo: name,
|
||||
reviewers: [ "naomi-lgbt" ],
|
||||
});
|
||||
await logger.metric("processed_github_event", 1, {
|
||||
action: "opened",
|
||||
event: "pull_request",
|
||||
user: user.login,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await logger.error("processGitHubEvent module", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a payload from a GitHub webhook.
|
||||
* @param amari - Amari's instance.
|
||||
* @param request - The Fastify request payload.
|
||||
* @param response - The Fastify reply class.
|
||||
*/
|
||||
// eslint-disable-next-line max-statements, max-lines-per-function -- STFU.
|
||||
export const processGithubEvent = async(
|
||||
amari: Amari,
|
||||
request: FastifyRequest<{
|
||||
@@ -58,40 +123,10 @@ export const processGithubEvent = async(
|
||||
const { action } = request.body;
|
||||
await response.status(200).send({ message: "Payload received!" });
|
||||
if (action === "opened" && event === "issues" && isIssue(request.body)) {
|
||||
await logger.log("info", "Processing new issue");
|
||||
const { issue, repository } = request.body;
|
||||
const { number, user } = issue;
|
||||
const { owner, name } = repository;
|
||||
await amari.github.rest.issues.addAssignees({
|
||||
assignees: [ "naomi-lgbt" ],
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Github SDK requirement.
|
||||
issue_number: number,
|
||||
owner: owner.login,
|
||||
repo: name,
|
||||
});
|
||||
await logger.metric("processed_github_event", 1, {
|
||||
action: "opened",
|
||||
event: "issue",
|
||||
user: user.login,
|
||||
});
|
||||
await handleIssueOpened(amari, request.body);
|
||||
return;
|
||||
}
|
||||
if (action === "opened" && event === "pull_request" && isPull(request.body)) {
|
||||
const { pull_request: pr, repository } = request.body;
|
||||
const { number, user } = pr;
|
||||
await logger.log("info", "Processing new PR");
|
||||
await logger.metric("processed_github_event", 1, {
|
||||
action: "opened",
|
||||
event: "pull_request",
|
||||
user: user.login,
|
||||
});
|
||||
const { owner, name } = repository;
|
||||
await amari.github.rest.pulls.requestReviewers({
|
||||
owner: owner.login,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Github SDK requirement.
|
||||
pull_number: number,
|
||||
repo: name,
|
||||
reviewers: [ "naomi-lgbt" ],
|
||||
});
|
||||
await handlePrOpened(amari, request.body);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,20 +34,21 @@ export const processMentorshipRole = async(
|
||||
return;
|
||||
}
|
||||
|
||||
const channel
|
||||
= amari.discord.channels.cache.get(ids.channels.menteeChat)
|
||||
?? await amari.discord.channels.fetch(ids.channels.menteeChat);
|
||||
try {
|
||||
const channel
|
||||
= amari.discord.channels.cache.get(ids.channels.menteeChat)
|
||||
?? await amari.discord.channels.fetch(ids.channels.menteeChat);
|
||||
|
||||
if (channel?.isSendable() !== true) {
|
||||
await logger.log(
|
||||
"warn",
|
||||
"Mentee Chat channel does not exist or is not sendable.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (channel?.isSendable() !== true) {
|
||||
await logger.log(
|
||||
"warn",
|
||||
"Mentee Chat channel does not exist or is not sendable.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.send({
|
||||
content: `Hey <@${updatedMember.id}>~! Welcome to the mentorship programme!
|
||||
await channel.send({
|
||||
content: `Hey <@${updatedMember.id}>~! Welcome to the mentorship programme!
|
||||
|
||||
Please ping (mention, tag) Naomi in this channel with the following template to get started:
|
||||
\`\`\`
|
||||
@@ -56,9 +57,14 @@ First name:
|
||||
Last name:
|
||||
\`\`\`
|
||||
Then read our [mentorship wiki](<https://docs.nhcarrigan.com/mentorship/00-faq/>) for the next steps!`,
|
||||
});
|
||||
addWelcomedMentee(updatedMember.id);
|
||||
await logger.metric("processed_mentorship_role", 1, {
|
||||
user: updatedMember.id,
|
||||
});
|
||||
});
|
||||
addWelcomedMentee(updatedMember.id);
|
||||
await logger.metric("processed_mentorship_role", 1, {
|
||||
user: updatedMember.id,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await logger.error("processMentorshipRole module", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user