made premium check faster. Added transcript endpoint, toHumanReadable function.

pull/11/head
TheCodedProf 3 years ago
parent cfe8e9aebe
commit 9c51a7ee53

@ -3,30 +3,22 @@
"@discordjs/rest": "^0.2.0-canary.0",
"@hokify/agenda": "^6.2.12",
"@tsconfig/node18-strictest-esm": "^1.0.0",
"@types/node-cron": "^3.0.1",
"@ungap/structured-clone": "^1.0.1",
"agenda": "^4.3.0",
"ansi-styles": "^6.1.0",
"body-parser": "^1.20.0",
"chalk": "^5.0.0",
"discord.js": "^14.7.1",
"eslint": "^8.21.0",
"express": "^4.18.1",
"form-data": "^4.0.0",
"fuse.js": "^6.6.2",
"humanize-duration": "^3.27.1",
"immutable": "^4.1.0",
"lodash": "^4.17.21",
"mongodb": "^4.7.0",
"node-cron": "^3.0.0",
"node-fetch": "^3.3.0",
"node-tesseract-ocr": "^2.2.1",
"pastebin-api": "^5.1.1",
"structured-clone": "^0.2.2",
"systeminformation": "^5.17.3",
"typescript": "^4.9.4",
"uuid": "^8.3.2"
},
"systeminformation": "^5.17.3"
},
"resolutions": {
"discord-api-types": "0.37.23"
},
@ -68,6 +60,7 @@
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.7.1",
"prettier-eslint": "^15.0.1",
"tsc-suppress": "^1.0.7"
"tsc-suppress": "^1.0.7",
"typescript": "^4.9.4"
}
}

@ -4,6 +4,7 @@ import client from "../../utils/client.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
import { preloadPage } from '../../utils/createTemporaryStorage.js';
import { LoadingEmbed } from '../../utils/defaults.js';
export default async function (interaction: Discord.CommandInteraction | ButtonInteraction) {
if (!interaction.guild) return;
@ -68,8 +69,9 @@ export default async function (interaction: Discord.CommandInteraction | ButtonI
await channel.delete();
} else if (status === "Active") {
// Close the ticket
await interaction.reply({embeds: LoadingEmbed, fetchReply: true});
// Archive the ticket
await interaction.channel.fetch()
if (channel.isThread()) {
channel.setName(`${channel.name.replace("Active", "Archived")}`);
channel.members.remove(channel.name.split(" - ")[1]!);
@ -79,13 +81,14 @@ export default async function (interaction: Discord.CommandInteraction | ButtonI
await channel.permissionOverwrites.delete(channel.topic!.split(" ")[0]!);
}
preloadPage(interaction.channel.id, "privacy", "2")
await interaction.reply({
const hasPremium = await client.database.premium.hasPremium(interaction.guild.id);
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Archived Ticket")
.setDescription(`This ticket has been Archived. Type ${getCommandMentionByName("ticket/close")} to delete it.\n` +
"Creating a transcript will delete all messages in this ticket" +
await client.database.premium.hasPremium(interaction.guild.id) ?
hasPremium ?
`\n\nFor more info on transcripts, check ${getCommandMentionByName("privacy")}` :
"")
.setStatus("Warning")
@ -100,7 +103,7 @@ export default async function (interaction: Discord.CommandInteraction | ButtonI
.setCustomId("closeticket")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
].concat(
await client.database.premium.hasPremium(interaction.guild.id)
hasPremium
? [
new ButtonBuilder()
.setLabel("Create Transcript and Delete")
@ -198,4 +201,4 @@ async function purgeByUser(member: string, guild: string) {
log(data);
}
export { purgeByUser };
export { purgeByUser };

@ -149,6 +149,16 @@ const runServer = (client: NucleusClient) => {
return res.sendStatus(404);
});
app.get("/transcript/:code", jsonParser, async function (req: express.Request, res: express.Response) {
const code = req.params.code;
if (code === undefined) return res.status(400).send("No code provided");
const entry = await client.database.transcripts.read(code);
if (entry === null) return res.status(404).send("Could not find a transcript by that code");
// Convert to a human readable format
const data = client.database.transcripts.toHumanReadable(entry);
return res.status(200).send(data);
});
app.listen(port);
};

@ -1,4 +1,3 @@
import { JSONTranscriptFromMessageArray, JSONTranscriptToHumanReadable } from '../../utils/logTranscripts.js';
import Discord, { CommandInteraction, GuildChannel, GuildMember, TextChannel, ButtonStyle, ButtonBuilder } from "discord.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
import confirmationMessage from "../../utils/confirmationMessage.js";
@ -161,7 +160,8 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}
};
log(data);
const transcript = JSONTranscriptToHumanReadable(JSONTranscriptFromMessageArray(deleted)!);
const newOut = await client.database.transcripts.createTranscript(deleted, interaction, interaction.member as GuildMember);
const transcript = client.database.transcripts.toHumanReadable(newOut);
const attachmentObject = {
attachment: Buffer.from(transcript),
name: `purge-${channel.id}-${Date.now()}.txt`,

@ -67,7 +67,7 @@ const dmcallback = async (interaction: CommandInteraction, dbUser: PremiumSchema
}
const callback = async (interaction: CommandInteraction): Promise<void> => {
if (interaction.guild) client.database.premium.hasPremium(interaction.guild.id).finally(() => {});
await interaction.reply({embeds: LoadingEmbed, ephemeral: true})
const member = await (await interaction.client.guilds.fetch("684492926528651336")).members.fetch(interaction.user.id).catch(() => {
interaction.editReply({ embeds: [
@ -172,7 +172,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
components: []
});
} else {
client.database.premium.addPremium(interaction.user.id, guild.id);
await client.database.premium.addPremium(interaction.user.id, guild.id);
interaction.editReply({
embeds: [
new EmojiEmbed()

@ -32,7 +32,7 @@ const colors: Record<string, number> = {
const buttonNames: Record<string, string> = {
verifybutton: "Verify",
rolemenu: "Role Menu",
createticket: "Ticket"
createticket: "Create Ticket"
}
export const callback = async (interaction: CommandInteraction): Promise<void> => {
@ -195,8 +195,8 @@ export const callback = async (interaction: CommandInteraction): Promise<void> =
continue;
}
if (!out || out.isButton()) continue
data.title = out.fields.getTextInputValue("title");
data.description = out.fields.getTextInputValue("description");
data.title = out.fields.getTextInputValue("title").length === 0 ? null : out.fields.getTextInputValue("title");
data.description = out.fields.getTextInputValue("description").length === 0 ? null : out.fields.getTextInputValue("description");
break;
}
case "send": {

@ -12,6 +12,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
.setDescription("Where attachments should be logged to (Premium only)")
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (interaction.guild) client.database.premium.hasPremium(interaction.guild.id).finally(() => {});
await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,

@ -8,6 +8,7 @@ import addPlural from "../utils/plurals.js";
import type { GuildTextBasedChannel, Message } from "discord.js";
export default async function logAttachment(message: Message): Promise<AttachmentLogSchema> {
if (message.guild) client.database.premium.hasPremium(message.guild.id).finally(() => {});
if (!message.guild) throw new Error("Tried to log an attachment in a non-guild message");
const { renderUser, renderChannel, renderDelta } = client.logger;
const attachments = [];

@ -8,83 +8,13 @@ import {
TextChannel,
ButtonStyle,
User,
ComponentType,
ThreadChannel
} from "discord.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import getEmojiByName from "../utils/getEmojiByName.js";
import { PasteClient, Publicity, ExpireDate } from "pastebin-api";
import client from "../utils/client.js";
import { messageException } from '../utils/createTemporaryStorage.js';
const pbClient = new PasteClient(client.config.pastebinApiKey);
interface TranscriptEmbed {
title?: string;
description?: string;
fields?: {
name: string;
value: string;
inline: boolean;
}[];
footer?: {
text: string;
iconURL?: string;
};
}
interface TranscriptComponent {
type: number;
style?: ButtonStyle;
label?: string;
description?: string;
placeholder?: string;
emojiURL?: string;
}
interface TranscriptAuthor {
username: string;
discriminator: number;
nickname?: string;
id: string;
iconURL?: string;
topRole: {
color: number;
badgeURL?: string;
}
}
interface TranscriptAttachment {
url: string;
filename: string;
size: number;
log?: string;
}
interface TranscriptMessage {
id: string;
author: TranscriptAuthor;
content?: string;
embeds?: TranscriptEmbed[];
components?: TranscriptComponent[][];
editedTimestamp?: number;
createdTimestamp: number;
flags?: string[];
attachments?: TranscriptAttachment[];
stickerURLs?: string[];
referencedMessage?: string | [string, string, string];
}
interface Transcript {
type: "ticket" | "purge"
guild: string;
channel: string;
for: TranscriptAuthor
messages: TranscriptMessage[];
createdTimestamp: number;
createdBy: TranscriptAuthor;
}
const noTopic = new EmojiEmbed()
.setTitle("User not found")
.setDescription("There is no user associated with this ticket.")
@ -114,175 +44,58 @@ export default async function (interaction: CommandInteraction | MessageComponen
)
));
let out = "";
messages.reverse().forEach((message) => {
if (!message.author.bot) {
const sentDate = new Date(message.createdTimestamp);
out += `${message.author.username}#${message.author.discriminator} (${
message.author.id
}) [${sentDate.toUTCString()}]\n`;
const lines = message.content.split("\n");
lines.forEach((line) => {
out += `> ${line}\n`;
});
out += "\n\n";
}
});
const interactionMember = await interaction.guild?.members.fetch(interaction.user.id)
let topic
let member: GuildMember | null = null;
let member: GuildMember = interaction.guild?.members.me!;
if (interaction.channel instanceof TextChannel) {
topic = interaction.channel.topic;
if (topic === null) return await interaction.reply({ embeds: [noTopic] });
member = interaction.guild!.members.cache.get(topic.split(" ")[1]!) ?? null;
const mem = interaction.guild!.members.cache.get(topic.split(" ")[1]!);
if (mem) member = mem;
} else {
topic = interaction.channel.name;
const split = topic.split("-").map(p => p.trim()) as [string, string, string];
member = interaction.guild!.members.cache.get(split[1]) ?? null;
if (member === null) return await interaction.reply({ embeds: [noTopic] });
const mem = interaction.guild!.members.cache.get(split[1])
if (mem) member = mem;
}
const newOut: Transcript = {
type: "ticket",
for: {
username: member!.user.username,
discriminator: parseInt(member!.user.discriminator),
id: member!.user.id,
topRole: {
color: member!.roles.highest.color
}
},
guild: interaction.guild!.id,
channel: interaction.channel!.id,
messages: [],
createdTimestamp: Date.now(),
createdBy: {
username: interaction.user.username,
discriminator: parseInt(interaction.user.discriminator),
id: interaction.user.id,
topRole: {
color: interactionMember?.roles.highest.color ?? 0x000000
}
}
}
if(interactionMember?.roles.icon) newOut.createdBy.topRole.badgeURL = interactionMember.roles.icon.iconURL()!;
messages.reverse().forEach((message) => {
const msg: TranscriptMessage = {
id: message.id,
author: {
username: message.author.username,
discriminator: parseInt(message.author.discriminator),
id: message.author.id,
topRole: {
color: message.member!.roles.highest.color
}
},
createdTimestamp: message.createdTimestamp
};
if (message.member!.roles.icon) msg.author.topRole.badgeURL = message.member!.roles.icon.iconURL()!;
if (message.content) msg.content = message.content;
if (message.embeds.length > 0) msg.embeds = message.embeds.map(embed => {
const obj: TranscriptEmbed = {};
if (embed.title) obj.title = embed.title;
if (embed.description) obj.description = embed.description;
if (embed.fields.length > 0) obj.fields = embed.fields.map(field => {
return {
name: field.name,
value: field.value,
inline: field.inline ?? false
}
});
if (embed.footer) obj.footer = {
text: embed.footer.text,
};
if (embed.footer?.iconURL) obj.footer!.iconURL = embed.footer.iconURL;
return obj;
});
if (message.components.length > 0) msg.components = message.components.map(component => component.components.map(child => {
const obj: TranscriptComponent = {
type: child.type
}
if (child.type === ComponentType.Button) {
obj.style = child.style;
obj.label = child.label ?? "";
} else if (child.type > 2) {
obj.placeholder = child.placeholder ?? "";
}
return obj
}));
if (message.editedTimestamp) msg.editedTimestamp = message.editedTimestamp;
msg.flags = message.flags.toArray();
if (message.stickers.size > 0) msg.stickerURLs = message.stickers.map(sticker => sticker.url);
if (message.reference) msg.referencedMessage = [message.reference.guildId ?? "", message.reference.channelId, message.reference.messageId ?? ""];
newOut.messages.push(msg);
});
const newOut = await client.database.transcripts.createTranscript(messages, interaction, member);
const code = await client.database.transcripts.create(newOut);
if(!code) return await interaction.reply({embeds: [new EmojiEmbed().setTitle("Error").setDescription("An error occurred while creating the transcript.").setStatus("Danger").setEmoji("CONTROL.BLOCKCROSS")]})
let m: Message;
if (out !== "") {
const url = await pbClient.createPaste({
code: out,
expireDate: ExpireDate.Never,
name:
`Ticket Transcript ${
member ? "for " + member.user.username + "#" + member.user.discriminator + " " : ""
}` + `(Created at ${new Date(interaction.channel.createdTimestamp!).toDateString()})`,
publicity: Publicity.Unlisted
});
const guildConfig = await client.database.guilds.read(interaction.guild!.id);
m = (await interaction.reply({
embeds: [
new EmojiEmbed()
.setTitle("Transcript")
.setDescription(
"You can view the transcript using the link below. You can save the link for later" +
(guildConfig.logging.logs.channel
? ` or find it in <#${guildConfig.logging.logs.channel}> once you press delete below. After this the channel will be deleted.`
: ".")
)
.setStatus("Success")
.setEmoji("CONTROL.DOWNLOAD")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(url),
new ButtonBuilder()
.setLabel("Delete")
.setStyle(ButtonStyle.Danger)
.setCustomId("close")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
])
],
fetchReply: true
})) as Message;
} else {
m = (await interaction.reply({
embeds: [
new EmojiEmbed()
.setTitle("Transcript")
.setDescription(
"The transcript was empty, so no changes were made. To delete this ticket, press the delete button below."
)
.setStatus("Success")
.setEmoji("CONTROL.DOWNLOAD")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Delete")
.setStyle(ButtonStyle.Danger)
.setCustomId("close")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
])
],
fetchReply: true
})) as Message;
}
if(!code) return await interaction.reply({
embeds: [
new EmojiEmbed()
.setTitle("Error")
.setDescription("An error occurred while creating the transcript.")
.setStatus("Danger")
.setEmoji("CONTROL.BLOCKCROSS")
]
})
const guildConfig = await client.database.guilds.read(interaction.guild!.id);
const m: Message = (await interaction.reply({
embeds: [
new EmojiEmbed()
.setTitle("Transcript")
.setDescription(
"You can view the transcript using the link below. You can save the link for later" +
(guildConfig.logging.logs.channel
? ` or find it in <#${guildConfig.logging.logs.channel}> once you press delete below. After this the channel will be deleted.`
: ".")
)
.setStatus("Success")
.setEmoji("CONTROL.DOWNLOAD")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript?code=${code}`),
new ButtonBuilder()
.setLabel("Delete")
.setStyle(ButtonStyle.Danger)
.setCustomId("close")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
])
],
fetchReply: true
})) as Message;
let i;
try {
i = await m.awaitMessageComponent({
@ -303,7 +116,7 @@ export default async function (interaction: CommandInteraction | MessageComponen
timestamp: Date.now()
},
list: {
ticketFor: member ? entry(member.id, renderUser(member.user)) : entry(null, "*Unknown*"),
ticketFor: entry(member.id, renderUser(member.user)),
deletedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as User)),
deleted: entry(Date.now().toString(), renderDelta(Date.now()))
},

@ -2,7 +2,7 @@ import Discord, { Client, Interaction, AutocompleteInteraction, Collection } fro
import { Logger } from "../utils/log.js";
import Memory from "../utils/memory.js";
import type { VerifySchema } from "../reflex/verify.js";
import { Guilds, History, ModNotes, Premium, PerformanceTest, ScanCache, Transcript } from "../utils/database.js";
import { Guilds, History, ModNotes, Premium, PerformanceTest, ScanCache, Transcript, } from "../utils/database.js";
import EventScheduler from "../utils/eventScheduler.js";
import type { RoleMenuSchema } from "../actions/roleMenu.js";
import config from "../config/main.js";

@ -225,6 +225,6 @@ export default async function register() {
console.log(`${colors.green}Registered commands, events and context menus${colors.none}`)
console.log(
(config.enableDevelopment ? `${colors.purple}Bot started in Development mode` :
`${colors.blue}Bot started in Production mode`) + colors.none)
// console.log(client.commands)
`${colors.blue}Bot started in Production mode`) + colors.none
)
};

@ -1,4 +1,4 @@
import type { ButtonStyle, GuildMember } from "discord.js";
import { ButtonStyle, CommandInteraction, ComponentType, GuildMember, Message, MessageComponentInteraction } from "discord.js";
import type Discord from "discord.js";
import { Collection, MongoClient } from "mongodb";
import config from "../config/main.js";
@ -154,7 +154,7 @@ interface TranscriptMessage {
flags?: string[];
attachments?: TranscriptAttachment[];
stickerURLs?: string[];
referencedMessage?: string | [string, string, string];
referencedMessage?: string | [string, string, string]; // the message id, the channel id, the guild id
}
interface TranscriptSchema {
@ -189,6 +189,134 @@ export class Transcript {
async read(code: string) {
return await this.transcripts.findOne({ code: code });
}
async createTranscript(messages: Message[], interaction: MessageComponentInteraction | CommandInteraction, member: GuildMember) {
const interactionMember = await interaction.guild?.members.fetch(interaction.user.id)
const newOut: Omit<TranscriptSchema, "code"> = {
type: "ticket",
for: {
username: member!.user.username,
discriminator: parseInt(member!.user.discriminator),
id: member!.user.id,
topRole: {
color: member!.roles.highest.color
}
},
guild: interaction.guild!.id,
channel: interaction.channel!.id,
messages: [],
createdTimestamp: Date.now(),
createdBy: {
username: interaction.user.username,
discriminator: parseInt(interaction.user.discriminator),
id: interaction.user.id,
topRole: {
color: interactionMember?.roles.highest.color ?? 0x000000
}
}
}
if(interactionMember?.roles.icon) newOut.createdBy.topRole.badgeURL = interactionMember.roles.icon.iconURL()!;
messages.reverse().forEach((message) => {
const msg: TranscriptMessage = {
id: message.id,
author: {
username: message.author.username,
discriminator: parseInt(message.author.discriminator),
id: message.author.id,
topRole: {
color: message.member!.roles.highest.color
}
},
createdTimestamp: message.createdTimestamp
};
if (message.member!.roles.icon) msg.author.topRole.badgeURL = message.member!.roles.icon.iconURL()!;
if (message.content) msg.content = message.content;
if (message.embeds.length > 0) msg.embeds = message.embeds.map(embed => {
const obj: TranscriptEmbed = {};
if (embed.title) obj.title = embed.title;
if (embed.description) obj.description = embed.description;
if (embed.fields.length > 0) obj.fields = embed.fields.map(field => {
return {
name: field.name,
value: field.value,
inline: field.inline ?? false
}
});
if (embed.footer) obj.footer = {
text: embed.footer.text,
};
if (embed.footer?.iconURL) obj.footer!.iconURL = embed.footer.iconURL;
return obj;
});
if (message.components.length > 0) msg.components = message.components.map(component => component.components.map(child => {
const obj: TranscriptComponent = {
type: child.type
}
if (child.type === ComponentType.Button) {
obj.style = child.style;
obj.label = child.label ?? "";
} else if (child.type > 2) {
obj.placeholder = child.placeholder ?? "";
}
return obj
}));
if (message.editedTimestamp) msg.editedTimestamp = message.editedTimestamp;
msg.flags = message.flags.toArray();
if (message.stickers.size > 0) msg.stickerURLs = message.stickers.map(sticker => sticker.url);
if (message.reference) msg.referencedMessage = [message.reference.guildId ?? "", message.reference.channelId, message.reference.messageId ?? ""];
newOut.messages.push(msg);
});
return newOut;
}
toHumanReadable(transcript: Omit<TranscriptSchema, "code">): string {
let out = "";
for (const message of transcript.messages) {
if (message.referencedMessage) {
if (Array.isArray(message.referencedMessage)) {
out += `> [Crosspost From] ${message.referencedMessage[0]} in ${message.referencedMessage[1]} in ${message.referencedMessage[2]}\n`;
}
else out += `> [Reply To] ${message.referencedMessage}\n`;
}
out += `${message.author.nickname ?? message.author.username}#${message.author.discriminator} (${message.author.id}) (${message.id}) `;
out += `[${new Date(message.createdTimestamp).toISOString()}] `;
if (message.editedTimestamp) out += `[Edited: ${new Date(message.editedTimestamp).toISOString()}] `;
out += "\n";
if (message.content) out += `[Content]\n${message.content}\n\n`;
if (message.embeds) {
for (const embed of message.embeds) {
out += `[Embed]\n`;
if (embed.title) out += `| Title: ${embed.title}\n`;
if (embed.description) out += `| Description: ${embed.description}\n`;
if (embed.fields) {
for (const field of embed.fields) {
out += `| Field: ${field.name} - ${field.value}\n`;
}
}
if (embed.footer) {
out += `|Footer: ${embed.footer.text}\n`;
}
out += "\n";
}
}
if (message.components) {
for (const component of message.components) {
out += `[Component]\n`;
for (const button of component) {
out += `| Button: ${button.label ?? button.description}\n`;
}
out += "\n";
}
}
if (message.attachments) {
for (const attachment of message.attachments) {
out += `[Attachment] ${attachment.filename} (${attachment.size} bytes) ${attachment.url}\n`;
}
}
}
return out
}
}
export class History {
@ -317,9 +445,12 @@ export class ModNotes {
export class Premium {
premium: Collection<PremiumSchema>;
cache: Map<string, [boolean, string, number, boolean, Date]>; // Date indicates the time one hour after it was created
cacheTimeout = 1000 * 60 * 60; // 1 hour
constructor() {
this.premium = database.collection<PremiumSchema>("premium");
this.cache = new Map<string, [boolean, string, number, boolean, Date]>();
}
async updateUser(user: string, level: number) {
@ -337,8 +468,11 @@ export class Premium {
}
async hasPremium(guild: string): Promise<[boolean, string, number, boolean] | null> {
// [Has premium, user giving premium, level, is mod: if given automatically]
const cached = this.cache.get(guild);
if (cached && cached[4].getTime() < Date.now()) return [cached[0], cached[1], cached[2], cached[3]];
const entries = await this.premium.find({}).toArray();
const members = await (await client.guilds.fetch(guild)).members.fetch()
const members = (await client.guilds.fetch(guild)).members.cache
for(const {user} of entries) {
const member = members.get(user);
if(member) { //TODO: Notify user if they've given premium to a server that has since gotten premium via a mod.
@ -355,7 +489,10 @@ export class Premium {
member.permissions.has("ManageMessages") ||
member.permissions.has("ManageThreads")
const entry = entries.find(e => e.user === member.id);
if(entry && (entry.level === 3) && modPerms) return [true, member.id, entry.level, true];
if(entry && (entry.level === 3) && modPerms) {
this.cache.set(guild, [true, member.id, entry.level, true, new Date(Date.now() + this.cacheTimeout)]);
return [true, member.id, entry.level, true];
}
}
}
const entry = await this.premium.findOne({
@ -365,6 +502,7 @@ export class Premium {
}
}
});
this.cache.set(guild, [entry ? true : false, entry?.user ?? "", entry?.level ?? 0, false, new Date(Date.now() + this.cacheTimeout)]);
return entry ? [true, entry.user, entry.level, false] : null;
}
@ -427,11 +565,14 @@ export class Premium {
}
}
addPremium(user: string, guild: string) {
async addPremium(user: string, guild: string) {
const { level } = (await this.fetchUser(user))!;
this.cache.set(guild, [true, user, level, false, new Date(Date.now() + this.cacheTimeout)]);
return this.premium.updateOne({ user: user }, { $addToSet: { appliesTo: guild } }, { upsert: true });
}
removePremium(user: string, guild: string) {
this.cache.set(guild, [false, "", 0, false, new Date(Date.now() + this.cacheTimeout)]);
return this.premium.updateOne({ user: user }, { $pull: { appliesTo: guild } });
}
}

@ -14,7 +14,6 @@ class EventScheduler {
collection: "eventScheduler"
}
});
this.agenda.define("unmuteRole", async (job) => {
const guild = await client.guilds.fetch(job.attrs.data.guild);
const user = await guild.members.fetch(job.attrs.data.user);

@ -1,64 +0,0 @@
import type Discord from 'discord.js';
export interface JSONTranscriptSchema {
messages: {
content: string | null;
attachments: {
url: string;
name: string;
size: number;
}[];
authorID: string;
authorUsername: string;
authorUsernameColor: string;
timestamp: string;
id: string;
edited: boolean;
}[];
channel: string;
guild: string;
timestamp: string;
}
export const JSONTranscriptFromMessageArray = (messages: Discord.Message[]): JSONTranscriptSchema | null => {
if (messages.length === 0) return null;
return {
guild: messages[0]!.guild!.id,
channel: messages[0]!.channel.id,
timestamp: Date.now().toString(),
messages: messages.map((message: Discord.Message) => {
return {
content: message.content,
attachments: message.attachments.map((attachment: Discord.Attachment) => {
return {
url: attachment.url,
name: attachment.name!,
size: attachment.size,
};
}),
authorID: message.author.id,
authorUsername: message.author.username + "#" + message.author.discriminator,
authorUsernameColor: message.member!.displayHexColor.toString(),
timestamp: message.createdTimestamp.toString(),
id: message.id,
edited: message.editedTimestamp ? true : false,
};
})
};
}
export const JSONTranscriptToHumanReadable = (data: JSONTranscriptSchema): string => {
let out = "";
for (const message of data.messages) {
const date = new Date(parseInt(message.timestamp));
out += `${message.authorUsername} (${message.authorID}) [${date}]`;
if (message.edited) out += " (edited)";
if (message.content) out += "\nContent:\n" + message.content.split("\n").map((line: string) => `\n> ${line}`).join("");
if (message.attachments.length > 0) out += "\nAttachments:\n" + message.attachments.map((attachment: { url: string; name: string; size: number; }) => `\n> [${attachment.name}](${attachment.url}) (${attachment.size} bytes)`).join("\n");
out += "\n\n";
}
return out;
}
Loading…
Cancel
Save