Edit: Add command to edit existing records.
This currently requires global admin permissions. Each edit gets persisted in the history table.
This commit is contained in:
197
commands/edit.js
Normal file
197
commands/edit.js
Normal file
@@ -0,0 +1,197 @@
|
||||
const { SlashCommandBuilder, ComponentType, ActionRowBuilder, ButtonBuilder, ButtonStyle, ModalBuilder, TextInputStyle, TextInputBuilder } = require("discord.js");
|
||||
const { Character, Band, RecordHistory } = require("../models");
|
||||
const { UserUtils, GeneralUtils } = require("../util");
|
||||
const axios = require("axios");
|
||||
const fs = require("fs");
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("edit")
|
||||
.setDescription("Admin command to edit records")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("type")
|
||||
.setDescription("The thing to edit")
|
||||
.setRequired(true)
|
||||
.addChoices(
|
||||
{ name: 'character', value: 'character' },
|
||||
{ name: 'band', value: 'band' }
|
||||
)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("id")
|
||||
.setDescription("Thing ID")
|
||||
.setRequired(true)
|
||||
)
|
||||
.addAttachmentOption((option) =>
|
||||
option
|
||||
.setName("attachement")
|
||||
.setDescription("Attachement to be used")
|
||||
.setRequired(false)
|
||||
),
|
||||
permissionLevel: 2,
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply();
|
||||
let user = await UserUtils.getUserByDiscordId(interaction.member.id);
|
||||
|
||||
let options = [];
|
||||
let record;
|
||||
switch (interaction.options.getString("type")) {
|
||||
case "character":
|
||||
record = await Character.findByPk(interaction.options.getString("id"), { include: Band });
|
||||
if (!record) {
|
||||
interaction.editReply({ content: "Character not found" });
|
||||
return;
|
||||
}
|
||||
options = [ "name", "description", "imageIdentifier" ];
|
||||
break;
|
||||
case "band":
|
||||
options = [ "name", "description" ];
|
||||
break;
|
||||
default:
|
||||
interaction.reply({
|
||||
content: `Your permission level is ${await UserUtils.getPermissionLevel(interaction.member)}`,
|
||||
ephemeral: false
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
//row of button components to select what property to edit
|
||||
const row = new ActionRowBuilder();
|
||||
for (option of options) {
|
||||
row.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel(`Edit ${option}`)
|
||||
.setCustomId(`${option}-${interaction.id}`)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
);
|
||||
}
|
||||
|
||||
//show buttons
|
||||
let message = await interaction.editReply({ content: `You've selected [${record.identifier ?? record.id}] ${record.name}`, components: [row], fetchReply: true });
|
||||
|
||||
//filter only events from the user who triggered the command
|
||||
const filter = (m) => m.author.id === interaction.author.id && m.customId.endsWith(interaction.id);
|
||||
const collector = message.createMessageComponentCollector({ componentType: ComponentType.Button, time: 65000 })
|
||||
|
||||
collector.on('collect', async (m) => {
|
||||
let option = m.customId.split("-")[0];
|
||||
switch (option) {
|
||||
case 'name':
|
||||
let newName = await this.openStringModal(m, `Edit ${option} for ${record.name}`, "");
|
||||
if (newName) {
|
||||
await this.updateRecord(user, record, option, newName.value);
|
||||
}
|
||||
break;
|
||||
case 'description':
|
||||
let newDesc = await this.openParagraphModal(m, `Edit ${option} for ${record.name}`, "");
|
||||
if (newDesc) {
|
||||
await this.updateRecord(user, record, option, newDesc.value);
|
||||
}
|
||||
break;
|
||||
case 'imageIdentifier':
|
||||
m.deferReply();
|
||||
let allowedContentTypes = [ "image/png", "image/jpeg", "image/gif" ];
|
||||
let image = interaction.options.getAttachment("attachement");
|
||||
if (!image) {
|
||||
await m.reply({ content: "You must attach an image", ephemeral: true });
|
||||
return;
|
||||
}
|
||||
if (!allowedContentTypes.includes(image.contentType)) {
|
||||
await m.reply({ content: "An invalid image has been attached", ephemeral: true });
|
||||
return;
|
||||
}
|
||||
let identifier = `${record.Band.name}/${image.name}`;
|
||||
let path = `/app/assets/cards/${identifier}`;
|
||||
await this.downloadImage(image.attachment, path);
|
||||
await this.updateRecord(user, record, option, identifier);
|
||||
m.editReply({ content: "Attached image has been applied" });
|
||||
break;
|
||||
default:
|
||||
m.reply({ content: "Invalid selection" });
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
async downloadImage(url, path) {
|
||||
let imageBuffer = await axios.get(url, { responseType: 'arraybuffer' });
|
||||
fs.writeFileSync(path, imageBuffer.data);
|
||||
},
|
||||
|
||||
async openParagraphModal(interaction, title, placeholder) {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId('paragraphModal')
|
||||
.setTitle(title.substr(0, 44));
|
||||
|
||||
let row = new ActionRowBuilder();
|
||||
let textInput = new TextInputBuilder()
|
||||
.setCustomId(`input-${interaction.id}`)
|
||||
.setLabel("Enter new value")
|
||||
.setStyle(TextInputStyle.Paragraph)
|
||||
.setRequired(false)
|
||||
.setMaxLength(255)
|
||||
.setPlaceholder(placeholder ?? "We've been trying to get a hold of you about your car's extended warranty.");
|
||||
row.addComponents(textInput);
|
||||
modal.addComponents(row);
|
||||
|
||||
let message = await interaction.showModal(modal);
|
||||
|
||||
let submitted = await interaction.awaitModalSubmit({
|
||||
time: 300000,
|
||||
filter: i => i.user.id === interaction.user.id,
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return null
|
||||
})
|
||||
|
||||
if (submitted) {
|
||||
submitted.reply({ content: `You submitted: ${submitted.fields.getTextInputValue(`input-${interaction.id}`)}`})
|
||||
return { i: submitted, value: submitted.fields.getTextInputValue(`input-${interaction.id}`)};
|
||||
}
|
||||
},
|
||||
async openStringModal(interaction, title, placeholder) {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId('textModal')
|
||||
.setTitle(title.substr(0, 44));
|
||||
|
||||
let row = new ActionRowBuilder();
|
||||
let textInput = new TextInputBuilder()
|
||||
.setCustomId(`input-${interaction.id}`)
|
||||
.setLabel("Enter new value")
|
||||
.setStyle(TextInputStyle.Short)
|
||||
.setRequired(false)
|
||||
.setMaxLength(255)
|
||||
.setPlaceholder(placeholder ?? "");
|
||||
row.addComponents(textInput);
|
||||
modal.addComponents(row);
|
||||
|
||||
let message = await interaction.showModal(modal);
|
||||
|
||||
let submitted = await interaction.awaitModalSubmit({
|
||||
time: 300000,
|
||||
filter: i => i.user.id === interaction.user.id,
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return null
|
||||
})
|
||||
|
||||
if (submitted) {
|
||||
submitted.reply({ content: `You submitted: ${submitted.fields.getTextInputValue(`input-${interaction.id}`)}` });
|
||||
return { i: submitted, value: submitted.fields.getTextInputValue(`input-${interaction.id}`)};
|
||||
}
|
||||
},
|
||||
async updateRecord(user, record, property, value) {
|
||||
let history = {
|
||||
affectedId: record.id,
|
||||
userId: user.id,
|
||||
type: record.constructor.name,
|
||||
property: property,
|
||||
oldValue: record[property],
|
||||
newValue: value
|
||||
}
|
||||
record[property] = value;
|
||||
await record.save();
|
||||
await RecordHistory.create(history);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user