Skip to content

Commit

Permalink
Add support for assigning and unassigning tickets via slash command
Browse files Browse the repository at this point in the history
  • Loading branch information
Rian8337 committed Feb 5, 2024
1 parent 8ce274d commit a2c3c9b
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ export const run: ButtonCommand["run"] = async (_, interaction) => {
};

export const config: ButtonCommand["config"] = {
cooldown: 5,
replyEphemeral: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,6 @@ export const run: ButtonCommand["run"] = async (_, interaction) => {
};

export const config: ButtonCommand["config"] = {
cooldown: 30,
replyEphemeral: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ export const run: ButtonCommand["run"] = async (_, interaction) => {
};

export const config: ButtonCommand["config"] = {
cooldown: 5,
replyEphemeral: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Config } from "@alice-core/Config";
import { Constants } from "@alice-core/Constants";
import { DatabaseManager } from "@alice-database/DatabaseManager";
import { SupportTicket } from "@alice-database/utils/aliceDb/SupportTicket";
import { ConstantsLocalization } from "@alice-localization/core/constants/ConstantsLocalization";
import { TicketLocalization } from "@alice-localization/interactions/commands/General/ticket/TicketLocalization";
import { SlashSubcommand } from "@alice-structures/core/SlashSubcommand";
import { MessageCreator } from "@alice-utils/creators/MessageCreator";
import { CommandHelper } from "@alice-utils/helpers/CommandHelper";
import { InteractionHelper } from "@alice-utils/helpers/InteractionHelper";

export const run: SlashSubcommand<true>["run"] = async (_, interaction) => {
if (!interaction.inCachedGuild()) {
return;
}

const language = await CommandHelper.getLocale(interaction);

if (!interaction.member.roles.cache.hasAny(...Config.verifyPerm)) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
new ConstantsLocalization(language).getTranslation(
Constants.noPermissionReject,
),
),
});
}

await InteractionHelper.deferReply(interaction);

const localization = new TicketLocalization(language);
const dbManager = DatabaseManager.aliceDb.collections.supportTicket;
const author = interaction.options.getUser("author");
const ticketId = interaction.options.getInteger("id");

let ticket: SupportTicket | null;

await InteractionHelper.deferReply(interaction);

if (author !== null && ticketId !== null) {
ticket = await dbManager.getFromUser(author.id, ticketId);
} else {
ticket = await dbManager.getFromChannel(interaction.channelId);
}

if (!ticket) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
localization.getTranslation("ticketNotFound"),
),
});
}

const result = await ticket.assign(interaction.user.id);

if (result.failed()) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
localization.getTranslation("assignTicketFailed"),
result.reason,
),
});
}

InteractionHelper.reply(interaction, {
content: MessageCreator.createAccept(
localization.getTranslation("assignTicketSuccess"),
),
});
};

export const config: SlashSubcommand["config"] = {
permissions: [],
cooldown: 5,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Config } from "@alice-core/Config";
import { Constants } from "@alice-core/Constants";
import { DatabaseManager } from "@alice-database/DatabaseManager";
import { SupportTicketStatus } from "@alice-enums/ticket/SupportTicketStatus";
import { ConstantsLocalization } from "@alice-localization/core/constants/ConstantsLocalization";
import { TicketLocalization } from "@alice-localization/interactions/commands/General/ticket/TicketLocalization";
import { SlashSubcommand } from "@alice-structures/core/SlashSubcommand";
import { OnButtonPageChange } from "@alice-structures/utils/OnButtonPageChange";
import { EmbedCreator } from "@alice-utils/creators/EmbedCreator";
import { MessageButtonCreator } from "@alice-utils/creators/MessageButtonCreator";
import { MessageCreator } from "@alice-utils/creators/MessageCreator";
import { CommandHelper } from "@alice-utils/helpers/CommandHelper";
import { InteractionHelper } from "@alice-utils/helpers/InteractionHelper";
import { StringHelper } from "@alice-utils/helpers/StringHelper";
import { hyperlink } from "discord.js";

export const run: SlashSubcommand<true>["run"] = async (_, interaction) => {
if (!interaction.inCachedGuild()) {
return;
}

const language = await CommandHelper.getLocale(interaction);

if (!interaction.member.roles.cache.hasAny(...Config.verifyPerm)) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
new ConstantsLocalization(language).getTranslation(
Constants.noPermissionReject,
),
),
});
}

await InteractionHelper.deferReply(interaction);

const localization = new TicketLocalization(language);
const author = interaction.options.getUser("author");
const status = <SupportTicketStatus | null>(
interaction.options.getInteger("status")
);

const tickets = await DatabaseManager.aliceDb.collections.supportTicket.get(
"id",
{
assigneeIds: {
$in: [interaction.user.id],
},
authorId: author?.id,
status: status ?? undefined,
},
);

if (tickets.size === 0) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
localization.getTranslation("noTicketsAssigned"),
),
});
}

const ticketArray = [...tickets.values()];
const ticketsPerPage = 5;
const embed = EmbedCreator.createNormalEmbed({
author: interaction.user,
color: interaction.member.displayColor,
});

embed.setTitle(
StringHelper.formatString(
localization.getTranslation("assignedTicketListEmbedTitle"),
interaction.user.username,
),
);

const onPageChange: OnButtonPageChange = async (_, page) => {
const tickets = ticketArray.slice(
ticketsPerPage * page,
ticketsPerPage * (page + 1),
);

for (let i = 0; i < tickets.length; ++i) {
const ticket = tickets[i];

embed.addFields({
name: `${ticketsPerPage * page + i + 1}. ${ticket.title}`,
value: `${localization.getTranslation("ticketStatus")}: ${ticket.statusToString()} | ${hyperlink(localization.getTranslation("ticketGoToChannel"), ticket.threadChannelURL)}`,
});
}
};

MessageButtonCreator.createLimitedButtonBasedPaging(
interaction,
{ embeds: [embed] },
[interaction.user.id],
1,
Math.ceil(tickets.size / ticketsPerPage),
120,
onPageChange,
);
};

export const config: SlashSubcommand["config"] = {
permissions: ["Special"],
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export const run: SlashSubcommand<true>["run"] = async (_, interaction) => {
authorId: author.id,
status: status ?? undefined,
},
{
projection: {
id: 1,
title: 1,
status: 1,
threadChannelId: 1,
},
},
);

if (tickets.size === 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Config } from "@alice-core/Config";
import { Constants } from "@alice-core/Constants";
import { DatabaseManager } from "@alice-database/DatabaseManager";
import { SupportTicket } from "@alice-database/utils/aliceDb/SupportTicket";
import { ConstantsLocalization } from "@alice-localization/core/constants/ConstantsLocalization";
import { TicketLocalization } from "@alice-localization/interactions/commands/General/ticket/TicketLocalization";
import { SlashSubcommand } from "@alice-structures/core/SlashSubcommand";
import { MessageCreator } from "@alice-utils/creators/MessageCreator";
import { CommandHelper } from "@alice-utils/helpers/CommandHelper";
import { InteractionHelper } from "@alice-utils/helpers/InteractionHelper";

export const run: SlashSubcommand<true>["run"] = async (_, interaction) => {
if (!interaction.inCachedGuild()) {
return;
}

const language = await CommandHelper.getLocale(interaction);

if (!interaction.member.roles.cache.hasAny(...Config.verifyPerm)) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
new ConstantsLocalization(language).getTranslation(
Constants.noPermissionReject,
),
),
});
}

await InteractionHelper.deferReply(interaction);

const localization = new TicketLocalization(language);
const dbManager = DatabaseManager.aliceDb.collections.supportTicket;
const author = interaction.options.getUser("author");
const ticketId = interaction.options.getInteger("id");

let ticket: SupportTicket | null;

await InteractionHelper.deferReply(interaction);

if (author !== null && ticketId !== null) {
ticket = await dbManager.getFromUser(author.id, ticketId);
} else {
ticket = await dbManager.getFromChannel(interaction.channelId);
}

if (!ticket) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
localization.getTranslation("ticketNotFound"),
),
});
}

const result = await ticket.unassign(interaction.user.id);

if (result.failed()) {
return InteractionHelper.reply(interaction, {
content: MessageCreator.createReject(
localization.getTranslation("unassignTicketFailed"),
result.reason,
),
});
}

InteractionHelper.reply(interaction, {
content: MessageCreator.createAccept(
localization.getTranslation("unassignTicketSuccess"),
),
});
};

export const config: SlashSubcommand["config"] = {
permissions: [],
cooldown: 5,
};
69 changes: 69 additions & 0 deletions src/interactions/commands/General/ticket/ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,55 @@ export const config: SlashCommand["config"] = {
name: "ticket",
description: "Primary interface of the ticket system.",
options: [
{
name: "assign",
type: ApplicationCommandOptionType.Subcommand,
description: "Assigns yourself to a ticket.",
options: [
{
name: "author",
type: ApplicationCommandOptionType.User,
description:
"The user who opened the ticket. If unspecified, will default to the ticket in the channel.",
},
{
name: "id",
type: ApplicationCommandOptionType.Integer,
minValue: 1,
description:
"The ID of the ticket. If unspecified, will default to the ticket in the channel.",
},
],
},
{
name: "assigned",
type: ApplicationCommandOptionType.Subcommand,
description: "Lists all tickets that you are assigned to.",
options: [
{
name: "author",
type: ApplicationCommandOptionType.User,
description:
"The ticket author to list for. If unspecified, all ticket authors will be listed.",
},
{
name: "status",
type: ApplicationCommandOptionType.Integer,
description:
"The ticket status to filter for. If unspecified, no status filter is applied.",
choices: [
{
name: "Open",
value: SupportTicketStatus.open,
},
{
name: "Closed",
value: SupportTicketStatus.closed,
},
],
},
],
},
{
name: "close",
type: ApplicationCommandOptionType.Subcommand,
Expand Down Expand Up @@ -149,6 +198,26 @@ export const config: SlashCommand["config"] = {
},
],
},
{
name: "unassign",
type: ApplicationCommandOptionType.Subcommand,
description: "Unassigns a yourself from a ticket.",
options: [
{
name: "author",
type: ApplicationCommandOptionType.User,
description:
"The user who opened the ticket. If unspecified, will default to the ticket in the channel.",
},
{
name: "id",
type: ApplicationCommandOptionType.Integer,
minValue: 1,
description:
"The ID of the ticket. If unspecified, will default to the ticket in the channel.",
},
],
},
{
name: "view",
type: ApplicationCommandOptionType.Subcommand,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface TicketStrings {
readonly ticketNotFound: string;
readonly presetNotFound: string;
readonly noTicketsFound: string;
readonly noTicketsAssigned: string;
readonly ticketEditModalTitle: string;
readonly ticketCreateModalTitle: string;
readonly ticketModalTitleLabel: string;
Expand All @@ -20,7 +21,12 @@ export interface TicketStrings {
readonly moveTicketConfirm: string;
readonly moveTicketFailed: string;
readonly moveTicketSuccess: string;
readonly assignTicketFailed: string;
readonly assignTicketSuccess: string;
readonly unassignTicketFailed: string;
readonly unassignTicketSuccess: string;
readonly ticketListEmbedTitle: string;
readonly assignedTicketListEmbedTitle: string;
readonly ticketStatus: string;
readonly ticketGoToChannel: string;
}
Expand Down
Loading

0 comments on commit a2c3c9b

Please sign in to comment.