chore: Ajout du transcript fonctionnel pour les tickets
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { EmbedBuilder, StickerFormatType } = require('discord.js');
|
||||
const { closeTicket } = require('./database');
|
||||
const { config } = require('./configLoader');
|
||||
|
||||
async function generateTranscript(channel, user) {
|
||||
const messages = await channel.messages.fetch({ limit: 100 });
|
||||
const sorted = [...messages.values()].reverse();
|
||||
|
||||
let html = `
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Transcript - ${channel.name}</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; background: #2c2f33; color: #fff; }
|
||||
.msg { border-bottom: 1px solid #444; padding: 5px; }
|
||||
.author { font-weight: bold; color: #7289da; }
|
||||
.time { color: #999; font-size: 12px; }
|
||||
img { max-width: 400px; margin-top: 5px; border-radius: 5px; }
|
||||
.embed { border-left: 3px solid #7289da; margin: 5px; padding-left: 5px; background: #23272a; }
|
||||
.sticker { margin-top: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Transcript - ${channel.name}</h2>
|
||||
`;
|
||||
|
||||
for (const msg of sorted) {
|
||||
const time = msg.createdAt.toLocaleString();
|
||||
const avatar = msg.author.displayAvatarURL();
|
||||
let content = msg.content || '';
|
||||
|
||||
// Mentions
|
||||
if (content) {
|
||||
content = content.replace(/<@!?(\d+)>/g, (match, id) => {
|
||||
const u = channel.client.users.cache.get(id);
|
||||
return u ? `@${u.username}` : match;
|
||||
});
|
||||
|
||||
// Emojis custom
|
||||
content = content.replace(/<a?:\w+:(\d+)>/g, (match, id) => {
|
||||
const isAnimated = match.startsWith('<a:');
|
||||
const ext = isAnimated ? 'gif' : 'png';
|
||||
return `<img src="https://cdn.discordapp.com/emojis/${id}.${ext}" height="24" style="vertical-align:middle;">`;
|
||||
});
|
||||
}
|
||||
|
||||
html += `
|
||||
<div class="msg">
|
||||
<img src="${avatar}" width="32" height="32" style="border-radius:50%; vertical-align:middle; margin-right:5px;">
|
||||
<span class="author">${msg.author.tag}</span>
|
||||
<span class="time">(${time})</span>
|
||||
<div style="white-space: pre-wrap; margin-left:37px;">${content}</div>
|
||||
`;
|
||||
|
||||
// Pièces jointes
|
||||
if (msg.attachments.size > 0) {
|
||||
msg.attachments.forEach((att) => {
|
||||
if (att.contentType?.startsWith('image/')) {
|
||||
html += `<div class="attachment"><img src="${att.url}"/></div>`;
|
||||
} else {
|
||||
html += `<div class="attachment"><a href="${att.url}" target="_blank">📎 ${att.name}</a></div>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Stickers
|
||||
if (msg.stickers.size > 0) {
|
||||
msg.stickers.forEach((sticker) => {
|
||||
if (sticker.format === StickerFormatType.LOTTIE) {
|
||||
html += `<div class="sticker">[Sticker Lottie non supporté]</div>`;
|
||||
return;
|
||||
}
|
||||
const url = `https://cdn.discordapp.com/stickers/${sticker.id}.png`;
|
||||
html += `
|
||||
<div class="sticker">
|
||||
<img src="${url}" alt="${sticker.name}"
|
||||
style="width:320px; height:320px; border-radius:8px; display:block;"/>
|
||||
<div style="color:#aaa; font-size:12px;">${sticker.name}</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// Embeds
|
||||
if (msg.embeds.length > 0) {
|
||||
msg.embeds.forEach((embed) => {
|
||||
html += `<div class="embed">`;
|
||||
if (embed.title) html += `<div><strong>${embed.title}</strong></div>`;
|
||||
if (embed.description) html += `<div>${embed.description}</div>`;
|
||||
if (embed.url)
|
||||
html += `<div><a href="${embed.url}" target="_blank">🔗 Lien</a></div>`;
|
||||
if (embed.thumbnail?.url) {
|
||||
html += `<img src="${embed.thumbnail.url}" style="max-width:150px;"/>`;
|
||||
}
|
||||
html += `</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
}
|
||||
|
||||
html += `</body></html>`;
|
||||
|
||||
const transcriptsDir = path.join(__dirname, '../transcripts');
|
||||
if (!fs.existsSync(transcriptsDir)) fs.mkdirSync(transcriptsDir);
|
||||
|
||||
const filePath = path.join(transcriptsDir, `${channel.id}.html`);
|
||||
fs.writeFileSync(filePath, html, 'utf8');
|
||||
|
||||
// Logs
|
||||
const logChannel = await channel.client.channels
|
||||
.fetch(config.logsChannel)
|
||||
.catch(() => null);
|
||||
if (logChannel) {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('🔒 Ticket fermé')
|
||||
.addFields(
|
||||
{ name: 'Salon', value: `${channel.name}`, inline: true },
|
||||
{
|
||||
name: 'Fermé par',
|
||||
value: user ? `${user.tag} (${user.id})` : 'Automatique',
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Transcript',
|
||||
value: `http://localhost:3000/transcript/${channel.id}`,
|
||||
}
|
||||
)
|
||||
.setColor(0xe74c3c)
|
||||
.setTimestamp();
|
||||
await logChannel.send({ embeds: [embed] });
|
||||
}
|
||||
}
|
||||
|
||||
async function closeTicketWithTranscript(channel, user) {
|
||||
await generateTranscript(channel, user);
|
||||
closeTicket(channel.id);
|
||||
await channel.delete().catch(() => {});
|
||||
}
|
||||
|
||||
module.exports = { closeTicketWithTranscript };
|
||||
Reference in New Issue
Block a user