mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2024-12-23 00:03:09 +02:00
Make edit button work
This commit is contained in:
parent
44ee84d8f7
commit
34a4e071b5
@ -10,6 +10,7 @@ const env = {
|
|||||||
HTTP_BIND: 8080,
|
HTTP_BIND: 8080,
|
||||||
HTTP_EXTERNAL: 'http://localhost:8080',
|
HTTP_EXTERNAL: 'http://localhost:8080',
|
||||||
PORTAL: '',
|
PORTAL: '',
|
||||||
|
PUBLIC: false,
|
||||||
SUPER: '319467558166069248',
|
SUPER: '319467558166069248',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
const { Button } = require('@eartharoid/dbf');
|
const { Button } = require('@eartharoid/dbf');
|
||||||
|
const {
|
||||||
|
ActionRowBuilder,
|
||||||
|
ModalBuilder,
|
||||||
|
SelectMenuBuilder,
|
||||||
|
SelectMenuOptionBuilder,
|
||||||
|
TextInputBuilder,
|
||||||
|
TextInputStyle,
|
||||||
|
} = require('discord.js');
|
||||||
|
const emoji = require('node-emoji');
|
||||||
|
|
||||||
module.exports = class EditButton extends Button {
|
module.exports = class EditButton extends Button {
|
||||||
constructor(client, options) {
|
constructor(client, options) {
|
||||||
@ -8,5 +17,93 @@ module.exports = class EditButton extends Button {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(id, interaction) { }
|
async run(id, interaction) {
|
||||||
|
/** @type {import("client")} */
|
||||||
|
const client = this.client;
|
||||||
|
|
||||||
|
const ticket = await client.prisma.ticket.findUnique({
|
||||||
|
select: {
|
||||||
|
category: { select: { name: true } },
|
||||||
|
guild: { select: { locale: true } },
|
||||||
|
questionAnswers: { include: { question: true } },
|
||||||
|
topic: true,
|
||||||
|
},
|
||||||
|
where: { id: interaction.channel.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMessage = client.i18n.getLocale(ticket.guild.locale);
|
||||||
|
|
||||||
|
if (ticket.questionAnswers.length === 0) {
|
||||||
|
await interaction.showModal(
|
||||||
|
new ModalBuilder()
|
||||||
|
.setCustomId(JSON.stringify({
|
||||||
|
action: 'topic',
|
||||||
|
edit: true,
|
||||||
|
}))
|
||||||
|
.setTitle(ticket.category.name)
|
||||||
|
.setComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.setComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('topic')
|
||||||
|
.setLabel(getMessage('modals.topic.label'))
|
||||||
|
.setStyle(TextInputStyle.Paragraph)
|
||||||
|
.setMaxLength(1000)
|
||||||
|
.setMinLength(5)
|
||||||
|
.setPlaceholder(getMessage('modals.topic.placeholder'))
|
||||||
|
.setRequired(true)
|
||||||
|
.setValue(ticket.topic || ''),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await interaction.showModal(
|
||||||
|
new ModalBuilder()
|
||||||
|
.setCustomId(JSON.stringify({
|
||||||
|
action: 'questions',
|
||||||
|
edit: true,
|
||||||
|
}))
|
||||||
|
.setTitle(ticket.category.name)
|
||||||
|
.setComponents(
|
||||||
|
ticket.questionAnswers
|
||||||
|
.filter(a => a.question.type === 'TEXT') // TODO: remove this when modals support select menus
|
||||||
|
.map(a => {
|
||||||
|
if (a.question.type === 'TEXT') {
|
||||||
|
return new ActionRowBuilder()
|
||||||
|
.setComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId(String(a.id))
|
||||||
|
.setLabel(a.question.label)
|
||||||
|
.setStyle(a.question.style)
|
||||||
|
.setMaxLength(Math.min(a.question.maxLength, 1000))
|
||||||
|
.setMinLength(a.question.minLength)
|
||||||
|
.setPlaceholder(a.question.placeholder)
|
||||||
|
.setRequired(a.question.required)
|
||||||
|
.setValue(a.value || a.question.value),
|
||||||
|
);
|
||||||
|
} else if (a.question.type === 'MENU') {
|
||||||
|
return new ActionRowBuilder()
|
||||||
|
.setComponents(
|
||||||
|
new SelectMenuBuilder()
|
||||||
|
.setCustomId(a.question.id)
|
||||||
|
.setPlaceholder(a.question.placeholder || a.question.label)
|
||||||
|
.setMaxValues(a.question.maxLength)
|
||||||
|
.setMinValues(a.question.minLength)
|
||||||
|
.setOptions(
|
||||||
|
a.question.options.map((o, i) => {
|
||||||
|
const builder = new SelectMenuOptionBuilder()
|
||||||
|
.setValue(String(i))
|
||||||
|
.setLabel(o.label);
|
||||||
|
if (o.description) builder.setDescription(o.description);
|
||||||
|
if (o.emoji) builder.setEmoji(emoji.hasEmoji(o.emoji) ? emoji.get(o.emoji) : { id: o.emoji });
|
||||||
|
return builder;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
@ -169,6 +169,7 @@ log:
|
|||||||
claim: claimed
|
claim: claimed
|
||||||
close: closed
|
close: closed
|
||||||
unclaim: released
|
unclaim: released
|
||||||
|
update: updated
|
||||||
menus:
|
menus:
|
||||||
category:
|
category:
|
||||||
placeholder: Select a ticket category
|
placeholder: Select a ticket category
|
||||||
@ -224,6 +225,9 @@ ticket:
|
|||||||
title: ✅ Ticket created
|
title: ✅ Ticket created
|
||||||
answers:
|
answers:
|
||||||
no_value: '*No response*'
|
no_value: '*No response*'
|
||||||
|
edited:
|
||||||
|
description: Your changes have been saved.
|
||||||
|
title: ✅ Ticket updated
|
||||||
opening_message:
|
opening_message:
|
||||||
content: |
|
content: |
|
||||||
{staff}
|
{staff}
|
||||||
|
@ -129,7 +129,7 @@ async function logAdminEvent(client, {
|
|||||||
* @param {string} details.action
|
* @param {string} details.action
|
||||||
*/
|
*/
|
||||||
async function logTicketEvent(client, {
|
async function logTicketEvent(client, {
|
||||||
userId, action, target,
|
userId, action, target, diff,
|
||||||
}) {
|
}) {
|
||||||
const ticket = await client.prisma.ticket.findUnique({
|
const ticket = await client.prisma.ticket.findUnique({
|
||||||
include: { guild: true },
|
include: { guild: true },
|
||||||
@ -143,9 +143,10 @@ async function logTicketEvent(client, {
|
|||||||
if (!ticket.guild.logChannel) return;
|
if (!ticket.guild.logChannel) return;
|
||||||
const colour = action === 'create'
|
const colour = action === 'create'
|
||||||
? 'Aqua' : action === 'close'
|
? 'Aqua' : action === 'close'
|
||||||
? 'DarkAqua' : action === 'claim'
|
? 'DarkAqua' : action === 'update'
|
||||||
? 'LuminousVividPink' : action === 'unclaim'
|
? 'Purple' : action === 'claim'
|
||||||
? 'DarkVividPink' : 'Default';
|
? 'LuminousVividPink' : action === 'unclaim'
|
||||||
|
? 'DarkVividPink' : 'Default';
|
||||||
const getMessage = client.i18n.getLocale(ticket.guild.locale);
|
const getMessage = client.i18n.getLocale(ticket.guild.locale);
|
||||||
const i18nOptions = {
|
const i18nOptions = {
|
||||||
user: `<@${member.user.id}>`,
|
user: `<@${member.user.id}>`,
|
||||||
@ -160,14 +161,8 @@ async function logTicketEvent(client, {
|
|||||||
iconURL: member.displayAvatarURL(),
|
iconURL: member.displayAvatarURL(),
|
||||||
name: member.displayName,
|
name: member.displayName,
|
||||||
})
|
})
|
||||||
.setTitle(getMessage('log.ticket.title', {
|
.setTitle(getMessage('log.ticket.title', i18nOptions))
|
||||||
...i18nOptions,
|
.setDescription(getMessage('log.ticket.description', i18nOptions))
|
||||||
verb: getMessage(`log.ticket.verb.${action}`),
|
|
||||||
}))
|
|
||||||
.setDescription(getMessage('log.ticket.description', {
|
|
||||||
...i18nOptions,
|
|
||||||
verb: getMessage(`log.ticket.verb.${action}`),
|
|
||||||
}))
|
|
||||||
.addFields([
|
.addFields([
|
||||||
{
|
{
|
||||||
name: getMessage('log.ticket.ticket'),
|
name: getMessage('log.ticket.ticket'),
|
||||||
@ -176,6 +171,15 @@ async function logTicketEvent(client, {
|
|||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (diff && diff.original) {
|
||||||
|
embeds.push(
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor(colour)
|
||||||
|
.setTitle(getMessage('log.admin.changes'))
|
||||||
|
.setFields(makeDiff(diff)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return await channel.send({ embeds });
|
return await channel.send({ embeds });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
const { Modal } = require('@eartharoid/dbf');
|
const { Modal } = require('@eartharoid/dbf');
|
||||||
|
const { EmbedBuilder } = require('discord.js');
|
||||||
|
const ExtendedEmbedBuilder = require('../lib/embed');
|
||||||
|
const { logTicketEvent } = require('../lib/logging');
|
||||||
|
|
||||||
module.exports = class QuestionsModal extends Modal {
|
module.exports = class QuestionsModal extends Modal {
|
||||||
constructor(client, options) {
|
constructor(client, options) {
|
||||||
@ -14,9 +17,103 @@ module.exports = class QuestionsModal extends Modal {
|
|||||||
* @param {import("discord.js").ModalSubmitInteraction} interaction
|
* @param {import("discord.js").ModalSubmitInteraction} interaction
|
||||||
*/
|
*/
|
||||||
async run(id, interaction) {
|
async run(id, interaction) {
|
||||||
await this.client.tickets.postQuestions({
|
/** @type {import("client")} */
|
||||||
...id,
|
const client = this.client;
|
||||||
interaction,
|
|
||||||
});
|
if (id.edit) {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
const { category } = await client.prisma.ticket.findUnique({
|
||||||
|
select: { category: { select: { customTopic: true } } },
|
||||||
|
where: { id: interaction.channel.id },
|
||||||
|
});
|
||||||
|
let topic;
|
||||||
|
if (category.customTopic) topic = interaction.fields.getTextInputValue(category.customTopic);
|
||||||
|
const select = {
|
||||||
|
createdById: true,
|
||||||
|
guild: {
|
||||||
|
select: {
|
||||||
|
footer: true,
|
||||||
|
locale: true,
|
||||||
|
successColour: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: true,
|
||||||
|
openingMessageId: true,
|
||||||
|
questionAnswers: { include: { question: true } },
|
||||||
|
};
|
||||||
|
const original = await client.prisma.ticket.findUnique({
|
||||||
|
select,
|
||||||
|
where: { id: interaction.channel.id },
|
||||||
|
});
|
||||||
|
const ticket = await client.prisma.ticket.update({
|
||||||
|
data: {
|
||||||
|
questionAnswers: {
|
||||||
|
update: interaction.fields.fields.map(f => ({
|
||||||
|
data: { value: f.value },
|
||||||
|
where: { id: Number(f.customId) },
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
topic,
|
||||||
|
},
|
||||||
|
select,
|
||||||
|
where: { id: interaction.channel.id },
|
||||||
|
});
|
||||||
|
const getMessage = client.i18n.getLocale(ticket.guild.locale);
|
||||||
|
|
||||||
|
if (topic) await interaction.channel.setTopic(`<@${ticket.createdById}> | ${topic}`);
|
||||||
|
|
||||||
|
const opening = await interaction.channel.messages.fetch(ticket.openingMessageId);
|
||||||
|
if (opening && opening.embeds.length >= 2) {
|
||||||
|
const embeds = [...opening.embeds];
|
||||||
|
embeds[1] = new EmbedBuilder(embeds[1].data)
|
||||||
|
.setFields(
|
||||||
|
ticket.questionAnswers
|
||||||
|
.map(a => ({
|
||||||
|
name: a.question.label,
|
||||||
|
value: a.value || getMessage('ticket.answers.no_value'),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
await opening.edit({ embeds });
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
new ExtendedEmbedBuilder({
|
||||||
|
iconURL: interaction.guild.iconURL(),
|
||||||
|
text: ticket.guild.footer,
|
||||||
|
})
|
||||||
|
.setColor(ticket.guild.successColour)
|
||||||
|
.setTitle(getMessage('ticket.edited.title'))
|
||||||
|
.setDescription(getMessage('ticket.edited.description')),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @param {ticket} ticket */
|
||||||
|
const makeDiff = ticket => {
|
||||||
|
const diff = {};
|
||||||
|
ticket.questionAnswers.forEach(a => {
|
||||||
|
diff[a.question.label] = a.value || getMessage('ticket.answers.no_value');
|
||||||
|
});
|
||||||
|
return diff;
|
||||||
|
};
|
||||||
|
|
||||||
|
logTicketEvent(this.client, {
|
||||||
|
action: 'update',
|
||||||
|
diff: {
|
||||||
|
original: makeDiff(original),
|
||||||
|
updated: makeDiff(ticket),
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
id: ticket.id,
|
||||||
|
name: `<#${ticket.id}>`,
|
||||||
|
},
|
||||||
|
userId: interaction.user.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await this.client.tickets.postQuestions({
|
||||||
|
...id,
|
||||||
|
interaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -1,4 +1,7 @@
|
|||||||
const { Modal } = require('@eartharoid/dbf');
|
const { Modal } = require('@eartharoid/dbf');
|
||||||
|
const { EmbedBuilder } = require('discord.js');
|
||||||
|
const ExtendedEmbedBuilder = require('../lib/embed');
|
||||||
|
const { logTicketEvent } = require('../lib/logging');
|
||||||
|
|
||||||
module.exports = class TopicModal extends Modal {
|
module.exports = class TopicModal extends Modal {
|
||||||
constructor(client, options) {
|
constructor(client, options) {
|
||||||
@ -9,9 +12,84 @@ module.exports = class TopicModal extends Modal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async run(id, interaction) {
|
async run(id, interaction) {
|
||||||
await this.client.tickets.postQuestions({
|
/** @type {import("client")} */
|
||||||
...id,
|
const client = this.client;
|
||||||
interaction,
|
|
||||||
});
|
if (id.edit) {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
const topic = interaction.fields.getTextInputValue('topic');
|
||||||
|
const select = {
|
||||||
|
createdById: true,
|
||||||
|
guild: {
|
||||||
|
select: {
|
||||||
|
footer: true,
|
||||||
|
locale: true,
|
||||||
|
successColour: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: true,
|
||||||
|
openingMessageId: true,
|
||||||
|
};
|
||||||
|
const original = await client.prisma.ticket.findUnique({
|
||||||
|
select,
|
||||||
|
where: { id: interaction.channel.id },
|
||||||
|
});
|
||||||
|
const ticket = await client.prisma.ticket.update({
|
||||||
|
data: { topic },
|
||||||
|
select,
|
||||||
|
where: { id: interaction.channel.id },
|
||||||
|
});
|
||||||
|
const getMessage = client.i18n.getLocale(ticket.guild.locale);
|
||||||
|
|
||||||
|
if (topic) await interaction.channel.setTopic(`<@${ticket.createdById}> | ${topic}`);
|
||||||
|
|
||||||
|
const opening = await interaction.channel.messages.fetch(ticket.openingMessageId);
|
||||||
|
if (opening && opening.embeds.length >= 2) {
|
||||||
|
const embeds = [...opening.embeds];
|
||||||
|
embeds[1] = new EmbedBuilder(embeds[1].data)
|
||||||
|
.setFields({
|
||||||
|
name: getMessage('ticket.opening_message.fields.topic'),
|
||||||
|
value: topic,
|
||||||
|
});
|
||||||
|
await opening.edit({ embeds });
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
new ExtendedEmbedBuilder({
|
||||||
|
iconURL: interaction.guild.iconURL(),
|
||||||
|
text: ticket.guild.footer,
|
||||||
|
})
|
||||||
|
.setColor(ticket.guild.successColour)
|
||||||
|
.setTitle(getMessage('ticket.edited.title'))
|
||||||
|
.setDescription(getMessage('ticket.edited.description')),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @param {ticket} ticket */
|
||||||
|
const makeDiff = ticket => {
|
||||||
|
const diff = {};
|
||||||
|
diff[getMessage('ticket.opening_message.fields.topic')] = ticket.topic;
|
||||||
|
return diff;
|
||||||
|
};
|
||||||
|
|
||||||
|
logTicketEvent(this.client, {
|
||||||
|
action: 'update',
|
||||||
|
diff: {
|
||||||
|
original: makeDiff(original),
|
||||||
|
updated: makeDiff(ticket),
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
id: ticket.id,
|
||||||
|
name: `<#${ticket.id}>`,
|
||||||
|
},
|
||||||
|
userId: interaction.user.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await this.client.tickets.postQuestions({
|
||||||
|
...id,
|
||||||
|
interaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -21,9 +21,10 @@ module.exports.get = () => ({
|
|||||||
discriminator: client.user.discriminator,
|
discriminator: client.user.discriminator,
|
||||||
id: client.user.id,
|
id: client.user.id,
|
||||||
portal: process.env.PORTAL || null,
|
portal: process.env.PORTAL || null,
|
||||||
|
public: !!process.env.PUBLIC,
|
||||||
stats: {
|
stats: {
|
||||||
activatedUsers: users.length,
|
activatedUsers: users.length,
|
||||||
archivedMessages: users.reduce((total, user) => total + user.messageCount, 0), // don't count archivedMessage table rows, they get deleted
|
archivedMessages: users.reduce((total, user) => total + user.messageCount, 0), // don't count archivedMessage table rows, they can be deleted
|
||||||
avgResolutionTime: ms(closedTickets.reduce((total, ticket) => total + (ticket.closedAt - ticket.createdAt), 0) ?? 1 / closedTickets.length),
|
avgResolutionTime: ms(closedTickets.reduce((total, ticket) => total + (ticket.closedAt - ticket.createdAt), 0) ?? 1 / closedTickets.length),
|
||||||
avgResponseTime: ms(closedTickets.reduce((total, ticket) => total + (ticket.firstResponseAt - ticket.createdAt), 0) ?? 1 / closedTickets.length),
|
avgResponseTime: ms(closedTickets.reduce((total, ticket) => total + (ticket.firstResponseAt - ticket.createdAt), 0) ?? 1 / closedTickets.length),
|
||||||
categories: await client.prisma.category.count(),
|
categories: await client.prisma.category.count(),
|
||||||
|
Loading…
Reference in New Issue
Block a user