Skip to content

Commit

Permalink
refactor(Commands): merge prefix and slash commands (#79)
Browse files Browse the repository at this point in the history
* refactor(Commands): merge prefix and slash commands

* refactor: prefix commands
  • Loading branch information
imnaiyar authored Sep 20, 2024
1 parent f608edc commit 254ce3e
Show file tree
Hide file tree
Showing 56 changed files with 1,308 additions and 1,231 deletions.
2 changes: 1 addition & 1 deletion docs/pages/commands.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ These server-specific commands rely on server-level data and interactions, which
<Cards>
<Card title="Guides" icon={<FaMapMarkedAlt />} href="/commands/guides" />
<Card title="Informations" icon={<HiMiniInformationCircle />} href="/commands/info" />
<Card title="Updates" icon={<IoIosNotifications />} href="/commands/updates" />
<Card title="Admin" icon={<IoIosNotifications />} href="/commands/admin" />
<Card title="Utilities" icon={<IoCog />} href="/commands/utility" />
</Cards>
2 changes: 1 addition & 1 deletion docs/pages/commands/_meta.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"guides": "Guides",
"info": "Informations",
"updates": "Updates",
"admin": "Admin",
"utility": "Utilities"
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
---
title: Updates Commands
description: A comprehensive guide on live updates commands offered by SkyHelper bot
title: Admin Commands
description: All the admin commands offered by SkyHelper
---

import { Callout, Steps } from "nextra/components";
import { ImFire } from "react-icons/im";
import { CiWarning } from "react-icons/ci";

# Updates Commands
# Admin Commands

Almost all commands under this category are related to features providing live updates and/or reminders.

<Callout type="error" emoji={<ImFire />}>
All commands in this category are only available for servers (not [user-apps](/pages/user-install-app)) and require users to
have `Manage Server` permissions to use them. These commands are also not visible to users who lack the permission (this
have `Manage Server` permissions(Admins) to use them. These commands are also not visible to users who lack the permission (this
behavior can be adjusted under `Server Settings > Integrations Tab`, although there’s also an internal check for permissions, so
enabling it for users without the necessary permission will still prevent them from using it).
</Callout>
Expand Down
1 change: 1 addition & 0 deletions locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"MESSAGE_NO_ARGS": "You didn't provide any arguments\n\n**Available Args**: {{ARGS}}!",
"MINIMUM_ARGS": "You need to provide minimum `{{LIMIT}}` args for this command",
"INVALID_ARGS": "Invalid Arguments!",
"INVALID_USAGE": "Invalid Usage!",
"NO_PERMS_USER": "You don't have necessary permission(s) ({{PERMISSIONS}}) to use this command.",
"NOT_A_SERVER": "Oops! Looks like you ran this command in a server where I'm not in or as an User App command. This command is only meant to be used in a server I am a member of.",
"NO_PERMS_BOT": "I do not have the required permission(s) ({{PERMISSIONS}}) to perform this action. Please run the command again after granting me the necessary permission(s).",
Expand Down
2 changes: 1 addition & 1 deletion src/bot/commands/contexts/m-hug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { ContextMenuCommand } from "#structures";
import { ApplicationCommandType, EmbedBuilder } from "discord.js";

export default {
name: "Hug",
data: {
name: "Hug",
type: ApplicationCommandType.Message,
integration_types: [0, 1],
contexts: [0, 1, 2],
Expand Down
2 changes: 1 addition & 1 deletion src/bot/commands/contexts/u-hug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { ContextMenuCommand } from "#structures";
import { ApplicationCommandType, EmbedBuilder } from "discord.js";

export default {
name: "Hug",
data: {
name: "Hug",
type: ApplicationCommandType.User,
integration_types: [0, 1],
contexts: [0, 1, 2],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { type EventReminder, type GuildSchema } from "#libs";
import type { SlashCommand } from "#structures";
import type { Command } from "#structures";
import {
Webhook,
ChatInputCommandInteraction,
Expand All @@ -22,11 +22,12 @@ import {
TextChannel,
ApplicationIntegrationType,
InteractionContextType,
Message,
} from "discord.js";
import { useTranslations as x } from "#handlers/useTranslation";
import { getTranslator } from "#bot/i18n";
export default {
async execute(interaction, t) {
async interactionRun(interaction, t) {
if (!interaction.inCachedGuild()) {
return void (await interaction.reply(t("commands.REMINDERS.RESPONSES.USER_APP_ERROR")));
}
Expand All @@ -37,25 +38,30 @@ export default {

await handleSetup(interaction, t, settings);
},
data: {
name: "reminders",
async messageRun({ message, client, t }) {
if (!message.inGuild()) return;
const settings = await client.database.getSettings(message.guild);
await handleSetup(message, t, settings);
},
name: "reminders",
description: "Set up reminders",
slash: {
name_localizations: x("commands.REMINDERS.name"),
description: "Set up reminders",
description_localizations: x("commands.REMINDERS.description"),
integration_types: [ApplicationIntegrationType.GuildInstall],
contexts: [InteractionContextType.Guild],
botPermissions: ["ManageWebhooks"],
userPermissions: ["ManageGuild"],
},
category: "Updates",
} satisfies SlashCommand;

async function handleSetup(interaction: ChatInputCommandInteraction, t: ReturnType<typeof getTranslator>, settings: GuildSchema) {
const client = interaction.client;

if (!interaction.inCachedGuild()) {
throw new Error(t("commands.REMINDERS.RESPONSES.NOT_CACHED"));
}
botPermissions: ["ManageWebhooks"],
userPermissions: ["ManageGuild"],
category: "Admin",
} satisfies Command;

async function handleSetup(
intOrMsg: ChatInputCommandInteraction<"cached"> | Message<true>,
t: ReturnType<typeof getTranslator>,
settings: GuildSchema,
) {
const client = intOrMsg.client;

const { reminders } = settings;
const { geyser, grandma, turtle, reset, dailies, eden, webhook } = reminders;
Expand Down Expand Up @@ -88,7 +94,7 @@ async function handleSetup(interaction: ChatInputCommandInteraction, t: ReturnTy
const initialEmbed = async () => {
return new EmbedBuilder()
.setAuthor({ name: t("commands.REMINDERS.RESPONSES.EMBED_AUTHOR"), iconURL: client.user.displayAvatarURL() })
.setTitle(interaction.guild.name)
.setTitle(intOrMsg.guild.name)
.addFields(
{ name: `**•** ${t("times-embed.GEYSER")} ${getActive(geyser)}`, value: "\u200B", inline: true },
{ name: `**•** ${t("times-embed.GRANDMA")} ${getActive(grandma)}`, value: "\u200B", inline: true },
Expand Down Expand Up @@ -156,20 +162,23 @@ async function handleSetup(interaction: ChatInputCommandInteraction, t: ReturnTy

return [mainMenu, defaultRoleMenu, channelSelectMenu, toggleButtons];
};

const reply = await (intOrMsg instanceof Message ? intOrMsg.reply : intOrMsg.editReply).bind(intOrMsg)({
embeds: [await initialEmbed()],
components: createActionRows(),
});
const editFunction =
intOrMsg instanceof ChatInputCommandInteraction ? intOrMsg.editReply.bind(intOrMsg) : reply.edit.bind(reply);
const updateOriginal = async () => {
await interaction.editReply({ embeds: [await initialEmbed()], components: createActionRows() });
await editFunction({ embeds: [await initialEmbed()], components: createActionRows() });
};

const reply = await interaction.editReply({ embeds: [await initialEmbed()], components: createActionRows() });

const collector = reply.createMessageComponentCollector({
idle: 2 * 60 * 1000,
idle: 90_000,
});

const user = intOrMsg instanceof Message ? intOrMsg.author : intOrMsg.user;
collector.on("collect", async (int) => {
const customId = int.customId;
if (int.user.id !== interaction.user.id) {
if (int.user.id !== user.id) {
await int.deferReply({ ephemeral: true });
const ts = await int.t();
await int.editReply(ts("common.errors.NOT-ALLOWED"));
Expand Down Expand Up @@ -300,7 +309,9 @@ async function handleSetup(interaction: ChatInputCommandInteraction, t: ReturnTy
});

collector.on("end", async () => {
const msg = await interaction.fetchReply().catch(() => {});
const msg = await (intOrMsg instanceof Message ? intOrMsg.fetch : intOrMsg.fetchReply)
.bind(intOrMsg)()
.catch(() => {});
const components: ActionRowBuilder<MessageActionRowComponentBuilder>[] = [];

msg?.components?.forEach((comp) => {
Expand All @@ -309,6 +320,6 @@ async function handleSetup(interaction: ChatInputCommandInteraction, t: ReturnTy
components.push(btn);
});

await interaction.editReply({ components }).catch(() => {});
await editFunction({ components }).catch(() => {});
});
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import type { PrefixCommand } from "#bot/structures/PrefixCommands";
import type { Command } from "#structures";

export default {
data: {
name: "setprefix",
description: "set the prefix for this server",
name: "setprefix",
description: "set the prefix for this server",
prefix: {
aliases: ["sp"],
args: {
minimum: 1,
},
userPermissions: ["ManageGuild"],
minimumArgs: 1,
usage: "<prefix>",
guildOnly: true,
},
async execute({ message: msg, args, client }) {
userPermissions: ["ManageGuild"],
category: "Admin",
async messageRun({ message: msg, args, client }) {
if (!msg.inGuild()) return;
const settings = await client.database.getSettings(msg.guild);
const prefix = args[0];
Expand All @@ -19,4 +20,4 @@ export default {
await settings.save();
await msg.reply(`Prefix set to \`${prefix}\` for this server`);
},
} satisfies PrefixCommand;
} satisfies Command;
86 changes: 86 additions & 0 deletions src/bot/commands/inputCommands/admin/shards-live.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { Command } from "#structures";
import { ApplicationCommandOptionType, ChannelType, TextChannel } from "discord.js";
import { useTranslations as x } from "#handlers/useTranslation";
import { handleLive } from "./sub/handle-live.js";
export default {
async interactionRun(interaction, t) {
const client = interaction.client;
await interaction.deferReply({ ephemeral: true });
if (!interaction.guild) {
return void (await interaction.followUp(t("commands.SHARDS_LIVE.RESPONSES.NOT_GUILD")));
}
const sub = interaction.options.getSubcommand();
const channel = sub === "start" ? (interaction.options.getChannel("channel", true) as TextChannel) : undefined;
const config = await client.database.getSettings(interaction.guild);
try {
await interaction.editReply(await handleLive(client, "Shards", sub, config, t, channel));
} catch (err) {
client.logger.error("Failed to stop Shards Updates in " + interaction.guild.name, err);
}
},
async messageRun({ message, client, t, args }) {
if (!message.inGuild()) return;
const sub = args[0];
const channel = message.mentions.channels.first() || client.channels.cache.get(args[1]);
if (sub === "start" && (!channel || channel.isDMBased() || channel.guildId !== message.guildId || !channel.isSendable())) {
return void message.reply(
"Please provide a valid channel id or mention the channel you want the live shards to be sent to.",
);
}

const config = await client.database.getSettings(message.guild);
await message.reply(await handleLive(client, "Shards", sub, config, t, channel as TextChannel));
},
name: "shards-live",
description: "auto updating message with live shards details",
slash: {
name_localizations: x("commands.SHARDS_LIVE.name"),
description_localizations: x("commands.SHARDS_LIVE.description"),
options: [
{
name: "start",
name_localizations: x("commands.SHARDS_LIVE.options.START.name"),
description: "start live shards",
description_localizations: x("commands.SHARDS_LIVE.options.START.description"),
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: "channel",
name_localizations: x("commands.SHARDS_LIVE.options.START.option.CHANNEL.name"),
description: "channel where shard details should be updated",
description_localizations: x("commands.SHARDS_LIVE.options.START.option.CHANNEL.description"),
type: ApplicationCommandOptionType.Channel,
channel_types: [ChannelType.GuildText],
required: true,
},
],
},
{
name: "stop",
name_localizations: x("commands.SHARDS_LIVE.options.STOP.name"),
description: "stop live shard",
description_localizations: x("commands.SHARDS_LIVE.options.STOP.description"),
type: ApplicationCommandOptionType.Subcommand,
},
],
integration_types: [0],
contexts: [0],
},
prefix: {
usage: "<sub> [#channel]",
minimumArgs: 1,
subcommands: [
{
trigger: "start <#channel>",
description: "starts live-shards in the given channel",
},
{
trigger: "stop",
description: "stop live shards",
},
],
},
botPermissions: ["ManageWebhooks"],
userPermissions: ["ManageGuild"],
category: "Admin",
} satisfies Command;
Loading

0 comments on commit 254ce3e

Please sign in to comment.