Skip to content

Commit

Permalink
a minimal (but functional) ban system
Browse files Browse the repository at this point in the history
  • Loading branch information
mrhappyma committed Jan 18, 2025
1 parent f75f6eb commit 75b73f0
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@prisma/client": "^6.1.0",
"@sentry/node": "^7.91.0",
"aws-sdk": "^2.1565.0",
"chrono-node": "^2.7.7",
"discord.js": "^14.13.0",
"express": "^4.20.0",
"prom-client": "^15.1.2",
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,14 @@ model application {
active Boolean @default(true)
createdAt DateTime @default(now())
}

model ban {
id Int @id @default(autoincrement())
user String
reason String
message String
endAt DateTime
appealAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
171 changes: 171 additions & 0 deletions src/modules/bans.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { ban } from "@prisma/client";
import bot, { prisma } from "..";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
EmbedBuilder,
ModalBuilder,
StringSelectMenuBuilder,
TextInputBuilder,
TextInputStyle,
UserSelectMenuBuilder,
} from "discord.js";
import * as chrono from "chrono-node";

const bans: ban[] = [];
//load active bans
const loadActiveBans = async () => {
const beans = await prisma.ban.findMany({
where: {
endAt: { gt: new Date() },
},
});
bans.push(...beans);
console.log(bans);
};
loadActiveBans();

export const userActiveBans = (userId: string) => {
return bans.filter((ban) => ban.user === userId && ban.endAt > new Date());
};

const addBan = async (
userId: string,
reason: string,
message: string,
endAt: Date,
appealAt?: Date
) => {
const ban = await prisma.ban.create({
data: {
user: userId,
reason,
message,
endAt,
appealAt,
},
});
bans.push(ban);
};

bot.registerButton("devtools:manage-bans", async (interaction) => {
const a1 = new ActionRowBuilder<UserSelectMenuBuilder>().addComponents([
new UserSelectMenuBuilder().setCustomId("devtools:manage-bans:user"),
]);
return await interaction.update({
components: [a1],
});
});

bot.registerUserSelectMenu("devtools:manage-bans:user", async (interaction) => {
const user = interaction.users.first()!;
const bans = userActiveBans(user.id);
const embed = new EmbedBuilder()
.setTitle(`Bans for ${user.tag}`)
.setDescription(
bans.length > 0 ? "User is currently banned" : "User is not banned"
)
.addFields(
bans.map((ban) => ({
name: ban.id.toString(),
value: `Reason: ${ban.reason}\nMessage: ${
ban.message
}\nEnd at: <t:${Math.floor(
ban.endAt.getTime() / 1000
)}:R>\nAppeal at: <t:${Math.floor(
(ban.appealAt?.getTime() ?? 0) / 1000
)}:R>`,
}))
);
const a1 = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents([
new StringSelectMenuBuilder()
.setCustomId("devtools:manage-bans:select")
.setPlaceholder("Select a ban")
.addOptions(
bans.map((ban) => ({
label: `Ban ${ban.id}`,
value: ban.id.toString(),
}))
)
.setDisabled(bans.length == 0),
]);
if (bans.length == 0)
a1.components[0].addOptions({
label: "No bans",
value: "no-bans",
});
const a2 = new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId(`devtools:manage-bans:create:${user.id}`)
.setLabel("Create ban")
.setStyle(ButtonStyle.Danger)
.setEmoji("🔨"),
]);
return await interaction.update({
embeds: [embed],
components: [a1, a2],
});
});

bot.registerButton(/devtools:manage-bans:create:(.+)/, async (interaction) => {
const userId = interaction.customId.split(":")[3];
const modal = new ModalBuilder()
.setTitle("Create ban")
.setCustomId(`devtools:manage-bans:create:${userId}:modal`)
.addComponents([
new ActionRowBuilder<TextInputBuilder>().addComponents([
new TextInputBuilder()
.setCustomId("reason")
.setLabel("reason")
.setStyle(TextInputStyle.Paragraph),
]),
new ActionRowBuilder<TextInputBuilder>().addComponents([
new TextInputBuilder()
.setCustomId("message")
.setLabel("message")
.setStyle(TextInputStyle.Paragraph),
]),
new ActionRowBuilder<TextInputBuilder>().addComponents([
new TextInputBuilder()
.setCustomId("endAt")
.setLabel("end at")
.setStyle(TextInputStyle.Short),
]),
new ActionRowBuilder<TextInputBuilder>().addComponents([
new TextInputBuilder()
.setCustomId("appealAt")
.setLabel("appeal at")
.setStyle(TextInputStyle.Short)
.setRequired(false),
]),
]);
return await interaction.showModal(modal);
});

bot.registerModal(
/devtools:manage-bans:create:(.+):modal/,
async (interaction) => {
const userId = interaction.customId.split(":")[3];
const reason = interaction.fields.getTextInputValue("reason");
const message = interaction.fields.getTextInputValue("message");
const endAtInput = interaction.fields.getTextInputValue("endAt");
const appealAtInput = interaction.fields.getTextInputValue("appealAt");

const endAt = chrono.parseDate(endAtInput);
const appealAt = chrono.parseDate(appealAtInput);

if (!endAt || (appealAtInput && !appealAt))
return interaction.reply({
content:
'Invalid date (s).\nIf you\'re trying to specify a relative date start with "in" like "in 2 months".',
ephemeral: true,
});

await addBan(userId, reason, message, endAt, appealAt ?? undefined);
return await interaction.reply({
content: "Ban added",
ephemeral: true,
});
}
);
6 changes: 5 additions & 1 deletion src/modules/devtools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ messagesClient.addGlobalCommand(
.setCustomId("devtools:dm")
.setLabel("Message user")
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId("devtools:manage-bans")
.setLabel("manage bans")
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId("devtools:edit-order")
.setLabel("edit order")
.setStyle(ButtonStyle.Primary),
.setStyle(ButtonStyle.Secondary),
]);
const a3 = new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
Expand Down
18 changes: 18 additions & 0 deletions src/modules/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import bot from "..";
import { closed, closedReason } from "./closed";

import { createOrder, getActiveOrdersForUser } from "../orders/cache";
import { userActiveBans } from "./bans";

bot.addGlobalCommand(
new SlashCommandBuilder()
Expand Down Expand Up @@ -83,6 +84,23 @@ bot.addGlobalCommand(
],
});

const bans = userActiveBans(interaction.user.id);
if (bans.length > 0)
return interaction.editReply({
embeds: [
{
title: "You are banned from ordering!",
description: `${
bans[0].message
}\n\nYou may appeal your ban starting <t:${Math.floor(
(bans[0].appealAt?.getTime() ?? 0) / 1000
)}:R>. Otherwise, it will expire <t:${Math.floor(
bans[0].endAt.getTime() / 1000
)}:R>`,
},
],
});

await createOrder(
orderText,
interaction.guild.id,
Expand Down

0 comments on commit 75b73f0

Please sign in to comment.