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
1 change: 1 addition & 0 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const config: Config = {
langs: "932638149618835466",
},
noPing: "932637353263128577",
zooExhibit: "1432483356393734194",
},
clientId: "932387188585398353",
guildId: "904478147351806012",
Expand Down
1 change: 1 addition & 0 deletions src/config.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface Config {
separators: { general: Snowflake; tags: Snowflake; langs: Snowflake };
noPing: Snowflake;
bumpNotifications?: Snowflake;
zooExhibit?: Snowflake;
};
modmail: {
channel: string;
Expand Down
2 changes: 2 additions & 0 deletions src/modules/moderation/moderation.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SoftBanCommand } from "./softBan.command.js";
import { TempBanCommand } from "./tempBan.command.js";
import { TempBanListener } from "./tempBan.listener.js";
import { UnbanCommand } from "./unban.command.js";
import { ZookeepCommand } from "./zookeep.command.js";

export const ModerationModule: Module = {
name: "moderation",
Expand All @@ -15,6 +16,7 @@ export const ModerationModule: Module = {
SoftBanCommand,
TempBanCommand,
KickCommand,
ZookeepCommand,
],
listeners: [...InviteListeners, TempBanListener],
};
131 changes: 131 additions & 0 deletions src/modules/moderation/zookeep.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import * as Sentry from "@sentry/node";
import { ApplicationCommandType } from "discord.js";
import type { Command } from "djs-slash-helper";
import { config } from "../../Config.js";
import { createStandardEmbed } from "../../util/embeds.js";
import randomElementFromArray from "../../util/random.js";
import { actualMention, type UserMentionable } from "../../util/users.js";

const zooGifs = [
"https://c.tenor.com/hZGXVfUTKkIAAAAd/tenor.gif",
"https://c.tenor.com/rVp0HbYphkEAAAAd/tenor.gif",
"https://c.tenor.com/xD622Ai2sLMAAAAC/tenor.gif",
"https://c.tenor.com/3fuiv47KDrkAAAAd/tenor.gif",
];

const zooMessages: ((user: UserMentionable) => string)[] = [
(user) => `${actualMention(user)} has been sent to the zoo! 🦁`,
(user) => `${actualMention(user)} will make a fine new exhibit! 🐯`,
(user) => `Look at ${actualMention(user)} go! Such a majestic creature! 🦒`,
(user) =>
`Everyone, please welcome our latest exhibit: ${actualMention(user)}! 🐵`,
(user) =>
`${actualMention(user)} has been safely secured in their new habitat! 🐼`,
(user) =>
`The zookeepers have successfully captured ${actualMention(user)}! 🦊`,
(user) =>
`${actualMention(user)} couldn't behave and has been placed in the zoo! 🐸`,
];

export const ZookeepCommand: Command<ApplicationCommandType.User> = {
name: "Zookeep",
default_permission: false,
type: ApplicationCommandType.User,
async handle(interaction) {
if (!config.roles.zooExhibit) {
await interaction.reply({
content: "Sorry, there's no zoo configured.",
flags: "Ephemeral",
});
return;
}
const user = interaction.targetUser;

const guild = interaction.guild;
if (!guild) {
await interaction.reply({
content: "This command can only be used in a guild.",
flags: "Ephemeral",
});
return;
}
const member = await guild?.members.fetch(user.id);
if (!member) {
await interaction.reply({
content: "User not found in this guild.",
flags: "Ephemeral",
});
return;
}
if (member.user.bot) {
await interaction.reply({
content: `Bots can't be sent to the zoo!`,
flags: "Ephemeral",
});
return;
}

if (member.roles.cache.has(config.roles.zooExhibit)) {
await interaction.reply({
content: `${actualMention(user)} is already in the zoo!`,
flags: "Ephemeral",
});
return;
}
try {
await member.roles.add(
config.roles.zooExhibit,
`Zookeep command used by ${interaction.user.tag}`,
);
} catch (error) {
Sentry.captureException(error);
await interaction.reply({
content: `Failed to send ${actualMention(user)} to the zoo. Do I have the correct permissions?`,
flags: "Ephemeral",
});
return;
}

const gif = randomElementFromArray(zooGifs);
const message = randomElementFromArray(zooMessages)(user);

const embed = createStandardEmbed(user)
.setTitle("Zoo Exhibit Captured!")
.setDescription(message)
.setColor("Purple")
.setImage(gif);
console.log(gif);

if (!interaction.inCachedGuild()) {
await interaction.reply({ embeds: [embed] });
return;
}
const applicableChannel = interaction.channel;

if (
applicableChannel &&
!applicableChannel.permissionsFor(guild.roles.everyone).has("ViewChannel")
) {
// send it in general instead
const generalChannel = guild.channels.cache.get(config.channels.general);
if (
generalChannel?.isTextBased() &&
generalChannel
.permissionsFor(interaction.client.user)
?.has("SendMessages")
) {
await interaction.reply({
content: `Zookept successfully executed! Posting the result in <#${config.channels.general}>.`,
flags: "Ephemeral",
});
embed.setDescription(
`${message}\nThanks ${actualMention(interaction.user)} for keeping our civilization safe!`,
);
await generalChannel.send({ embeds: [embed] });
return;
}
}

await interaction.reply({ embeds: [embed] });
},
};
4 changes: 2 additions & 2 deletions src/util/random.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function randomElementFromArray<T>(array: T[]): T | undefined {
export default function randomElementFromArray<T>(array: T[]): T {
if (array.length === 0) {
return undefined;
throw new Error("Array is empty");
}
if (array.length === 1) {
return array[0];
Expand Down