Skip to content
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
3 changes: 2 additions & 1 deletion .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ DEV=true/false (this env var is optional)
DEVIDS=list of userids that can run commands when in dev mode (this env var is optional)
KUMA_PUSH_URL=single push URL/multiple URLs in shard order (this env var is optional)
SHARD_COUNT=number of shards, if not provided it will use discords recommendation (this env var is optional)
LIMITS=false, please keep this as false but if set to true it will enable limits and also monetization (this env var is optional)
LIMITS=false, please keep this as false but if set to true it will enable limits and also monetization (this env var is optional)
MODERATORS=list of userids that are considered global moderators (this env var is optional but highly recommended if you want to moderate the bot for others)
85 changes: 85 additions & 0 deletions apps/bot/src/commands/moderation/nick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Command } from '@sapphire/framework';
import { GuildMember, MessageFlags, PermissionsBitField } from 'discord.js';
import { emojis } from '#utils/emoji.js';

export class NickCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, { ...options });
}

public override registerApplicationCommands(registry: Command.Registry) {
registry.registerChatInputCommand((builder: any) =>
builder
.setName('nick')
.setDescription("Change a member's nickname.")
.addUserOption((option: any) =>
option.setName('member').setDescription('Select a member to change their nickname').setRequired(true)
)
.addStringOption((option: any) =>
option.setName('nickname').setDescription('Nickname (leave empty to reset)')
)
);
}

public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
if (!interaction.inCachedGuild()) {
await interaction.reply({
content: `${emojis.rightArrow2} This command can only be used in a server.`,
flags: MessageFlags.Ephemeral
});
return;
}

const member = interaction.member as GuildMember;

if (!member.permissions.has(PermissionsBitField.Flags.ManageNicknames)) {
await interaction.reply({
content: `${emojis.rightArrow2} You do not have permission to manage nicknames.`,
flags: MessageFlags.Ephemeral
});
return;
}

const targetMember = interaction.options.getMember('member');
const nickname = interaction.options.getString('nickname') ?? null;

if (!targetMember) {
await interaction.reply({
content: `${emojis.rightArrow2} That user is not in this server.`,
flags: MessageFlags.Ephemeral
});
return;
}

if (targetMember.id === interaction.guild.ownerId) {
await interaction.reply({
content: `${emojis.rightArrow2} You cannot change the server owner's nickname.`,
flags: MessageFlags.Ephemeral
});
return;
}

if (!targetMember.manageable) {
await interaction.reply({
content: `${emojis.rightArrow2} I cannot manage this member's nickname.`,
flags: MessageFlags.Ephemeral
});
return;
}

try {
await targetMember.setNickname(nickname);
await interaction.reply({
content: nickname
? `${emojis.rightArrow2} Set <@${targetMember.user.id}>'s nickname to **${nickname}**.`
: `${emojis.rightArrow2} Reseted <@${targetMember.user.id}>'s nickname.`,
flags: MessageFlags.Ephemeral
});
} catch {
await interaction.reply({
content: `${emojis.rightArrow2} Failed to update <@${targetMember.user.id}>'s nickname.`,
flags: MessageFlags.Ephemeral
});
}
}
}
2 changes: 1 addition & 1 deletion apps/bot/src/commands/promotion/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export class BotCommand extends Command {
}

public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
await interaction.reply(`${emojis.rightArrow1} https://questfoundation.dev/bot/invite`);
await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/bot/invite`);
}
}
2 changes: 1 addition & 1 deletion apps/bot/src/commands/promotion/invite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export class InviteCommand extends Command {
}

public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
await interaction.reply(`${emojis.rightArrow1} https://questfoundation.dev/bot/invite`);
await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/bot/invite`);
}
}
11 changes: 8 additions & 3 deletions apps/bot/src/commands/utility/help.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command } from '@sapphire/framework';
import { emojis } from '#utils/emoji.js';
import { MessageFlags } from 'discord.js';
import { EmbedBuilder, MessageFlags } from 'discord.js';

export class HelpCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
Expand All @@ -26,9 +26,14 @@ export class HelpCommand extends Command {
})
.join('\n');

const embed = new EmbedBuilder()
.setTitle('Commands')
.setDescription(commandList)
.addFields({ name: 'Links', value: '**Status:** https://status.questfoundation.dev/\n**Official Discord Server:** https://discord.gg/F4HYE8frK2\n**Documentation:** https://docs.questfoundation.dev/' });

await interaction.reply({
content: commandList + `\n\n**Status:** https://status.questfoundation.dev/\n**Official Discord Server:** https://discord.gg/F4HYE8frK2\n**Documentation:** https://docs.questfoundation.dev/`,
flags: MessageFlags.SuppressEmbeds | MessageFlags.Ephemeral
embeds: [embed],
flags: MessageFlags.Ephemeral
});
}
}
2 changes: 1 addition & 1 deletion apps/bot/src/lib/logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export async function isLoggingChannel(guild: Guild, channelId: string | null |

export async function getRecentAuditLogEntry(guild: Guild, type: AuditLogEvent, targetId: string) {
const auditLogs = await guild.fetchAuditLogs({ type, limit: 5 }).catch((err) => {
console.error(err);
if (err?.code !== 10004) console.error(err);
return null;
});

Expand Down
13 changes: 13 additions & 0 deletions apps/bot/src/listeners/guildDelete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Listener } from '@sapphire/framework';
import { Events, type Guild } from 'discord.js';
import { prisma } from '#lib/prisma.js';

export class GuildDeleteListener extends Listener<typeof Events.GuildDelete> {
public constructor(context: Listener.LoaderContext, options: Listener.Options) {
super(context, { ...options, event: Events.GuildDelete });
}

public async run(guild: Guild) {
await prisma.server.delete({ where: { id: guild.id } }).catch(() => null);
}
}
2 changes: 1 addition & 1 deletion apps/bot/src/listeners/messageDelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class MessageDeleteListener extends Listener<typeof Events.MessageDelete>
.addFields(
{ name: 'Channel', value: message.channel?.toString() ?? 'Unknown', inline: true },
{ name: 'Author', value: message.author?.tag ?? 'Unknown', inline: true },
{ name: 'Content', value: truncate(message instanceof Object ? (message as Message).content : undefined) || '-' }
{ name: 'Content', value: truncate(message instanceof Object ? (message as Message).content : undefined, 1024) || '-' }
)
.setFooter({ text: `ID: ${message.id}` })
.setTimestamp();
Expand Down
4 changes: 2 additions & 2 deletions apps/bot/src/listeners/messageUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export class MessageUpdateListener extends Listener {
.addFields(
{ name: 'Channel', value: newMsg.channel?.toString() ?? 'Unknown', inline: true },
{ name: 'Author', value: newMsg.author?.tag ?? oldMsg?.author?.tag ?? 'Unknown', inline: true },
{ name: 'Before', value: truncate(oldMsg?.content) || '-' },
{ name: 'After', value: truncate(newMsg.content) || '-' }
{ name: 'Before', value: truncate(oldMsg?.content, 1023) || '-' },
{ name: 'After', value: truncate(newMsg.content, 1023) || '-' }
)
.setFooter({ text: `ID: ${newMsg.id}` })
.setTimestamp();
Expand Down