mirror of https://github.com/clickscodes/nucleus
Added options for stats channels, moderation command buttons and fixed the updating of stats channels
parent
708692bec3
commit
0bc0416355
@ -0,0 +1,144 @@
|
||||
import Discord, { CommandInteraction, MessageActionRow, MessageButton, TextInputComponent } from "discord.js";
|
||||
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
|
||||
import getEmojiByName from "../../utils/getEmojiByName.js";
|
||||
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
|
||||
import { WrappedCheck } from "jshaiku";
|
||||
import client from "../../utils/client.js";
|
||||
import { modalInteractionCollector } from "../../utils/dualCollector.js";
|
||||
import confirmationMessage from "../../utils/confirmationMessage.js";
|
||||
import keyValueList from "../../utils/generateKeyValueList.js";
|
||||
|
||||
const command = (builder: SlashCommandSubcommandBuilder) =>
|
||||
builder
|
||||
.setName("commands")
|
||||
.setDescription("Links and text shown to a user after a moderator action is performed")
|
||||
.addRoleOption(o => o.setName("role").setDescription("The role given when a member is muted"))
|
||||
|
||||
const callback = async (interaction: CommandInteraction): Promise<any> => {
|
||||
await interaction.reply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Loading")
|
||||
.setStatus("Danger")
|
||||
.setEmoji("NUCLEUS.LOADING")
|
||||
], ephemeral: true, fetchReply: true});
|
||||
let m;
|
||||
let clicked = "";
|
||||
if (interaction.options.getRole("role")) {
|
||||
let confirmation = await new confirmationMessage(interaction)
|
||||
.setEmoji("GUILD.ROLES.DELETE")
|
||||
.setTitle("Moderation Commands")
|
||||
.setDescription(keyValueList({
|
||||
role: `<@&${interaction.options.getRole("role").id}>`,
|
||||
}))
|
||||
.setColor("Danger")
|
||||
.send(true)
|
||||
if (confirmation.cancelled) return await interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Moderation Commands")
|
||||
.setDescription("No changes were made")
|
||||
.setStatus("Success")
|
||||
.setEmoji("GUILD.ROLES.CREATE")
|
||||
]})
|
||||
if (confirmation.success) {
|
||||
await client.database.guilds.write(interaction.guild.id, {["moderation.mute.role"]: interaction.options.getRole("role").id});
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
let config = await client.database.guilds.read(interaction.guild.id);
|
||||
let moderation = config.getKey("moderation");
|
||||
m = await interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Moderation Commands")
|
||||
.setEmoji("PUNISH.BAN.GREEN")
|
||||
.setStatus("Success")
|
||||
.setDescription(
|
||||
"These links are shown below the message sent in a user's DM when they are warned, banned, etc.\n\n" +
|
||||
`**Mute Role:** ` + (moderation.mute.role ? `<@&${moderation.mute.role}>` : "*None set*")
|
||||
)
|
||||
], components: [new MessageActionRow().addComponents([
|
||||
new MessageButton().setLabel("Warn").setEmoji(getEmojiByName("PUNISH.WARN.YELLOW", "id")).setCustomId("warn").setStyle("SECONDARY"),
|
||||
new MessageButton().setLabel("Mute").setEmoji(getEmojiByName("PUNISH.MUTE.YELLOW", "id")).setCustomId("mute").setStyle("SECONDARY"),
|
||||
new MessageButton().setLabel("Nickname").setEmoji(getEmojiByName("PUNISH.NICKNAME.GREEN", "id")).setCustomId("nickname").setStyle("SECONDARY")
|
||||
]), new MessageActionRow().addComponents([
|
||||
new MessageButton().setLabel("Kick").setEmoji(getEmojiByName("PUNISH.KICK.RED", "id")).setCustomId("kick").setStyle("SECONDARY"),
|
||||
new MessageButton().setLabel("Softban").setEmoji(getEmojiByName("PUNISH.BAN.YELLOW", "id")).setCustomId("softban").setStyle("SECONDARY"),
|
||||
new MessageButton().setLabel("Ban").setEmoji(getEmojiByName("PUNISH.BAN.RED", "id")).setCustomId("ban").setStyle("SECONDARY")
|
||||
]), new MessageActionRow().addComponents([
|
||||
new MessageButton().setLabel(
|
||||
clicked === "clearMuteRole" ? "Click again to confirm" : "Clear mute role"
|
||||
).setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setCustomId("clearMuteRole").setStyle("DANGER").setDisabled(!moderation.mute.role),
|
||||
new MessageButton()
|
||||
.setCustomId("timeout")
|
||||
.setLabel("Mute timeout " + (moderation.mute.timeout ? "Enabled" : "Disabled"))
|
||||
.setStyle(moderation.mute.timeout ? "SUCCESS" : "DANGER")
|
||||
.setEmoji(getEmojiByName("CONTROL." + (moderation.mute.timeout ? "TICK" : "CROSS"), "id"))
|
||||
])]});
|
||||
let i;
|
||||
try {
|
||||
i = await m.awaitMessageComponent({ time: 300000 });
|
||||
} catch (e) { return }
|
||||
let chosen = moderation[i.customId] ?? {text: null, url: null};
|
||||
if (i.component.customId === "clearMuteRole") {
|
||||
if (clicked === "clearMuteRole") {
|
||||
await client.database.guilds.write(interaction.guild.id, { moderation: { mute: { role: null } } });
|
||||
} else { clicked = "clearMuteRole" }
|
||||
} else { clicked = "" }
|
||||
if (i.component.customId === "timeout") {
|
||||
await i.deferUpdate()
|
||||
await client.database.guilds.write(interaction.guild.id, { moderation: { mute: { timeout: !moderation.mute.timeout } } });
|
||||
} else if (i.customId) {
|
||||
await i.showModal(new Discord.Modal().setCustomId("modal").setTitle(`Options for ${i.customId}`).addComponents(
|
||||
new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
|
||||
.setCustomId("name")
|
||||
.setLabel("Button text")
|
||||
.setMaxLength(100)
|
||||
.setRequired(false)
|
||||
.setStyle("SHORT")
|
||||
.setValue(chosen.text ?? "")
|
||||
),
|
||||
new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
|
||||
.setCustomId("url")
|
||||
.setLabel("URL - Type {id} to insert the user's ID")
|
||||
.setMaxLength(2000)
|
||||
.setRequired(false)
|
||||
.setStyle("SHORT")
|
||||
.setValue(chosen.link ?? "")
|
||||
)
|
||||
))
|
||||
await interaction.editReply({
|
||||
embeds: [new EmojiEmbed()
|
||||
.setTitle("Moderation Links")
|
||||
.setDescription("Modal opened. If you can't see it, click back and try again.")
|
||||
.setStatus("Success")
|
||||
.setEmoji("GUILD.TICKET.OPEN")
|
||||
], components: [new MessageActionRow().addComponents([new MessageButton()
|
||||
.setLabel("Back")
|
||||
.setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
|
||||
.setStyle("PRIMARY")
|
||||
.setCustomId("back")
|
||||
])]
|
||||
});
|
||||
let out;
|
||||
try {
|
||||
out = await modalInteractionCollector(m, (m) => m.channel.id == interaction.channel.id, (m) => true)
|
||||
} catch (e) { continue }
|
||||
if (out.fields) {
|
||||
let buttonText = out.fields.getTextInputValue("name");
|
||||
let buttonLink = out.fields.getTextInputValue("url").replace(/{id}/gi, "{id}");
|
||||
let current = chosen;
|
||||
if (current.text !== buttonText || current.link !== buttonLink) {
|
||||
chosen = { text: buttonText, link: buttonLink };
|
||||
await client.database.guilds.write(interaction.guild.id, { ["moderation" + i.customId]: { text: buttonText, link: buttonLink }});
|
||||
}
|
||||
} else { continue }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
|
||||
let member = (interaction.member as Discord.GuildMember)
|
||||
if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage server permission to use this command"
|
||||
return true;
|
||||
}
|
||||
|
||||
export { command };
|
||||
export { callback };
|
||||
export { check };
|
||||
@ -1,144 +0,0 @@
|
||||
import { ChannelType } from 'discord-api-types';
|
||||
import Discord, { CommandInteraction } from "discord.js";
|
||||
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
|
||||
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
|
||||
import { WrappedCheck } from "jshaiku";
|
||||
import confirmationMessage from '../../../utils/confirmationMessage.js';
|
||||
import keyValueList from '../../../utils/generateKeyValueList.js';
|
||||
import client from '../../../utils/client.js';
|
||||
|
||||
const command = (builder: SlashCommandSubcommandBuilder) =>
|
||||
builder
|
||||
.setName("ignore")
|
||||
.setDescription("Sets which users, channels and roles should be ignored")
|
||||
.addStringOption(o => o.setName("action").setDescription("Add or remove from the list").addChoices([
|
||||
["Add", "add"], ["Remove", "remove"]
|
||||
]).setRequired(true))
|
||||
.addChannelOption(o => o.setName("addchannel").setDescription("Add a channel that should be ignored").addChannelTypes([
|
||||
ChannelType.GuildText, ChannelType.GuildVoice, ChannelType.GuildNews, ChannelType.GuildPublicThread, ChannelType.GuildPrivateThread, ChannelType.GuildNewsThread
|
||||
]))
|
||||
.addUserOption(o => o.setName("adduser").setDescription("Add a user that should be ignored"))
|
||||
.addRoleOption(o => o.setName("addrole").setDescription("Add a role that should be ignored"))
|
||||
|
||||
const callback = async (interaction: CommandInteraction): Promise<any> => {
|
||||
let channel = interaction.options.getChannel("addchannel")
|
||||
let user = interaction.options.getUser("adduser")
|
||||
let role = interaction.options.getRole("addrole")
|
||||
await interaction.reply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Loading")
|
||||
.setStatus("Danger")
|
||||
.setEmoji("NUCLEUS.LOADING")
|
||||
], ephemeral: true, fetchReply: true});
|
||||
if (channel || user || role) {
|
||||
if (channel) {
|
||||
try {
|
||||
channel = interaction.guild.channels.cache.get(channel.id)
|
||||
} catch {
|
||||
return await interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setEmoji("CHANNEL.TEXT.DELETE")
|
||||
.setTitle("Logs > Ignore")
|
||||
.setDescription("The channel you provided is not a valid channel")
|
||||
.setStatus("Danger")
|
||||
]})
|
||||
}
|
||||
channel = channel as Discord.TextChannel
|
||||
if (channel.guild.id != interaction.guild.id) {
|
||||
return interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Logs > Ignore")
|
||||
.setDescription(`You must choose a channel in this server`)
|
||||
.setStatus("Danger")
|
||||
.setEmoji("CHANNEL.TEXT.DELETE")
|
||||
]});
|
||||
}
|
||||
}
|
||||
if (user) {
|
||||
try {
|
||||
user = interaction.guild.members.cache.get(user.id).user
|
||||
} catch {
|
||||
return await interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setEmoji("USER.DELETE")
|
||||
.setTitle("Logs > Ignore")
|
||||
.setDescription("The user you provided is not a valid user")
|
||||
.setStatus("Danger")
|
||||
]})
|
||||
}
|
||||
user = user as Discord.User
|
||||
}
|
||||
if (role) {
|
||||
try {
|
||||
role = interaction.guild.roles.cache.get(role.id)
|
||||
} catch {
|
||||
return await interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setEmoji("ROLE.DELETE")
|
||||
.setTitle("Logs > Ignore")
|
||||
.setDescription("The role you provided is not a valid role")
|
||||
.setStatus("Danger")
|
||||
]})
|
||||
}
|
||||
role = role as Discord.Role
|
||||
if (role.guild.id != interaction.guild.id) {
|
||||
return interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Logs > Ignore")
|
||||
.setDescription(`You must choose a role in this server`)
|
||||
.setStatus("Danger")
|
||||
.setEmoji("ROLE.DELETE")
|
||||
]});
|
||||
}
|
||||
}
|
||||
let changes = {}
|
||||
if (channel) changes["channel"] = channel.id
|
||||
if (user) changes["user"] = user.id
|
||||
if (role) changes["role"] = role.id
|
||||
let confirmation = await new confirmationMessage(interaction)
|
||||
.setEmoji("NUCLEUS.COMMANDS.IGNORE")
|
||||
.setTitle("Logs > Ignore")
|
||||
.setDescription(keyValueList(changes)
|
||||
+ `Are you sure you want to **${interaction.options.getString("action") == "add" ? "add" : "remove"}** these to the ignore list?`)
|
||||
.setColor("Warning")
|
||||
.send(true)
|
||||
if (confirmation.cancelled) return
|
||||
if (confirmation.success) {
|
||||
let data = client.database.guilds.read(interaction.guild.id)
|
||||
if (channel) data.logging.logs.ignore.channels.concat([channel.id])
|
||||
if (user) data.logging.logs.ignore.users.concat([user.id])
|
||||
if (role) data.logging.logs.ignore.roles.concat([role.id])
|
||||
if (interaction.options.getString("action") == "add") {
|
||||
await client.database.guilds.append(interaction.guild.id, data)
|
||||
} else {
|
||||
await client.database.guilds.remove(interaction.guild.id, data)
|
||||
}
|
||||
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
|
||||
try {
|
||||
let data = {
|
||||
meta:{
|
||||
type: 'logIgnoreUpdated',
|
||||
displayName: 'Ignored Groups Changed',
|
||||
calculateType: 'nucleusSettingsUpdated',
|
||||
color: NucleusColors.yellow,
|
||||
emoji: "CHANNEL.TEXT.EDIT",
|
||||
timestamp: new Date().getTime()
|
||||
},
|
||||
list: {
|
||||
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
|
||||
changedBy: entry(interaction.user.id, renderUser(interaction.user)),
|
||||
channel: entry(channel.id, renderChannel(channel)),
|
||||
},
|
||||
hidden: {
|
||||
guild: interaction.guild.id
|
||||
}
|
||||
}
|
||||
log(data);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
|
||||
let member = (interaction.member as Discord.GuildMember)
|
||||
if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
|
||||
return true;
|
||||
}
|
||||
|
||||
export { command };
|
||||
export { callback };
|
||||
export { check };
|
||||
@ -1,4 +0,0 @@
|
||||
const name = "stats";
|
||||
const description = "Settings for stats channels";
|
||||
|
||||
export { name, description };
|
||||
@ -1,120 +0,0 @@
|
||||
import { ChannelType } from 'discord-api-types';
|
||||
import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
|
||||
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
|
||||
import confirmationMessage from "../../../utils/confirmationMessage.js";
|
||||
import getEmojiByName from "../../../utils/getEmojiByName.js";
|
||||
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
|
||||
import { WrappedCheck } from "jshaiku";
|
||||
import client from "../../../utils/client.js";
|
||||
|
||||
const command = (builder: SlashCommandSubcommandBuilder) =>
|
||||
builder
|
||||
.setName("remove")
|
||||
.setDescription("Stops updating channels when a member joins or leaves")
|
||||
.addChannelOption(option => option.setName("channel").setDescription("The channel to stop updating").addChannelTypes([
|
||||
ChannelType.GuildNews, ChannelType.GuildText
|
||||
]).setRequired(true))
|
||||
|
||||
const callback = async (interaction: CommandInteraction): Promise<any> => {
|
||||
let m;
|
||||
m = await interaction.reply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Loading")
|
||||
.setStatus("Danger")
|
||||
.setEmoji("NUCLEUS.LOADING")
|
||||
], ephemeral: true, fetchReply: true});
|
||||
if (interaction.options.getChannel("channel")) {
|
||||
let config = client.database.guilds.read(interaction.guild.id);
|
||||
let channel
|
||||
try {
|
||||
channel = interaction.options.getChannel("channel")
|
||||
} catch {
|
||||
return await interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setEmoji("CHANNEL.TEXT.DELETE")
|
||||
.setTitle("Stats Channel")
|
||||
.setDescription("The channel you provided is not a valid channel")
|
||||
.setStatus("Danger")
|
||||
]})
|
||||
}
|
||||
channel = channel as Discord.TextChannel
|
||||
if (channel.guild.id != interaction.guild.id) {
|
||||
return interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Stats Channel")
|
||||
.setDescription(`You must choose a channel in this server`)
|
||||
.setStatus("Danger")
|
||||
.setEmoji("CHANNEL.TEXT.DELETE")
|
||||
]});
|
||||
}
|
||||
// check if the channel is not in the list
|
||||
let allow = false;
|
||||
for (let c of config.stats) { if (c.channel == channel.id) allow = true; }
|
||||
if (!allow) {
|
||||
return interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Stats Channel")
|
||||
.setDescription(`That channel is not a stats channel`)
|
||||
.setStatus("Danger")
|
||||
.setEmoji("CHANNEL.TEXT.DELETE")
|
||||
]});
|
||||
}
|
||||
let confirmation = await new confirmationMessage(interaction)
|
||||
.setEmoji("CHANNEL.TEXT.EDIT")
|
||||
.setTitle("Stats Channel")
|
||||
.setDescription(`Are you sure you want to stop <#${channel.id}> updating?`)
|
||||
.setColor("Warning")
|
||||
.setInverted(true)
|
||||
.send(true)
|
||||
if (confirmation.cancelled) return
|
||||
if (confirmation.success) {
|
||||
try {
|
||||
let channel = interaction.options.getChannel("channel")
|
||||
await client.database.guilds.write(interaction.guild.id, {}, [`stats.${channel.id}`]);
|
||||
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
|
||||
try {
|
||||
let data = {
|
||||
meta:{
|
||||
type: 'statsChannelUpdate',
|
||||
displayName: 'Stats Channel Removed',
|
||||
calculateType: 'nucleusSettingsUpdated',
|
||||
color: NucleusColors.red,
|
||||
emoji: "CHANNEL.TEXT.EDIT",
|
||||
timestamp: new Date().getTime()
|
||||
},
|
||||
list: {
|
||||
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
|
||||
changedBy: entry(interaction.user.id, renderUser(interaction.user)),
|
||||
channel: entry(channel.id, renderChannel(channel)),
|
||||
},
|
||||
hidden: {
|
||||
guild: interaction.guild.id
|
||||
}
|
||||
}
|
||||
log(data);
|
||||
} catch {}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Stats Channel")
|
||||
.setDescription(`Something went wrong and the stats channel could not be reset`)
|
||||
.setStatus("Danger")
|
||||
.setEmoji("CHANNEL.TEXT.DELETE")
|
||||
], components: []});
|
||||
}
|
||||
} else {
|
||||
return interaction.editReply({embeds: [new EmojiEmbed()
|
||||
.setTitle("Stats Channel")
|
||||
.setDescription(`No changes were made`)
|
||||
.setStatus("Success")
|
||||
.setEmoji("CHANNEL.TEXT.CREATE")
|
||||
], components: []});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
|
||||
let member = (interaction.member as Discord.GuildMember)
|
||||
if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
|
||||
return true;
|
||||
}
|
||||
|
||||
export { command };
|
||||
export { callback };
|
||||
export { check };
|
||||
Loading…
Reference in new issue