Skip to content

Commit 7d2d89a

Browse files
committed
Add my issues command
1 parent 0211daf commit 7d2d89a

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import {
2+
SlashCommandBuilder,
3+
CommandInteraction,
4+
ActionRowBuilder,
5+
ButtonBuilder,
6+
ButtonStyle,
7+
} from "discord.js";
8+
import { GithubAPI } from "@infrastructure/github";
9+
import logger from "@config/logger";
10+
import githubDiscordMapJson from "../../../../data/githubDiscordMap.json";
11+
import { can } from "../authz";
12+
13+
const githubDiscordMap: { [githubUsername: string]: string } =
14+
githubDiscordMapJson;
15+
16+
export const data = new SlashCommandBuilder()
17+
.setName("my-issues")
18+
.setDescription("List all GitHub project issues assigned to you");
19+
20+
export async function execute(interaction: CommandInteraction) {
21+
if (!can(interaction)) {
22+
await interaction.reply({
23+
content: "You do not have permission to create an issue.",
24+
ephemeral: true,
25+
});
26+
return;
27+
}
28+
const discordUserId = interaction.user.id;
29+
30+
// Find GitHub username from Discord ID
31+
const githubUsername = Object.keys(githubDiscordMap).find(
32+
(ghUser) => githubDiscordMap[ghUser] === discordUserId,
33+
);
34+
35+
if (!githubUsername) {
36+
await interaction.reply({
37+
content: "❌ You don’t appear to be linked to a GitHub account.",
38+
ephemeral: true,
39+
});
40+
return;
41+
}
42+
43+
await interaction.deferReply({ ephemeral: true });
44+
45+
const githubItemsResult = await GithubAPI.fetchProjectItems();
46+
if (githubItemsResult.err) {
47+
logger.error({
48+
event: "myIssues.error",
49+
body: githubItemsResult.val.message,
50+
});
51+
52+
await interaction.editReply({
53+
content: "❌ Failed to fetch issues from GitHub.",
54+
});
55+
return;
56+
}
57+
58+
const assignedItems = githubItemsResult.val.filter(
59+
(item) =>
60+
Array.isArray(item.assignedUsers) &&
61+
item.assignedUsers.some((assigneeUrl: string) =>
62+
assigneeUrl.endsWith(`/${githubUsername}`),
63+
),
64+
);
65+
66+
if (assignedItems.length === 0) {
67+
await interaction.editReply({
68+
content: "✅ You have no assigned issues at the moment.",
69+
});
70+
return;
71+
}
72+
73+
await interaction.editReply({
74+
content: `📋 Showing ${assignedItems.length} issue(s) assigned to you:`,
75+
});
76+
77+
for (const item of assignedItems.slice(0, 5)) {
78+
const link = item.url ?? "https://github.com/";
79+
80+
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
81+
new ButtonBuilder()
82+
.setCustomId(`issue:edit:${item.githubId}`)
83+
.setLabel("Edit")
84+
.setStyle(ButtonStyle.Primary),
85+
new ButtonBuilder()
86+
.setCustomId(`issue:unassign:${item.githubId}`)
87+
.setLabel("Unassign")
88+
.setStyle(ButtonStyle.Secondary),
89+
new ButtonBuilder()
90+
.setCustomId(`issue:delete:${item.githubId}`)
91+
.setLabel("Delete")
92+
.setStyle(ButtonStyle.Danger),
93+
new ButtonBuilder()
94+
.setLabel("Open")
95+
.setStyle(ButtonStyle.Link)
96+
.setURL(link),
97+
);
98+
99+
await interaction.followUp({
100+
content: `## ${item.title}`,
101+
components: [buttons],
102+
ephemeral: true,
103+
});
104+
}
105+
106+
logger.info({
107+
event: "myIssues.success",
108+
body: `${assignedItems.length} issues returned for ${githubUsername}`,
109+
});
110+
}

0 commit comments

Comments
 (0)