few changes
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index e94035e..8da4f1c 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -4,7 +4,8 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from '../../utils/readConfig.js'
+import readConfig from '../../utils/readConfig.js';
+import addPlurals from "../../utils/plurals.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -27,7 +28,7 @@
"reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
})
+ `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n`
- + `${interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0} day${interaction.options.getInteger("delete") === 1 || interaction.options.getInteger("delete") === null ? "s" : ""} of messages will be deleted\n\n` // TODO:[s addition]
+ + `${addPlurals(interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0, "day")} of messages will be deleted\n\n`
+ `Are you sure you want to ban <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
// pluralize("day", interaction.options.getInteger("delete"))
@@ -57,10 +58,37 @@
}
} catch {}
try {
- (interaction.options.getMember("user") as GuildMember).ban({
+ let member = (interaction.options.getMember("user") as GuildMember)
+ let reason = interaction.options.getString("reason") ?? "No reason provided"
+ member.ban({
days: Number(interaction.options.getInteger("delete") ?? 0),
- reason: interaction.options.getString("reason") ?? "No reason provided"
+ reason: reason
})
+ // @ts-ignore
+ const { log, NucleusColors, entry, renderUser, renderDelta } = interaction.user.client.logger
+ let data = {
+ meta: {
+ type: 'memberBan',
+ displayName: 'Member Banned',
+ calculateType: 'guildMemberPunish',
+ color: NucleusColors.red,
+ emoji: "PUNISH.BAN.RED",
+ timestamp: new Date().getTime()
+ },
+ list: {
+ id: entry(member.user.id, `\`${member.user.id}\``),
+ name: entry(member.user.id, renderUser(member.user)),
+ banned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+ bannedBy: entry(interaction.user.id, renderUser(interaction.user)),
+ reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
+ accountCreated: entry(member.user.createdAt, renderDelta(member.user.createdAt)),
+ serverMemberCount: interaction.guild.memberCount,
+ },
+ hidden: {
+ guild: interaction.guild.id
+ }
+ }
+ log(data, member.user.client);
} catch {
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setEmoji("PUNISH.BAN.RED")
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index 34a1571..b6ab653 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -1,4 +1,5 @@
import { CommandInteraction, GuildMember, MessageActionRow, MessageButton } from "discord.js";
+import humanizeDuration from 'humanize-duration';
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { WrappedCheck } from "jshaiku";
import confirmationMessage from "../../utils/confirmationMessage.js";
@@ -56,6 +57,35 @@
} catch {}
try {
(interaction.options.getMember("user") as GuildMember).kick(interaction.options.getString("reason") ?? "No reason provided.")
+ let member = (interaction.options.getMember("user") as GuildMember)
+ let reason = interaction.options.getString("reason") ?? null
+ // @ts-ignore
+ const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta } = member.client.logger
+ let data = {
+ meta: {
+ type: 'memberKick',
+ displayName: 'Member Kicked',
+ calculateType: 'guildMemberPunish',
+ color: NucleusColors.red,
+ emoji: "PUNISH.KICK.RED",
+ timestamp: new Date().getTime()
+ },
+ list: {
+ id: entry(member.id, `\`${member.id}\``),
+ name: entry(member.id, renderUser(member.user)),
+ joined: entry(member.joinedAt, renderDelta(member.joinedAt)),
+ kicked: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+ kickedBy: entry(interaction.user.id, renderUser(interaction.user)),
+ reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
+ timeInServer: entry(new Date().getTime() - member.joinedTimestamp, humanizeDuration(new Date().getTime() - member.joinedTimestamp, { round: true })),
+ accountCreated: entry(member.user.createdAt, renderDelta(member.user.createdAt)),
+ serverMemberCount: member.guild.memberCount,
+ },
+ hidden: {
+ guild: member.guild.id
+ }
+ }
+ log(data, member.client);
} catch {
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setEmoji("PUNISH.KICK.RED")
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index 165d906..3d6d912 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -21,7 +21,6 @@
.addStringOption(option => option.setName("reason").setDescription("The reason for the mute").setRequired(false))
.addStringOption(option => option.setName("notify").setDescription("If the user should get a message when they are muted | Default yes").setRequired(false)
.addChoices([["Yes", "yes"], ["No", "no"]]))
- // TODO: notify the user when the mute is lifted
const callback = async (interaction: CommandInteraction) => {
// @ts-ignore
@@ -34,6 +33,10 @@
minutes: interaction.options.getInteger("minutes") || 0,
seconds: interaction.options.getInteger("seconds") || 0
}
+ let config = await readConfig(interaction.guild.id)
+ let serverSettingsDescription = (config.moderation.mute.timeout ? "given a timeout" : "")
+ if (config.moderation.mute.role) serverSettingsDescription += (serverSettingsDescription ? " and " : "") + `given the <@&${config.moderation.mute.role}> role`
+
let muteTime = (time.days * 24 * 60 * 60) + (time.hours * 60 * 60) + (time.minutes * 60) + time.seconds
if (muteTime == 0) {
let m = await interaction.reply({embeds: [
@@ -126,6 +129,7 @@
"time": `${humanizeDuration(muteTime * 1000, {round: true})}`,
"reason": `\n> ${reason ? reason : "*No reason provided*"}`
})
+ + `The user will be ` + serverSettingsDescription + "\n"
+ `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
+ `Are you sure you want to mute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
@@ -157,7 +161,12 @@
}
} catch {}
try {
- (interaction.options.getMember("user") as GuildMember).timeout(muteTime * 1000, interaction.options.getString("reason") || "No reason provided")
+ if (config.moderation.mute.timeout) {
+ (interaction.options.getMember("user") as GuildMember).timeout(muteTime * 1000, interaction.options.getString("reason") || "No reason provided")
+ }
+ if (config.moderation.mute.role) {
+ (interaction.options.getMember("user") as GuildMember).roles.add(config.moderation.mute.role)
+ }
} catch {
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setEmoji("PUNISH.MUTE.RED")
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index 9584055..72b2524 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -45,8 +45,8 @@
embeds: [new generateEmojiEmbed()
.setEmoji("PUNISH.NICKNAME.RED")
.setTitle("Nickname changed")
- .setDescription(`Your nickname was ${interaction.options.getString("name") ? "changed" : "cleared"} in ${interaction.guild.name}` +
- (interaction.options.getString("name") ? ` it is now: ${interaction.options.getString("name")}` : ".") + "\n\n" +
+ .setDescription(`Your nickname was ${interaction.options.getString("name") ? "changed" : "cleared"} in ${interaction.guild.name}.` +
+ (interaction.options.getString("name") ? ` it is now: ${interaction.options.getString("name")}` : "") + "\n\n" +
(confirmation.buttonClicked ? `You can appeal this in this ticket: <#${confirmation.response}>` : ``))
.setStatus("Danger")
]
@@ -55,7 +55,33 @@
}
} catch {}
try {
- (interaction.options.getMember("user") as GuildMember).setNickname(interaction.options.getString("name") ?? null, "Nucleus Nickname command")
+ let member = (interaction.options.getMember("user") as GuildMember)
+ let before = member.nickname
+ let nickname = interaction.options.getString("name")
+ member.setNickname(nickname ?? null, "Nucleus Nickname command")
+ // @ts-ignore
+ const { log, NucleusColors, entry, renderUser, renderDelta, getAuditLog } = interaction.client.logger
+ let data = {
+ meta: {
+ type: 'memberUpdate',
+ displayName: 'Member Updated',
+ calculateType: 'guildMemberUpdate',
+ color: NucleusColors.yellow,
+ emoji: "PUNISH.NICKNAME.YELLOW",
+ timestamp: new Date().getTime()
+ },
+ list: {
+ id: entry(member.id, `\`${member.id}\``),
+ before: entry(before, before ? before : '*None*'),
+ after: entry(nickname, nickname ? nickname : '*None*'),
+ updated: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+ updatedBy: entry(interaction.user.id, renderUser(interaction.user))
+ },
+ hidden: {
+ guild: interaction.guild.id
+ }
+ }
+ log(data, interaction.client);
} catch {
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setEmoji("PUNISH.NICKNAME.RED")
@@ -99,6 +125,8 @@
if ((interaction.member as GuildMember).id == interaction.guild.ownerId) return true
// Check if the user has manage_nicknames permission
if (! (interaction.member as GuildMember).permissions.has("MANAGE_NICKNAMES")) throw "You do not have the `manage_nicknames` permission";
+ // Allow changing your own nickname
+ if (member == apply) return true
// Check if the user is below on the role list
if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
// Allow change
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 29c228f..a1c8fe3 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -107,13 +107,15 @@
let amount;
try { amount = parseInt(component.customId); } catch { break; }
let messages;
- (interaction.channel as TextChannel).messages.fetch({limit: amount}).then(async (ms) => {
+ await (interaction.channel as TextChannel).messages.fetch({limit: amount}).then(async (ms) => {
if (user) {
ms = ms.filter(m => m.author.id === user.id)
}
messages = await (channel as TextChannel).bulkDelete(ms, true);
})
- deleted = deleted.concat(messages.map(m => m))
+ if (messages) {
+ deleted = deleted.concat(messages.map(m => m))
+ }
}
if (deleted.length === 0) return await interaction.editReply({
embeds: [
@@ -127,6 +129,28 @@
})
let attachmentObject;
try {
+ // @ts-ignore
+ const { log, NucleusColors, entry, renderUser, renderChannel } = interaction.user.client.logger
+ let data = {
+ meta: {
+ type: 'channelPurge',
+ displayName: 'Channel Purged',
+ calculateType: 'messageDelete',
+ color: NucleusColors.red,
+ emoji: "PUNISH.BAN.RED",
+ timestamp: new Date().getTime()
+ },
+ list: {
+ id: entry(interaction.user.id, `\`${interaction.user.id}\``),
+ purgedBy: entry(interaction.user.id, renderUser(interaction.user)),
+ channel: entry(interaction.channel.id, renderChannel(interaction.channel)),
+ messagesCleared: entry(deleted.length, deleted.length),
+ },
+ hidden: {
+ guild: interaction.guild.id
+ }
+ }
+ log(data, interaction.user.client);
let out = ""
deleted.reverse().forEach(message => {
out += `${message.author.username}#${message.author.discriminator} (${message.author.id}) [${new Date(message.createdTimestamp).toISOString()}]\n`
@@ -177,7 +201,7 @@
.setEmoji("CHANNEL.PURGE.RED")
.setTitle("Purge")
.setDescription(keyValueList({
- "channel": `<#${channel.id}> (${(channel as GuildChannel).name})` + ("[This channel]"),
+ "channel": `<#${channel.id}>`,
"amount": interaction.options.getInteger("amount").toString(),
"reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
}))
@@ -206,6 +230,28 @@
}
let attachmentObject;
try {
+ // @ts-ignore
+ const { log, NucleusColors, entry, renderUser, renderChannel } = interaction.user.client.logger
+ let data = {
+ meta: {
+ type: 'channelPurge',
+ displayName: 'Channel Purged',
+ calculateType: 'messageDelete',
+ color: NucleusColors.red,
+ emoji: "PUNISH.BAN.RED",
+ timestamp: new Date().getTime()
+ },
+ list: {
+ id: entry(interaction.user.id, `\`${interaction.user.id}\``),
+ purgedBy: entry(interaction.user.id, renderUser(interaction.user)),
+ channel: entry(interaction.channel.id, renderChannel(interaction.channel)),
+ messagesCleared: entry(messages.size, messages.size),
+ },
+ hidden: {
+ guild: interaction.guild.id
+ }
+ }
+ log(data, interaction.user.client);
let out = ""
messages.reverse().forEach(message => {
out += `${message.author.username}#${message.author.discriminator} (${message.author.id}) [${new Date(message.createdTimestamp).toISOString()}]\n`
diff --git a/src/commands/mod/softban.ts b/src/commands/mod/softban.ts
index 44d425a..2b9643d 100644
--- a/src/commands/mod/softban.ts
+++ b/src/commands/mod/softban.ts
@@ -4,7 +4,8 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from '../../utils/readConfig.js'
+import readConfig from '../../utils/readConfig.js';
+import addPlurals from '../../utils/plurals.js';
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -27,7 +28,7 @@
"reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
})
+ `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n`
- + `${interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0} day${interaction.options.getInteger("delete") === 1 || interaction.options.getInteger("delete") === null ? "s" : ""} of messages will be deleted\n\n` // TODO:[s addition]
+ + `${addPlurals(interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0, "day")} of messages will be deleted\n\n`
+ `Are you sure you want to softban <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
// pluralize("day", interaction.options.getInteger("delete"))
diff --git a/src/commands/mod/unban.ts b/src/commands/mod/unban.ts
index 3ffc001..f96a7bd 100644
--- a/src/commands/mod/unban.ts
+++ b/src/commands/mod/unban.ts
@@ -1,18 +1,102 @@
-import { CommandInteraction } from "discord.js";
+import { CommandInteraction, GuildMember, User } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { WrappedCheck } from "jshaiku";
+import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import keyValueList from "../../utils/generateKeyValueList.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("unban")
.setDescription("Unbans a user")
+ .addStringOption(option => option.setName("user").setDescription("The user to unban (Username or ID)").setRequired(true))
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [mod/unban]");
+const callback = async (interaction: CommandInteraction) => { // TODO: User search
+ let bans = await interaction.guild.bans.fetch()
+ let user = interaction.options.getString("user")
+ let resolved = bans.find(ban => ban.user.id == user)
+ if (!resolved) resolved = bans.find(ban => ban.user.username.toLowerCase() == user.toLowerCase())
+ if (!resolved) resolved = bans.find(ban => ban.user.tag.toLowerCase() == user.toLowerCase())
+ if (!resolved) {
+ return interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Unban")
+ .setDescription(`Could not find any user called \`${user}\``)
+ .setEmoji("PUNISH.UNBAN.RED")
+ .setStatus("Danger")
+ ], ephemeral: true})
+ }
+ // TODO:[Modals] Replace this with a modal
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("PUNISH.UNBAN.RED")
+ .setTitle("Unban")
+ .setDescription(keyValueList({
+ "user": `${resolved.user.username} [<@${resolved.user.id}>]`,
+ })
+ + `Are you sure you want to unban <@${resolved.user.id}>?`)
+ .setColor("Danger")
+ .send()
+ if (confirmation.success) {
+ try {
+ await interaction.guild.members.unban(resolved.user as User, "Unban");
+ let member = (resolved.user as User)
+ // @ts-ignore
+ const { log, NucleusColors, entry, renderUser, renderDelta } = interaction.user.client.logger
+ let data = {
+ meta: {
+ type: 'memberUnban',
+ displayName: 'Member Unbanned',
+ calculateType: 'guildMemberPunish',
+ color: NucleusColors.green,
+ emoji: "PUNISH.BAN.GREEN",
+ timestamp: new Date().getTime()
+ },
+ list: {
+ id: entry(member.id, `\`${member.id}\``),
+ name: entry(member.id, renderUser(member)),
+ unbanned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+ unbannedBy: entry(interaction.user.id, renderUser(interaction.user)),
+ accountCreated: entry(member.createdAt, renderDelta(member.createdAt)),
+ },
+ hidden: {
+ guild: interaction.guild.id
+ }
+ }
+ log(data, member.client);
+ } catch {
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("PUNISH.UNBAN.RED")
+ .setTitle(`Unban`)
+ .setDescription("Something went wrong and the user was not unbanned")
+ .setStatus("Danger")
+ ], components: []})
+ }
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji(`PUNISH.UNBAN.GREEN`)
+ .setTitle(`Unban`)
+ .setDescription("The member was unbanned")
+ .setStatus("Success")
+ ], components: []})
+ } else {
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("PUNISH.UNBAN.GREEN")
+ .setTitle(`Unban`)
+ .setDescription("No changes were made")
+ .setStatus("Success")
+ ], components: []})
+ }
}
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
+ let member = (interaction.member as GuildMember)
+ let me = (interaction.guild.me as GuildMember)
+ // Check if Nucleus can unban members
+ if (! interaction.guild.me.permissions.has("BAN_MEMBERS")) throw "I do not have the `ban_members` permission";
+ // Allow the owner to unban anyone
+ if ((interaction.member as GuildMember).id == interaction.guild.ownerId) return true
+ // Check if the user has ban_members permission
+ if (! (interaction.member as GuildMember).permissions.has("BAN_MEMBERS")) throw "You do not have the `ban_members` permission";
+ // Allow unban
+ return true
}
export { command, callback, check };
\ No newline at end of file
diff --git a/src/commands/nucleus/suggest.ts b/src/commands/nucleus/suggest.ts
index 36338dc..0512020 100644
--- a/src/commands/nucleus/suggest.ts
+++ b/src/commands/nucleus/suggest.ts
@@ -11,9 +11,9 @@
.addStringOption(option => option.setName("suggestion").setDescription("The suggestion to send").setRequired(true))
const callback = async (interaction: CommandInteraction) => {
- // @ts-ignore
+ // @ts-ignore
const { renderUser } = interaction.client.logger
- let suggestion = interaction.options.getString("suggestion");
+ let suggestion = interaction.options.getString("suggestion");
let confirmation = await new confirmationMessage(interaction)
.setEmoji("ICONS.OPP.ADD")
.setTitle("Suggest")
@@ -23,14 +23,14 @@
.send()
if (confirmation.success) {
await (interaction.client.channels.cache.get('955161206459600976') as Discord.TextChannel).send({
- embeds: [
- new generateEmojiEmbed()
- .setTitle(`Suggestion`)
- .setDescription(`**From:** ${renderUser(interaction.member.user)}\n**Suggestion:**\n> ${suggestion}`)
- .setStatus("Danger")
- .setEmoji("NUCLEUS.LOGO")
- ]
- })
+ embeds: [
+ new generateEmojiEmbed()
+ .setTitle(`Suggestion`)
+ .setDescription(`**From:** ${renderUser(interaction.member.user)}\n**Suggestion:**\n> ${suggestion}`)
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOGO")
+ ]
+ })
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setEmoji("ICONS.ADD")
.setTitle(`Suggest`)
diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts
index da6a37a..ebbef82 100644
--- a/src/commands/user/track.ts
+++ b/src/commands/user/track.ts
@@ -5,6 +5,7 @@
import getEmojiByName from "../../utils/getEmojiByName.js";
import generateKeyValueList from "../../utils/generateKeyValueList.js";
import readConfig from "../../utils/readConfig.js";
+import addPlural from "../../utils/plurals.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -45,7 +46,7 @@
default: index == track,
label: option.name,
value: index.toString(),
- description: option.track.length == 0 ? "No" : option.track.length + " role" + (option.track.length == 1 ? "" : "s"), // TODO[s addition]
+ description: option.track.length == 0 ? "No" : addPlural(option.track.length, "role"),
emoji: interaction.client.emojis.resolve(getEmojiByName("TRACKS.SINGLE." + (hasRoleInTrack ? "ACTIVE" : "INACTIVE"), "id"))
})
})).setCustomId("select").setMaxValues(1)