Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor folder structure #236

Merged
merged 4 commits into from
Apr 13, 2024
Merged
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
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,27 @@ pnpm run prisma:gen
### DB GUI

```bash
pnpm prisma:studio
pnpm run prisma:studio
```

### Deploying your commands to a test Discord Server

- Please make sure you have filled out your `GUILD_ID`, `TOKEN` and `CLIENT_ID`
in the `.env` file.
- Add your commands into the `src/command/index.ts` file like so.
- Add your commands into the `src/slash-commands/index.ts` & `src/context-menu-commands/index.ts` file like so.

```ts
import yourCommand from './yourCommand';
// File: src/slash-commands/index.ts
import yourCommand from './your-command';

export const commandList: Command[] = [yourCommand];
export const commandList: SlashCommand[] = [yourCommand];
```

```ts
// File: src/context-menu-commands/index.ts
import yourCommand from './your-command';

export const commandList: ContextMenuCommand[] = [yourCommand]
```

- Run the `deploy:command` command.
Expand Down Expand Up @@ -182,6 +190,7 @@ pnpm run deploy:command
### Running lints and tests

```bash
pnpm run lint
pnpm run format
pnpm run test
```
Expand Down
2 changes: 1 addition & 1 deletion bin/autobump.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ThreadChannel } from 'discord.js';
import { Result } from 'oxide.ts';
import { getDiscordClient } from '../src/clients';
import { listAllThreads } from '../src/commands/autobump-threads/utils';
import { listAllThreads } from '../src/slash-commands/autobump-threads/utils';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';

Expand Down
4 changes: 2 additions & 2 deletions bin/broadcast-reminder.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChannelType } from 'discord.js';
import { Result } from 'oxide.ts';
import { getDiscordClient } from '../src/clients';
import { formatReminderMessage, getReminderByTime, removeReminders } from '../src/commands/reminder/utils';
import { getReminderChannel } from '../src/commands/serverSettings/utils';
import { formatReminderMessage, getReminderByTime, removeReminders } from '../src/slash-commands/reminder/utils';
import { getReminderChannel } from '../src/slash-commands/server-settings/utils';
import { getCurrentUnixTime } from '../src/utils/date';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';
Expand Down
2 changes: 1 addition & 1 deletion bin/cleanup-expired-referrals.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result } from 'oxide.ts';
import { cleanupExpiredCode } from '../src/commands/referral/cleanupExpiredCode';
import { cleanupExpiredCode } from '../src/slash-commands/referral/utils';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';

Expand Down
12 changes: 7 additions & 5 deletions bin/main.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { InteractionType } from 'discord-api-types/v10';
import { Result } from 'oxide.ts';
import { getDiscordClient } from '../src/clients';
import { commandList, contextMenuCommandList } from '../src/commands';
import { deployGlobalCommands } from '../src/commands/deploy-command';
import { getConfigs } from '../src/config';
import { commands as contextMenuCommandList } from '../src/context-menu-commands';
import { deployGlobalCommands } from '../src/deploy-command';
import { commands as slashCommandList } from '../src/slash-commands';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';
import { processMessage } from '../src/utils/message-processor';
Expand All @@ -21,8 +22,9 @@ const main = async () => {
// This should only be run once during the bot startup in production.
// For development usage, please use `pnpm deploy:command`
logger.info('[main]: Deploying global commands');
const commands = [...slashCommandList, ...contextMenuCommandList];
const op = await Result.safe(
deployGlobalCommands([...commandList, ...contextMenuCommandList], {
deployGlobalCommands(commands, {
token,
clientId: client.user.id,
})
Expand All @@ -45,7 +47,7 @@ const main = async () => {
if (isCommand) {
const { commandName } = interaction;
logger.info(`[main]: RECEIVED COMMAND. COMMAND: ${commandName}`);
const command = commandList.find((cmd) => cmd.data.name === commandName);
const command = slashCommandList.find((cmd) => cmd.data.name === commandName);
return await command?.execute(interaction);
}

Expand All @@ -61,7 +63,7 @@ const main = async () => {
if (isAutocomplete) {
const { commandName } = interaction;
logger.info(`[main]: RECEIVED AUTOCOMPLETE. COMMAND: ${commandName}`);
const command = commandList.find((cmd) => cmd.data.name === commandName);
const command = slashCommandList.find((cmd) => cmd.data.name === commandName);
return await command?.autocomplete?.(interaction);
}
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 160,
"ignore": ["node_modules/**", "./src/commands/referral/generated"]
"ignore": ["node_modules/**", "./src/slash-commands/referral/generated"]
},
"javascript": {
"formatter": {
Expand Down
5 changes: 3 additions & 2 deletions scripts/build-referral-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import wretch from 'wretch';
import { logger } from '../src/utils/logger';

const ozbargainApi = wretch('https://www.ozbargain.com.au/wiki/list_of_referral_links');
const OUTPUT_DIR = path.join(__dirname, '..', 'src', 'commands', 'referral', 'generated');
const referralModuleDir = path.join(__dirname, '..', 'src', 'slash-commands', 'referral');
const OUTPUT_DIR = path.join(referralModuleDir, 'generated');

const getOzbReferralNodes = async () => {
const getOzbReferralNodes = async (): Promise<HTMLElement[]> => {
logger.info('[get-ozbargain-referral-nodes]: Fetching Ozbargain referral list');
const rawHtml = await ozbargainApi.get().text();
const htmlTree = parseHtml(rawHtml);
Expand Down
2 changes: 1 addition & 1 deletion scripts/delete-global-commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result } from 'oxide.ts';
import { deployGlobalCommands } from '../src/commands/deploy-command';
import { deployGlobalCommands } from '../src/deploy-command';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';

Expand Down
2 changes: 1 addition & 1 deletion scripts/delete-guild-commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result } from 'oxide.ts';
import { deployGuildCommands } from '../src/commands/deploy-command';
import { deployGuildCommands } from '../src/deploy-command';
import { getCurrentUnixTime } from '../src/utils/date';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';
Expand Down
8 changes: 5 additions & 3 deletions scripts/deploy-guild-commands.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Result } from 'oxide.ts';
import { commandList, contextMenuCommandList } from '../src/commands';
import { deployGuildCommands } from '../src/commands/deploy-command';
import { commands as slashCommandList } from '../src/slash-commands';
import { commands as contextMenuCommandList } from '../src/context-menu-commands';
import { deployGuildCommands } from '../src/deploy-command';
import { getCurrentUnixTime } from '../src/utils/date';
import { loadEnv } from '../src/utils/load-env';
import { logger } from '../src/utils/logger';
Expand All @@ -16,8 +17,9 @@ const deploy = async () => {
}

logger.info('[deploy-guild-commands]: Deploying guild commands');
const commands = [...slashCommandList, ...contextMenuCommandList];
const op = await Result.safe(
deployGuildCommands([...commandList, ...contextMenuCommandList,], {
deployGuildCommands(commands, {
token,
clientId,
guildId,
Expand Down
13 changes: 0 additions & 13 deletions src/commands/referral/cleanupExpiredCode.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { thankUserInMessage } from './commands';
import { thankUserInMessage } from './slash-commands/reputation/give-reputation';
import type { CommandConfig } from './utils/message-processor';

export const getConfigs = (): CommandConfig => {
Expand Down
8 changes: 8 additions & 0 deletions src/context-menu-commands/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { ContextMenuCommandBuilder, ContextMenuCommandInteraction } from 'discord.js';

export type ContextMenuCommandInteractionHandler = (interaction: ContextMenuCommandInteraction) => Promise<void>;

export interface ContextMenuCommand {
data: ContextMenuCommandBuilder;
execute: ContextMenuCommandInteractionHandler;
}
4 changes: 4 additions & 0 deletions src/context-menu-commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { ContextMenuCommand } from './builder';
import pinMessageCommand from './pin-message';

export const commands: ContextMenuCommand[] = [pinMessageCommand];
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApplicationCommandType, ContextMenuCommandBuilder, type ContextMenuCommandInteraction } from 'discord.js';
import { logger } from '../../../utils/logger';
import type { ContextMenuCommand } from '../../builder';
import { logger } from '../../utils/logger';
import type { ContextMenuCommand } from '../builder';

export const data = new ContextMenuCommandBuilder().setName('Pin').setType(ApplicationCommandType.Message);

Expand Down
7 changes: 4 additions & 3 deletions src/commands/deploy-command.ts → src/deploy-command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { REST, type RequestData, type RouteLike } from '@discordjs/rest';
import { Routes } from 'discord-api-types/v10';
import type { Command, ContextMenuCommand } from './builder';
import type { ContextMenuCommand } from './context-menu-commands/builder';
import type { SlashCommand } from './slash-commands/builder';

interface DiscordRequestConfig {
token: string;
Expand All @@ -19,7 +20,7 @@ const registerCommands = async ({ request, token, body }: DiscordRequestPayload)
return rest.put(request, { body });
};

export const deployGuildCommands = async (commandList: Array<Command | ContextMenuCommand>, config: DiscordRequestConfig) => {
export const deployGuildCommands = async (commandList: Array<SlashCommand | ContextMenuCommand>, config: DiscordRequestConfig) => {
const { token, clientId, guildId } = config;

const commands = commandList.map((cmd) => cmd.data.toJSON());
Expand All @@ -28,7 +29,7 @@ export const deployGuildCommands = async (commandList: Array<Command | ContextMe
return registerCommands({ request, token, body: commands });
};

export const deployGlobalCommands = async (commandList: Array<Command | ContextMenuCommand>, config: Omit<DiscordRequestConfig, 'guildId'>) => {
export const deployGlobalCommands = async (commandList: Array<SlashCommand | ContextMenuCommand>, config: Omit<DiscordRequestConfig, 'guildId'>) => {
const { token, clientId } = config;

const commands = commandList.map((cmd) => cmd.data.toJSON());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js';
import { logger } from '../../utils/logger';
import { getRandomIntInclusive } from '../../utils/random';
import type { Command } from '../builder';
import type { SlashCommand } from '../builder';

const data = new SlashCommandBuilder()
.setName('8ball')
Expand Down Expand Up @@ -32,7 +32,7 @@ export const ask8Ball = async (interaction: ChatInputCommandInteraction) => {
await interaction.reply(`Q: ${question}\nA: ${reply}`);
};

const command: Command = {
const command: SlashCommand = {
data,
execute: ask8Ball,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Result } from 'oxide.ts';
import { isBlank } from '../../utils/is-blank';
import { logger } from '../../utils/logger';
import { fetchLastMessageBeforeId } from '../../utils/message-fetcher';
import type { Command } from '../builder';
import type { SlashCommand } from '../builder';

const data = new SlashCommandBuilder()
.setName('allcap')
Expand Down Expand Up @@ -44,7 +44,7 @@ export const allCapExpandText = async (interaction: ChatInputCommandInteraction)
await interaction.reply(reply);
};

const command: Command = {
const command: SlashCommand = {
data,
execute: allCapExpandText,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ChannelType, SlashCommandSubcommandBuilder } from 'discord.js';
import { Result } from 'oxide.ts';
import { logger } from '../../utils/logger';
import type { CommandHandler, Subcommand } from '../builder';
import type { SlashCommandHandler, Subcommand } from '../builder';
import { addAutobumpThread } from './utils';

const data = new SlashCommandSubcommandBuilder()
.setName('add')
.setDescription('Add thread to autobump list')
.addChannelOption((option) => option.setName('thread').setDescription('thread to be auto-bumped').setRequired(true));

export const addAutobumpThreadCommand: CommandHandler = async (interaction) => {
export const addAutobumpThreadCommand: SlashCommandHandler = async (interaction) => {
const guildId = interaction.guildId!;
const thread = interaction.options.getChannel('thread', true);
logger.info(`[add-autobump-thread]: Adding thread ${thread.id} to autobump list for guild ${guildId}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { type GuildMember, SlashCommandBuilder } from 'discord.js';
import { isAdmin, isModerator } from '../../utils/permission';
import addThread from '../autobump-threads/add-thread';
import listThreads from '../autobump-threads/list-threads';
import removeThread from '../autobump-threads/remove-thread';
import type { Command, CommandHandler } from '../builder';
import type { SlashCommand, SlashCommandHandler } from '../builder';
import addThread from './add-thread';
import listThreads from './list-threads';
import removeThread from './remove-thread';

const data = new SlashCommandBuilder()
.setName('autobump-threads')
Expand All @@ -14,7 +14,7 @@ const data = new SlashCommandBuilder()

const subcommands = [listThreads, addThread, removeThread];

const execute: CommandHandler = async (interaction) => {
const execute: SlashCommandHandler = async (interaction) => {
const member = interaction.member as GuildMember;
if (!isAdmin(member) && !isModerator(member)) {
await interaction.reply("You don't have enough permission to run this command.");
Expand All @@ -26,7 +26,7 @@ const execute: CommandHandler = async (interaction) => {
return subcommand?.execute(interaction);
};

const command: Command = {
const command: SlashCommand = {
data,
execute,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ServerChannelsSettings } from '@prisma/client';
import { SlashCommandSubcommandBuilder } from 'discord.js';
import { Result } from 'oxide.ts';
import { logger } from '../../utils/logger';
import type { CommandHandler, Subcommand } from '../builder';
import type { SlashCommandHandler, Subcommand } from '../builder';
import { listThreadsByGuild } from './utils';

const data = new SlashCommandSubcommandBuilder().setName('list').setDescription('Show list of autobump threads');
Expand All @@ -14,7 +14,7 @@ const buildThreadList = (threadIds: ServerChannelsSettings['autobumpThreads']) =
}, startText);
};

export const listAutobumpThreadsCommand: CommandHandler = async (interaction) => {
export const listAutobumpThreadsCommand: SlashCommandHandler = async (interaction) => {
const guildId = interaction.guildId!;
const threads = await Result.safe(listThreadsByGuild(guildId));
logger.info(`[list-autobump-threads]: Listing autobump threads for guild ${guildId}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { SlashCommandSubcommandBuilder } from 'discord.js';
import { Result } from 'oxide.ts';
import { logger } from '../../utils/logger';
import type { CommandHandler, Subcommand } from '../builder';
import type { SlashCommandHandler, Subcommand } from '../builder';
import { removeAutobumpThread } from './utils';

const data = new SlashCommandSubcommandBuilder()
.setName('remove')
.setDescription('Remove thread from autobump list')
.addChannelOption((option) => option.setName('thread').setDescription('thread not to be auto-bumped').setRequired(true));

export const removeAutobumpThreadCommand: CommandHandler = async (interaction) => {
export const removeAutobumpThreadCommand: SlashCommandHandler = async (interaction) => {
const guildId = interaction.guildId!;
const thread = interaction.options.getChannel('thread', true);
logger.info(`[remove-autobump-thread]: Removing thread ${thread.id} from autobump list for guild ${guildId}`);
Expand Down
16 changes: 4 additions & 12 deletions src/commands/builder.ts → src/slash-commands/builder.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
import type {
AutocompleteInteraction,
ChatInputCommandInteraction,
ContextMenuCommandBuilder,
ContextMenuCommandInteraction,
SlashCommandBuilder,
SlashCommandSubcommandBuilder,
SlashCommandSubcommandsOnlyBuilder,
} from 'discord.js';

export type CommandHandler = (interaction: ChatInputCommandInteraction) => Promise<void>;
export type SlashCommandHandler = (interaction: ChatInputCommandInteraction) => Promise<void>;
export type AutocompleteHandler = (autocomplete: AutocompleteInteraction) => Promise<void>;
export type ContextMenuCommandInteractionHandler = (interaction: ContextMenuCommandInteraction) => Promise<void>;

export interface Command {
export interface SlashCommand {
data: Omit<SlashCommandBuilder, 'addSubcommandGroup' | 'addSubcommand'> | SlashCommandSubcommandsOnlyBuilder;
execute: CommandHandler;
execute: SlashCommandHandler;
autocomplete?: AutocompleteHandler;
}

export interface Subcommand {
data: SlashCommandSubcommandBuilder | ((subcommandGroup: SlashCommandSubcommandBuilder) => SlashCommandSubcommandBuilder);
execute: CommandHandler;
}

export interface ContextMenuCommand {
data: ContextMenuCommandBuilder;
execute: ContextMenuCommandInteractionHandler;
execute: SlashCommandHandler;
}
Loading
Loading