Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
325ba93
🌟 feat: Add buildCommandString function to format command strings
hmd-ali Oct 17, 2025
36feabb
🌟 feat: Implement getPublicChannels function to filter accessible tex…
hmd-ali Oct 17, 2025
b33014a
🌟 feat: Add fetchAndCachePublicChannelsMessages function to cache mes…
hmd-ali Oct 17, 2025
9bd9c27
🌟 feat: Implement timeToString function to format milliseconds into r…
hmd-ali Oct 17, 2025
e4bc7cd
🌟 feat: Add cache-messages command to cache messages in all public te…
hmd-ali Oct 17, 2025
10e6b4a
🌟 feat: Add force re-caching option to cache-messages command
hmd-ali Oct 17, 2025
e81a74e
🌟 feat: Add new config variables (repel, server Id, moderator role Id…
hmd-ali Oct 17, 2025
0f8d354
🌟 feat: Fetch and cache messages on client ready event
hmd-ali Oct 17, 2025
526a2fb
🌟 feat: Implement repel command to timeout users and delete recent me…
hmd-ali Oct 17, 2025
4827b15
🌟 feat: Add cacheMessages and repelCommand to commands map
hmd-ali Oct 17, 2025
64796e6
🔨 refactor: remove FETCH_AND_SYNC_MESSAGES from env and put it direct…
hmd-ali Oct 18, 2025
b962467
🔨 refactor: remove unnecessary `return` from cache-messages command h…
hmd-ali Oct 18, 2025
d0cb686
🌟 feat: add error logging for target fetching and timeout functions
hmd-ali Oct 18, 2025
db8930e
🌟 feat: replace Promis.all with Promise.allSettled and track/log fail…
hmd-ali Oct 18, 2025
41ef4ce
🌟 feat: enhance message caching by tracking failed channels and using…
hmd-ali Oct 18, 2025
f6cccce
Merge branch 'main' into feat/repel
hmd-ali Oct 18, 2025
e33f680
🐛 fix: fix missing } after resolving merge conflicts
hmd-ali Oct 18, 2025
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
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
DISCORD_TOKEN="" # Your bot token
CLIENT_ID="" # Your bot's application ID
GUIDES_CHANNEL_ID="" # The ID of the channel where guides will be posted

SERVER_ID=
MODERATORS_ROLE_IDS= # Comma separated list of role IDs that are Moderators(Mods, Admins, etc)

REPEL_LOG_CHANNEL_ID= # Channel ID where the bot will log repel actions
GUIDES_CHANNEL_ID="" # The ID of the channel where guides will be posted
6 changes: 5 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { docsCommands } from './docs/index.js';
import { guidesCommand } from './guides/index.js';
import cacheMessages from './moderation/cache-messages.js';
import { repelCommand } from './moderation/repel.js';
import { pingCommand } from './ping.js';
import { tipsCommands } from './tips/index.js';
import type { Command } from './types.js';

export const commands = new Map<string, Command>(
[pingCommand, guidesCommand, docsCommands, tipsCommands].flat().map((cmd) => [cmd.data.name, cmd])
[pingCommand, guidesCommand, docsCommands, tipsCommands, repelCommand, cacheMessages]
.flat()
.map((cmd) => [cmd.data.name, cmd])
);
49 changes: 49 additions & 0 deletions src/commands/moderation/cache-messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ApplicationCommandOptionType, PermissionFlagsBits, PermissionsBitField } from 'discord.js';
import { fetchAndCachePublicChannelsMessages } from '../../util/cache.js';
import { createCommand } from '../../util/commands.js';

export default createCommand({
data: {
name: 'cache-messages',
description: 'Cache messages in all text channels of the server',
default_member_permissions: new PermissionsBitField(
PermissionFlagsBits.ManageMessages
).toJSON(),
options: [
{
name: 'force',
description: 'Force re-caching even if messages are already cached',
type: ApplicationCommandOptionType.Boolean,
required: false,
},
],
},
execute: async (interaction) => {
await interaction.deferReply();
if (!interaction.guild || !interaction.isChatInputCommand()) {
await interaction.editReply('This command can only be used in a guild.');
return;
}

if (!interaction.memberPermissions?.has(PermissionFlagsBits.ManageMessages)) {
await interaction.editReply('You do not have permission to use this command.');
return;
}

const guild = interaction.guild;
const force = interaction.options.getBoolean('force') ?? false;

await interaction.editReply('Caching messages in all public text channels...');

const { cachedChannels, totalChannels, failedChannels } =
await fetchAndCachePublicChannelsMessages(guild, force);

const failedMessage = failedChannels.length
? `\nFailed to cache messages in the following channels: ${failedChannels.map((id) => `<#${id}>`).join(', ')}`
: '';

await interaction.editReply(
`Cached messages in ${cachedChannels} out of ${totalChannels} text channels.${failedMessage}`
);
},
});
Loading