Skip to content
This repository has been archived by the owner on Oct 12, 2024. It is now read-only.

Commit

Permalink
TempBan
Browse files Browse the repository at this point in the history
  • Loading branch information
RealEthanPlayzDev committed Jan 6, 2024
1 parent d0d8411 commit 7f75b6f
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 3 deletions.
13 changes: 13 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"editor.formatOnSave": true,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.quickSuggestions": {
"strings": true
},
"editor.suggest.insertMode": "replace",
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
11 changes: 10 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ model Guild {

enum ModerationAction {
Ban
TempBan
Kick
Mute
Warn
Expand All @@ -38,7 +39,9 @@ model ModerationCase {
GuildId String
Reason String
AttachmentProof String
MuteDuration String @default("0")
Duration String @default("0")
CreatedAt DateTime @default(dbgenerated("0"))
ActiveTempBans ActiveTempBans[]
}

model Tag {
Expand All @@ -48,3 +51,9 @@ model Tag {
Content String
Image String
}

model ActiveTempBans {
ActiveTempBanId Int @id @default(autoincrement())
GlobalCaseId Int
Case ModerationCase @relation(fields: [GlobalCaseId], references: [GlobalCaseId])
}
1 change: 1 addition & 0 deletions src/commands/Moderation/Ban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const Command: MeteoriumCommand = {
GuildId: interaction.guildId,
Reason: Reason,
AttachmentProof: AttachmentProof ? AttachmentProof.url : "",
CreatedAt: new Date(),
},
});
await interaction.guild.members.ban(User, {
Expand Down
1 change: 1 addition & 0 deletions src/commands/Moderation/Kick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const Command: MeteoriumCommand = {
GuildId: interaction.guildId,
Reason: Reason,
AttachmentProof: AttachmentProof ? AttachmentProof.url : "",
CreatedAt: new Date(),
},
});
await interaction.guild.members.kick(
Expand Down
3 changes: 2 additions & 1 deletion src/commands/Moderation/Mute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export const Command: MeteoriumCommand = {
GuildId: interaction.guildId,
Reason: Reason,
AttachmentProof: AttachmentProof ? AttachmentProof.url : "",
MuteDuration: Duration,
Duration: Duration,
CreatedAt: new Date(),
},
});
await GuildUser.timeout(
Expand Down
4 changes: 4 additions & 0 deletions src/commands/Moderation/Punishments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ export const Command: MeteoriumCommand = {
TotalBan++;
break;
}
case ModerationAction.TempBan: {
TotalBan++;
break;
}
case ModerationAction.Kick: {
TotalKick++;
break;
Expand Down
15 changes: 14 additions & 1 deletion src/commands/Moderation/RemoveCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const Command: MeteoriumCommand = {
.setColor("Red");

if (Case.Action == ModerationAction.Mute)
ConfirmationEmbed.addFields([{ name: "Duration", value: Case.MuteDuration }]);
ConfirmationEmbed.addFields([{ name: "Duration", value: Case.Duration }]);

const ConfirmationInteractionResult = await interaction.reply({
content: "Are you sure you want to remove this punishment?",
Expand Down Expand Up @@ -86,6 +86,19 @@ export const Command: MeteoriumCommand = {
Case.TargetUserId,
`Case ${CaseId} removed by ${interaction.user.username} (${interaction.user.id})`,
);
else if (Case.Action == ModerationAction.TempBan) {
await interaction.guild.members.unban(
Case.TargetUserId,
`Case ${CaseId} removed by ${interaction.user.username} (${interaction.user.id})`,
);
const ATB = await client.Database.activeTempBans.findFirst({
where: { GlobalCaseId: Case.GlobalCaseId },
});
if (ATB)
await client.Database.activeTempBans.delete({
where: { ActiveTempBanId: ATB.ActiveTempBanId },
});
}

await interaction.editReply({ content: "", embeds: [SuccessDeleteEmbed], components: [] });

Expand Down
171 changes: 171 additions & 0 deletions src/commands/Moderation/TempBan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { ModerationAction } from "@prisma/client";
import { SlashCommandBuilder, userMention } from "discord.js";
import type { MeteoriumCommand } from "..";
import { MeteoriumEmbedBuilder } from "../../util/MeteoriumEmbedBuilder";
import ms from "ms";

export const Command: MeteoriumCommand = {
InteractionData: new SlashCommandBuilder()
.setName("tempban")
.setDescription("Temporarily bans someone inside this server and create a new case regarding it")
.addUserOption((option) =>
option.setName("user").setDescription("The user to be temporarily banned").setRequired(true),
)
.addStringOption((option) =>
option
.setName("reason")
.setDescription("The reason on why the user was temporarily banned")
.setRequired(true),
)
.addStringOption((option) =>
option.setName("duration").setDescription("The duration of the temporary ban").setRequired(true),
)
.addAttachmentOption((option) =>
option
.setName("proof")
.setDescription("An media containing proof to prove the reason valid")
.setRequired(false),
),
async Callback(interaction, client) {
if (!interaction.member.permissions.has("BanMembers"))
return await interaction.editReply({
content: "You do not have permission to temporarily ban users from this server.",
});

const User = interaction.options.getUser("user", true);
const Reason = interaction.options.getString("reason", true);
const Duration = await interaction.options.getString("duration", true);
const AttachmentProof = interaction.options.getAttachment("proof", false);
const GuildUser = await interaction.guild.members.fetch(User).catch(() => null);
const GuildSchema = (await client.Database.guild.findUnique({ where: { GuildId: interaction.guildId } }))!;

if (User.id == interaction.user.id)
return await interaction.reply({ content: "You can't ban yourself!", ephemeral: true });
if (User.bot)
return await interaction.reply({ content: "You can't ban bots! (do it manually)", ephemeral: true });
if (
GuildUser &&
GuildUser.moderatable &&
GuildUser.roles.highest.position >= interaction.member.roles.highest.position
)
return interaction.reply({
content: "You (or the bot) can't moderate this user due to lack of permission/hierachy.",
ephemeral: true,
});

await client.Database.guild.update({
where: { GuildId: interaction.guildId },
data: { CurrentCaseId: GuildSchema.CurrentCaseId + 1 },
});
const CaseResult = await client.Database.moderationCase.create({
data: {
CaseId: GuildSchema.CurrentCaseId + 1,
Action: ModerationAction.TempBan,
TargetUserId: User.id,
ModeratorUserId: interaction.user.id,
GuildId: interaction.guildId,
Reason: Reason,
AttachmentProof: AttachmentProof ? AttachmentProof.url : "",
Duration: Duration,
CreatedAt: new Date(),
},
});
await client.Database.activeTempBans.create({
data: {
GlobalCaseId: CaseResult.GlobalCaseId,
},
});
await interaction.guild.members.ban(User, {
reason: `Case ${CaseResult.CaseId} by ${interaction.user.username} (${interaction.user.id}): ${Reason}`,
});

const LogEmbed = new MeteoriumEmbedBuilder(undefined, interaction.user)
.setAuthor({
name: `Case: #${CaseResult.CaseId} | tempban | ${User.username}`,
iconURL: User.displayAvatarURL({ extension: "png" }),
})
.addFields(
{ name: "User", value: userMention(User.id) },
{
name: "Moderator",
value: userMention(interaction.user.id),
},
{ name: "Reason", value: Reason },
{ name: "Duration", value: Duration },
)
.setImage(AttachmentProof ? AttachmentProof.url : null)
.setFooter({ text: `Id: ${User.id}` })
.setTimestamp()
.setColor("Red");

const PublicModLogChannel = await interaction.guild.channels
.fetch(GuildSchema.PublicModLogChannelId)
.catch(() => null);
if (PublicModLogChannel && PublicModLogChannel.isTextBased())
await PublicModLogChannel.send({ embeds: [LogEmbed] });

const GuildSetting = await client.Database.guild.findUnique({ where: { GuildId: interaction.guild.id } });
if (GuildSetting && GuildSetting.LoggingChannelId != "")
client.channels
.fetch(GuildSetting.LoggingChannelId)
.then(async (channel) => {
if (channel && channel.isTextBased())
await channel.send({
embeds: [
new MeteoriumEmbedBuilder(undefined, interaction.user)
.setTitle("Moderation action")
.setFields([
{ name: "Case id", value: String(CaseResult.CaseId) },
{
name: "Moderator",
value: `${interaction.user.username} (${
interaction.user.id
}) (${userMention(interaction.user.id)})`,
},
{
name: "Offending user",
value: `${User.username} (${User.id}) (${userMention(User.id)})`,
},
{ name: "Action", value: "Temp Ban" },
{ name: "Reason", value: Reason },
{ name: "Duration", value: Duration },
{ name: "Proof", value: AttachmentProof ? AttachmentProof.url : "N/A" },
])
.setImage(AttachmentProof ? AttachmentProof.url : null),
],
});
})
.catch(() => null);

return await interaction.reply({
content:
PublicModLogChannel != null && PublicModLogChannel.isTextBased()
? undefined
: "(Warning: could not send log message to the public mod log channel)",
embeds: [LogEmbed],
ephemeral: GuildSchema?.PublicModLogChannelId != "",
});
},
Init(client) {
setInterval(async () => {
await client.Database.$transaction(async (tx) => {
const ActiveTBs = await tx.activeTempBans.findMany({ include: { Case: true } });
const Promises = [
ActiveTBs.map(async (active) => {
const CreatedAt = active.Case.CreatedAt;
const ExpiresAt = new Date(Number(active.Case.CreatedAt) + ms(active.Case.Duration));
if (ExpiresAt <= CreatedAt) {
const Guild = await client.guilds.fetch(active.Case.GuildId);
const User = await client.users.fetch(active.Case.TargetUserId);
await Guild.members.unban(User);
return tx.activeTempBans.delete({ where: { ActiveTempBanId: active.ActiveTempBanId } });
}
return;
}),
];
await Promise.all(Promises);
return;
});
}, 10000);
},
};
1 change: 1 addition & 0 deletions src/commands/Moderation/Unban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const Command: MeteoriumCommand = {
GuildId: interaction.guildId,
Reason: Reason,
AttachmentProof: AttachmentProof ? AttachmentProof.url : "",
CreatedAt: new Date(),
},
});
await interaction.guild.members.unban(
Expand Down
1 change: 1 addition & 0 deletions src/commands/Moderation/Warn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const Command: MeteoriumCommand = {
GuildId: interaction.guildId,
Reason: Reason,
AttachmentProof: AttachmentProof ? AttachmentProof.url : "",
CreatedAt: new Date(),
},
});

Expand Down
2 changes: 2 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ export * as case from "./Moderation/Case";
export * as removecase from "./Moderation/RemoveCase";
export * as unban from "./Moderation/Unban";
export * as createcase from "./Moderation/CreateCase";
export * as tempban from "./Moderation/TempBan";

export type MeteoriumCommand = {
InteractionData: Pick<SlashCommandBuilder, "toJSON">;
Callback(interaction: ChatInputCommandInteraction<"cached">, client: MeteoriumClient): Awaitable<any>;
Autocomplete?(interaction: AutocompleteInteraction<"cached">, client: MeteoriumClient): Awaitable<any>;
Init?(client: MeteoriumClient): Awaitable<void>;
};
4 changes: 4 additions & 0 deletions src/util/MeteoriumClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export class MeteoriumClient extends Client<true> {
this.Commands.clear();
for (const [Name, { Command }] of Object.entries(Commands)) {
loginNS.debug(`Registering command -> ${Name} ${Command}`);
if (Command.Init) {
loginNS.debug(`Running command init -> ${Name} ${Command}`);
await Command.Init(this);
}
this.Commands.set(Name, Command);
}

Expand Down

0 comments on commit 7f75b6f

Please sign in to comment.