Major rework of submitting and deletion, empty implementation of context delete
This commit is contained in:
parent
125a872fbb
commit
9d57598352
|
@ -16,17 +16,31 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { REST, Routes } from "discord.js";
|
||||
import {
|
||||
REST,
|
||||
RESTPostAPIChatInputApplicationCommandsJSONBody,
|
||||
RESTPostAPIContextMenuApplicationCommandsJSONBody,
|
||||
Routes
|
||||
} from "discord.js";
|
||||
import { commands } from "../commands";
|
||||
import { BOT_ID, BOT_TOKEN } from "./config";
|
||||
import { DeployCommandsProps } from "./types";
|
||||
import Logger from "../utils/Logger";
|
||||
import { BotClient } from "./client";
|
||||
import { contextCommands } from "../contextcommands";
|
||||
|
||||
const logger = new Logger("Deployer");
|
||||
|
||||
const commandsData = Object.values(commands).map(command =>
|
||||
command.data.toJSON()
|
||||
let commandsData: (
|
||||
| RESTPostAPIChatInputApplicationCommandsJSONBody
|
||||
| RESTPostAPIContextMenuApplicationCommandsJSONBody
|
||||
)[] = [];
|
||||
|
||||
Object.values(commands).forEach(command =>
|
||||
commandsData.push(command.data.toJSON())
|
||||
);
|
||||
Object.values(contextCommands).forEach(command =>
|
||||
commandsData.push(command.data.toJSON())
|
||||
);
|
||||
|
||||
export const rest = new REST({ version: "9" }).setToken(BOT_TOKEN);
|
||||
|
|
|
@ -16,18 +16,11 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ChatInputCommandInteraction,
|
||||
EmbedBuilder,
|
||||
PermissionFlagsBits,
|
||||
SlashCommandBuilder,
|
||||
TextChannel
|
||||
} from "discord.js";
|
||||
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
|
||||
import { dt } from "../main";
|
||||
import { BotClient } from "../bot";
|
||||
import getRandomColor from "../utils/getRandomColor";
|
||||
import Logger from "../utils/Logger";
|
||||
import { messageOpts } from "../constants";
|
||||
import { deleteConfession } from "../commandutils";
|
||||
|
||||
const logger = new Logger("(/) confessdel");
|
||||
|
||||
|
@ -40,7 +33,6 @@ export const data = new SlashCommandBuilder()
|
|||
|
||||
export async function execute(interaction: ChatInputCommandInteraction) {
|
||||
const { id: guildId } = interaction.guild!;
|
||||
const { id: userId } = interaction.user;
|
||||
|
||||
// If there is no guild info, don't let the user delete anything
|
||||
if (!dt.getGuildInfo(guildId)) {
|
||||
|
@ -52,55 +44,8 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
|||
}
|
||||
|
||||
const idVal = interaction.options.getString("id")!;
|
||||
const result = dt.getConfession(guildId, idVal);
|
||||
// If there is a result, and the user is either an author or has manage messages
|
||||
const allowedByUser = result && result.authorId === userId;
|
||||
const allowedByMod =
|
||||
result &&
|
||||
interaction.memberPermissions?.has(PermissionFlagsBits.ManageMessages);
|
||||
|
||||
// If a confession is found with the given ID, check if the user is the one that posted it, and delete it if they are.
|
||||
// Otherwise, don't let the user delete anything.
|
||||
if (allowedByUser || allowedByMod) {
|
||||
const confession = dt.getConfession(guildId, idVal)!.messageId;
|
||||
const channelId = dt.getGuildInfo(guildId)!.settings.confessChannel;
|
||||
const emptyEmbed = new EmbedBuilder()
|
||||
.setColor(getRandomColor())
|
||||
.setTitle("Confession Deleted")
|
||||
.setDescription(
|
||||
allowedByUser
|
||||
? "[Confession removed by user]"
|
||||
: "[Confession removed by moderator]"
|
||||
);
|
||||
|
||||
// Replace the given confession with an empty embed
|
||||
(BotClient.channels.cache.get(channelId) as TextChannel).messages
|
||||
.fetch(confession)
|
||||
.then(message => {
|
||||
message.edit({
|
||||
embeds: [emptyEmbed]
|
||||
});
|
||||
|
||||
return interaction.reply({
|
||||
content: "Confession removed.",
|
||||
...messageOpts
|
||||
});
|
||||
})
|
||||
.catch(async err => {
|
||||
logger.error("An error occured deleting a confession:", err);
|
||||
|
||||
return interaction.reply({
|
||||
content: "An error occured when trying to delete that confession.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An error occured following up:", err));
|
||||
})
|
||||
} else {
|
||||
// If there was a result, the user wasn't allowed to remove it, otherwise it didn't exist.
|
||||
return interaction.reply({
|
||||
content: result ? "You are not allowed to remove this confession." : "Either the confession wasn't found or you may not be allowed to remove it.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A confession delete error occured:", err));
|
||||
}
|
||||
return deleteConfession(interaction, idVal).catch(err =>
|
||||
logger.error("An error occured:", err)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -93,34 +93,39 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
|||
const confessionId = interaction.options.getString("id")!;
|
||||
|
||||
if (dt.isBannedById(guildId, confessionId)) {
|
||||
return interaction.reply({
|
||||
content: "That user is already banned!",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A ban interaction error occured:", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: "That user is already banned!",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A ban interaction error occured:", err));
|
||||
}
|
||||
|
||||
const result = dt.addBanById(guildId, confessionId);
|
||||
|
||||
return interaction.reply({
|
||||
content: result ? "User was banned." : "No confession with that ID was found.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A ban interaction error occured:", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: result
|
||||
? "User was banned."
|
||||
: "No confession with that ID was found.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A ban interaction error occured:", err));
|
||||
|
||||
// /confessmod banuser <user>
|
||||
// /confessmod banuser <user>
|
||||
} else if (interaction.options.getSubcommand() === "banuser") {
|
||||
const { id: userId } = interaction.options.getUser("user")!;
|
||||
|
||||
const result = dt.addBanByUser(guildId, userId);
|
||||
|
||||
return interaction.reply({
|
||||
content: result ? "User was banned." : "How did we get here?",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.log("A ban user interaction error occured:", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: result ? "User was banned." : "How did we get here?",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.log("A ban user interaction error occured:", err));
|
||||
|
||||
// /confessmod list
|
||||
// /confessmod list
|
||||
} else if (interaction.options.getSubcommand() === "list") {
|
||||
const bannedMembers = dt.getBans(guildId);
|
||||
|
||||
|
@ -153,36 +158,43 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
|||
}
|
||||
};
|
||||
|
||||
return interaction.reply({
|
||||
content: determineContent(),
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A banlist interaction error occured:", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: determineContent(),
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A banlist interaction error occured:", err));
|
||||
|
||||
// /confessmod pardon <id>
|
||||
// /confessmod pardon <id>
|
||||
} else if (interaction.options.getSubcommand() === "pardon") {
|
||||
const result = dt.removeBanById(
|
||||
guildId,
|
||||
interaction.options.getString("id")!
|
||||
);
|
||||
|
||||
return interaction.reply({
|
||||
content: result ? "User was unbanned." : "No confession with that ID was found.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.log("An unban interaction error occured", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: result
|
||||
? "User was unbanned."
|
||||
: "No confession with that ID was found.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.log("An unban interaction error occured", err));
|
||||
|
||||
// /confessmod pardonuser <user>
|
||||
// /confessmod pardonuser <user>
|
||||
} else if (interaction.options.getSubcommand() === "pardonuser") {
|
||||
const { id: userId } = interaction.options.getUser("user")!;
|
||||
|
||||
const result = dt.removeBanByUser(guildId, userId);
|
||||
|
||||
return interaction.reply({
|
||||
content: result ? "User was unbanned." : "That user is not banned from confessions.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.log("Error replying to user ban interaction", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: result
|
||||
? "User was unbanned."
|
||||
: "That user is not banned from confessions.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.log("Error replying to user ban interaction", err));
|
||||
}
|
||||
|
||||
// Catch-all
|
||||
|
|
|
@ -26,6 +26,9 @@ export const data = new SlashCommandBuilder()
|
|||
const logger = new Logger("(/) ping");
|
||||
|
||||
export async function execute(interaction: CommandInteraction) {
|
||||
return interaction.reply("I'm an OSS confessions bot!")
|
||||
.catch(err => logger.error("I'm honestly suprised this even happened:", err));
|
||||
return interaction
|
||||
.reply("I'm an OSS confessions bot!")
|
||||
.catch(err =>
|
||||
logger.error("I'm honestly suprised this even happened:", err)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -43,11 +43,12 @@ export async function execute(interaction: CommandInteraction) {
|
|||
const { displayName: username } = interaction.user;
|
||||
|
||||
if (dt.checkSetup(guildId)) {
|
||||
return interaction.reply({
|
||||
content: "This guild has already been set up!",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An error occured during setup:", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: "This guild has already been set up!",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An error occured during setup:", err));
|
||||
}
|
||||
|
||||
let confessChannel: string, logChannel: string;
|
||||
|
|
|
@ -38,11 +38,12 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
|||
const { id: guildId, name: guildName } = interaction.guild!;
|
||||
|
||||
if (cooldownList.has(guildId)) {
|
||||
return interaction.reply({
|
||||
content: `You can only run the update command once every ${minutes} minutes.`,
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An update error occured:", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: `You can only run the update command once every ${minutes} minutes.`,
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An update error occured:", err));
|
||||
}
|
||||
|
||||
deployCommands({ guildId: guildId });
|
||||
|
@ -58,9 +59,10 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
|||
minutes * 60 * 1000
|
||||
);
|
||||
|
||||
return interaction.reply({
|
||||
content: "Commands refreshed.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An update error occured", err));
|
||||
return interaction
|
||||
.reply({
|
||||
content: "Commands refreshed.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An update error occured", err));
|
||||
}
|
||||
|
|
96
src/commandutils/deleteConfession.ts
Normal file
96
src/commandutils/deleteConfession.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Confoss: Anonymous confessions for Discord, free as in freedom and price!
|
||||
* Copyright (C) 2024 powermaker450
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ChatInputCommandInteraction,
|
||||
ContextMenuCommandInteraction,
|
||||
EmbedBuilder,
|
||||
PermissionFlagsBits,
|
||||
TextChannel
|
||||
} from "discord.js";
|
||||
import { dt } from "../main";
|
||||
import getRandomColor from "../utils/getRandomColor";
|
||||
import { BotClient } from "../bot";
|
||||
import { messageOpts } from "../constants";
|
||||
import Logger from "../utils/Logger";
|
||||
|
||||
const logger = new Logger("deleteConfession");
|
||||
|
||||
export async function deleteConfession(
|
||||
interaction: ChatInputCommandInteraction | ContextMenuCommandInteraction,
|
||||
idVal: string
|
||||
) {
|
||||
const { id: guildId } = interaction.guild!;
|
||||
const { id: userId } = interaction.user;
|
||||
|
||||
const result = dt.getConfession(guildId, idVal);
|
||||
// If there is a result, and the user is either an author or has manage messages
|
||||
const allowedByUser = result && result.authorId === userId;
|
||||
const allowedByMod =
|
||||
result &&
|
||||
interaction.memberPermissions?.has(PermissionFlagsBits.ManageMessages);
|
||||
|
||||
// If a confession is found with the given ID, check if the user is the one that posted it, and delete it if they are.
|
||||
// Otherwise, don't let the user delete anything.
|
||||
if (allowedByUser || allowedByMod) {
|
||||
const confession = dt.getConfession(guildId, idVal)!.messageId;
|
||||
const channelId = dt.getGuildInfo(guildId)!.settings.confessChannel;
|
||||
const emptyEmbed = new EmbedBuilder()
|
||||
.setColor(getRandomColor())
|
||||
.setTitle("Confession Deleted")
|
||||
.setDescription(
|
||||
allowedByUser
|
||||
? "[Confession removed by user]"
|
||||
: "[Confession removed by moderator]"
|
||||
);
|
||||
|
||||
// Replace the given confession with an empty embed
|
||||
(BotClient.channels.cache.get(channelId) as TextChannel).messages
|
||||
.fetch(confession)
|
||||
.then(message => {
|
||||
message.edit({
|
||||
embeds: [emptyEmbed]
|
||||
});
|
||||
|
||||
return interaction.reply({
|
||||
content: "Confession removed.",
|
||||
...messageOpts
|
||||
});
|
||||
})
|
||||
.catch(async err => {
|
||||
logger.error("An error occured deleting a confession:", err);
|
||||
|
||||
return interaction
|
||||
.reply({
|
||||
content: "An error occured when trying to delete that confession.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An error occured following up:", err));
|
||||
});
|
||||
} else {
|
||||
// If there was a result, the user wasn't allowed to remove it, otherwise it didn't exist.
|
||||
return interaction
|
||||
.reply({
|
||||
content: result
|
||||
? "You are not allowed to remove this confession."
|
||||
: "Either the confession wasn't found or you may not be allowed to remove it.",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("A confession delete error occured:", err));
|
||||
}
|
||||
}
|
|
@ -16,4 +16,5 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./deleteConfession";
|
||||
export * from "./submitConfession";
|
||||
|
|
48
src/contextcommands/contextdel.ts
Normal file
48
src/contextcommands/contextdel.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Confoss: Anonymous confessions for Discord, free as in freedom and price!
|
||||
* Copyright (C) 2024 powermaker450
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ApplicationCommandType,
|
||||
ContextMenuCommandBuilder,
|
||||
ContextMenuCommandInteraction,
|
||||
ContextMenuCommandType
|
||||
} from "discord.js";
|
||||
import Logger from "../utils/Logger";
|
||||
import { messageOpts } from "../constants";
|
||||
import { BotClient } from "../bot";
|
||||
|
||||
const logger = new Logger("(:) contextdel");
|
||||
|
||||
export const friendlyName = "Delete Confession";
|
||||
|
||||
export const data = new ContextMenuCommandBuilder()
|
||||
.setName(friendlyName)
|
||||
// This is what it's supposed to be, but tsc gets upset if the type isn't coerced
|
||||
// .setType(ApplicationCommandType.Message)
|
||||
.setType(ApplicationCommandType.Message as ContextMenuCommandType);
|
||||
|
||||
export async function execute(interaction: ContextMenuCommandInteraction) {
|
||||
const text = `Target: ${interaction.targetId}`;
|
||||
|
||||
logger.log(text);
|
||||
|
||||
return interaction.reply({
|
||||
content: text,
|
||||
...messageOpts
|
||||
});
|
||||
}
|
23
src/contextcommands/index.ts
Normal file
23
src/contextcommands/index.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Confoss: Anonymous confessions for Discord, free as in freedom and price!
|
||||
* Copyright (C) 2024 powermaker450
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as contextdel from "./contextdel";
|
||||
|
||||
export const contextCommands = {
|
||||
contextdel
|
||||
};
|
49
src/main.ts
49
src/main.ts
|
@ -16,7 +16,10 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ChatInputCommandInteraction, Events } from "discord.js";
|
||||
import {
|
||||
ChatInputCommandInteraction,
|
||||
Events
|
||||
} from "discord.js";
|
||||
import { BotClient, BOT_TOKEN, deployCommands } from "./bot";
|
||||
import { commands } from "./commands";
|
||||
import { StoreMan } from "./storeman";
|
||||
|
@ -24,6 +27,7 @@ import Logger from "./utils/Logger";
|
|||
import { submit } from "./modals";
|
||||
import { messageOpts } from "./constants";
|
||||
import { submitConfession } from "./commandutils";
|
||||
import { contextCommands } from "./contextcommands";
|
||||
|
||||
export const dt = new StoreMan(StoreMan.checkFile());
|
||||
const logger = new Logger("Main");
|
||||
|
@ -57,6 +61,20 @@ BotClient.on(Events.InteractionCreate, async interaction => {
|
|||
}
|
||||
});
|
||||
|
||||
BotClient.on(Events.InteractionCreate, async interaction => {
|
||||
if (!interaction.isContextMenuCommand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { commandName } = interaction;
|
||||
|
||||
for (const command of Object.values(contextCommands)) {
|
||||
if (command.friendlyName === commandName) {
|
||||
command.execute(interaction);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BotClient.on(Events.MessageDelete, async message => {
|
||||
const guildId = message.guild?.id!;
|
||||
if (!dt.getGuildInfo(guildId)) {
|
||||
|
@ -91,13 +109,19 @@ BotClient.on(Events.InteractionCreate, async interaction => {
|
|||
if (requestSubmit) {
|
||||
// Check if the user is banned from confessions before showing the modal
|
||||
dt.isBannedByUser(interaction.guild?.id!, interaction.user.id)
|
||||
? interaction.reply({
|
||||
content: "You are banned from confessions in this server!",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err => logger.error("An error occured during a requestSubmit", err))
|
||||
: interaction.showModal(submit)
|
||||
.catch(err => logger.error("An error occured during a requestSubmit", err));
|
||||
? interaction
|
||||
.reply({
|
||||
content: "You are banned from confessions in this server!",
|
||||
...messageOpts
|
||||
})
|
||||
.catch(err =>
|
||||
logger.error("An error occured during a requestSubmit", err)
|
||||
)
|
||||
: interaction
|
||||
.showModal(submit)
|
||||
.catch(err =>
|
||||
logger.error("An error occured during a requestSubmit", err)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -112,8 +136,13 @@ BotClient.on(Events.InteractionCreate, interaction => {
|
|||
"confessionAttachment"
|
||||
);
|
||||
|
||||
submitConfession(interaction, messageContent, attachment ? attachment : undefined)
|
||||
.catch(err => logger.error("An error occured when submitting a confession", err));
|
||||
submitConfession(
|
||||
interaction,
|
||||
messageContent,
|
||||
attachment ? attachment : undefined
|
||||
).catch(err =>
|
||||
logger.error("An error occured when submitting a confession", err)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue