diff --git a/src/actions/tickets/delete.ts b/src/actions/tickets/delete.ts index be891ec..990b360 100644 --- a/src/actions/tickets/delete.ts +++ b/src/actions/tickets/delete.ts @@ -87,10 +87,8 @@ export default async function (interaction: Discord.CommandInteraction | ButtonI 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" + - hasPremium ? - `\n\nFor more info on transcripts, check ${getCommandMentionByName("privacy")}` : - "") + hasPremium ? ("Creating a transcript will delete all messages in this ticket" + + `\n\nFor more info on transcripts, check ${getCommandMentionByName("privacy")}`): "") .setStatus("Warning") .setEmoji("GUILD.TICKET.ARCHIVED") ], diff --git a/src/api/index.ts b/src/api/index.ts index 8c1e8cc..9676194 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -156,6 +156,8 @@ const runServer = (client: NucleusClient) => { 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); + res.attachment(`${code}.txt`); + res.type("txt"); return res.status(200).send(data); }); @@ -168,6 +170,28 @@ const runServer = (client: NucleusClient) => { return res.status(200).send(entry); }); + app.get("/channels/:id", jsonParser, async function (req: express.Request, res: express.Response) { + const id = req.params.id; + if (id === undefined) return res.status(400).send("No id provided"); + const channel = await client.channels.fetch(id); + if (channel === null) return res.status(404).send("Could not find a channel by that id"); + if (channel.isDMBased()) return res.status(400).send("Cannot get a DM channel"); + return res.status(200).send(channel.name); + }); + + app.get("/users/:id", jsonParser, async function (req: express.Request, res: express.Response) { + const id = req.params.id; + if (id === undefined) return res.status(400).send("No id provided"); + let user; + try { + user = await client.users.fetch(id); + } catch (e) { + console.log(e) + return res.status(404).send("Could not find a user by that id"); + } + return res.status(200).send(user.username); + }); + app.listen(port); }; diff --git a/src/commands/settings/automod.ts b/src/commands/settings/automod.ts index 87b1844..09b8914 100644 --- a/src/commands/settings/automod.ts +++ b/src/commands/settings/automod.ts @@ -650,19 +650,19 @@ const cleanMenu = async (interaction: StringSelectMenuInteraction, m: Message, c channels?: string[], allowed?: { roles: string[], - user: string[] + users: string[] } }): Promise<{ channels: string[], allowed: { roles: string[], - user: string[] + users: string[] } }> => { let closed = false; - if(!current) current = {channels: [], allowed: {roles: [], user: []}}; + if(!current) current = {channels: [], allowed: {roles: [], users: []}}; if(!current.channels) current.channels = []; - if(!current.allowed) current.allowed = {roles: [], user: []}; + if(!current.allowed) current.allowed = {roles: [], users: []}; const channelMenu = new ActionRowBuilder() .addComponents( @@ -773,7 +773,7 @@ const cleanMenu = async (interaction: StringSelectMenuInteraction, m: Message, c case "allowed": { switch (i.values[0]) { case "users": { - current.allowed.user = await toSelectMenu(interaction, m, current.allowed.user, "member", "Mention Settings"); + current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings"); break; } case "roles": { @@ -792,7 +792,7 @@ const cleanMenu = async (interaction: StringSelectMenuInteraction, m: Message, c channels: string[], allowed: { roles: string[], - user: string[] + users: string[] } }; diff --git a/src/commands/settings/moderation.ts b/src/commands/settings/moderation.ts index c7f0dd0..336e53a 100644 --- a/src/commands/settings/moderation.ts +++ b/src/commands/settings/moderation.ts @@ -21,6 +21,7 @@ const callback = async (interaction: CommandInteraction): Promise => { while (!timedOut) { const config = await client.database.guilds.read(interaction.guild!.id); const moderation = config.moderation; + console.log(moderation) await interaction.editReply({ embeds: [ new EmojiEmbed() diff --git a/src/config/default.json b/src/config/default.json deleted file mode 100644 index 704896f..0000000 --- a/src/config/default.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "id": "default", - "version": 1, - "singleEventNotifications": { - "statsChannelDeleted": false - }, - "filters": { - "images": { - "NSFW": false, - "size": false - }, - "malware": false, - "wordFilter": { - "enabled": false, - "words": { - "strict": [], - "loose": [] - }, - "allowed": { - "user": [], - "roles": [], - "channels": [] - } - }, - "invite": { - "enabled": false, - "allowed": { - "user": [], - "roles": [], - "channels": [] - } - }, - "pings": { - "mass": 5, - "everyone": true, - "roles": true, - "allowed": { - "user": [], - "roles": [], - "channels": [], - "rolesToMention": [] - } - }, - "clean": { - "channels": [], - "allowed": { - "user": [], - "roles": [] - } - } - }, - "welcome": { - "enabled": false, - "role": null, - "ping": null, - "channel": null, - "message": null - }, - "stats": {}, - "logging": { - "logs": { - "enabled": true, - "channel": null, - "toLog": "3fffff" - }, - "staff": { - "channel": null - }, - "attachments": { - "channel": null, - "saved": {} - } - }, - "verify": { - "enabled": false, - "role": null - }, - "tickets": { - "enabled": false, - "category": null, - "types": "3f", - "customTypes": null, - "useCustom": false, - "supportRole": null, - "maxTickets": 5 - }, - "moderation": { - "mute": { - "timeout": true, - "role": null, - "text": null, - "link": null - }, - "kick": { - "text": null, - "link": null - }, - "ban": { - "text": null, - "link": null - }, - "softban": { - "text": null, - "link": null - }, - "warn": { - "text": null, - "link": null - }, - "nick": { - "text": null, - "link": null - } - }, - "tracks": [], - "roleMenu": [], - "tags": {}, - "autoPublish": { - "enabled": false, - "channels": [] - } -} diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 44017d7..4f525fc 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -28,7 +28,7 @@ export async function callback(_client: NucleusClient, message: Message) { if(config.filters.clean.channels.includes(message.channel.id)) { const memberRoles = message.member!.roles.cache.map(role => role.id); const roleAllow = config.filters.clean.allowed.roles.some(role => memberRoles.includes(role)); - const userAllow = config.filters.clean.allowed.user.includes(message.author.id); + const userAllow = config.filters.clean.allowed.users.includes(message.author.id); if(!roleAllow && !userAllow) return await message.delete(); } diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts index 85e059f..67aed04 100644 --- a/src/premium/createTranscript.ts +++ b/src/premium/createTranscript.ts @@ -86,7 +86,7 @@ export default async function (interaction: CommandInteraction | MessageComponen ], components: [ new ActionRowBuilder().addComponents([ - new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript?code=${code}`), + new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript/${code}`), new ButtonBuilder() .setLabel("Delete") .setStyle(ButtonStyle.Danger) @@ -118,7 +118,8 @@ export default async function (interaction: CommandInteraction | MessageComponen list: { 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())) + deleted: entry(Date.now().toString(), renderDelta(Date.now())), + transcript: entry(code, `https://clicks.codes/nucleus/transcript/${code}`) }, hidden: { guild: interaction.guild!.id diff --git a/src/utils/client.ts b/src/utils/client.ts index 7e84716..b1fa31f 100644 --- a/src/utils/client.ts +++ b/src/utils/client.ts @@ -41,7 +41,7 @@ class NucleusClient extends Client { } } const client = new NucleusClient({ - guilds: await new Guilds().setup(), + guilds: await new Guilds(), history: new History(), notes: new ModNotes(), premium: new Premium(), diff --git a/src/utils/database.ts b/src/utils/database.ts index 1e2d3ba..2e64320 100644 --- a/src/utils/database.ts +++ b/src/utils/database.ts @@ -4,7 +4,8 @@ import { Collection, MongoClient } from "mongodb"; import config from "../config/main.js"; import client from "../utils/client.js"; import * as crypto from "crypto"; - +import _ from "lodash"; +import defaultData from '../config/default.js'; // config.mongoOptions.host, { // auth: { // username: config.mongoOptions.username, @@ -23,27 +24,22 @@ const collectionOptions = { authdb: "admin" }; export class Guilds { guilds: Collection; - defaultData: GuildConfig | null; + defaultData: GuildConfig; constructor() { this.guilds = database.collection("guilds"); - this.defaultData = null; - } - - async setup(): Promise { - this.defaultData = (await import("../config/default.json", { assert: { type: "json" } })) - .default as unknown as GuildConfig; - return this; + this.defaultData = defaultData; } async read(guild: string): Promise { - console.log("Guild read") + // console.log("Guild read") const entry = await this.guilds.findOne({ id: guild }); - return Object.assign({}, this.defaultData, entry); + const data = _.clone(this.defaultData!); + return _.merge(data, entry ?? {}); } async write(guild: string, set: object | null, unset: string[] | string = []) { - console.log("Guild write") + // console.log("Guild write") // eslint-disable-next-line @typescript-eslint/no-explicit-any const uo: Record = {}; if (!Array.isArray(unset)) unset = [unset]; @@ -58,7 +54,7 @@ export class Guilds { // eslint-disable-next-line @typescript-eslint/no-explicit-any async append(guild: string, key: string, value: any) { - console.log("Guild append") + // console.log("Guild append") if (Array.isArray(value)) { await this.guilds.updateOne( { id: guild }, @@ -85,7 +81,7 @@ export class Guilds { value: any, innerKey?: string | null ) { - console.log("Guild remove") + // console.log("Guild remove") if (innerKey) { await this.guilds.updateOne( { id: guild }, @@ -114,7 +110,7 @@ export class Guilds { } async delete(guild: string) { - console.log("Guild delete") + // console.log("Guild delete") await this.guilds.deleteOne({ id: guild }); } } @@ -202,7 +198,7 @@ export class Transcript { } async create(transcript: Omit) { - console.log("Transcript create") + // console.log("Transcript create") let code; do { code = crypto.randomBytes(64).toString("base64").replace(/=/g, "").replace(/\//g, "_").replace(/\+/g, "-"); @@ -214,7 +210,7 @@ export class Transcript { } async read(code: string) { - console.log("Transcript read") + // console.log("Transcript read") return await this.transcripts.findOne({ code: code }); } @@ -322,9 +318,9 @@ export class Transcript { } 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 += `${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) { @@ -380,7 +376,7 @@ export class History { after?: string | null, amount?: string | null ) { - console.log("History create"); + // console.log("History create"); await this.histories.insertOne({ type: type, guild: guild, @@ -395,7 +391,7 @@ export class History { } async read(guild: string, user: string, year: number) { - console.log("History read"); + // console.log("History read"); const entry = (await this.histories .find({ guild: guild, @@ -410,7 +406,7 @@ export class History { } async delete(guild: string) { - console.log("History delete"); + // console.log("History delete"); await this.histories.deleteMany({ guild: guild }); } } @@ -430,17 +426,17 @@ export class ScanCache { } async read(hash: string) { - console.log("ScanCache read"); + // console.log("ScanCache read"); return await this.scanCache.findOne({ hash: hash }); } async write(hash: string, data: boolean, tags?: string[]) { - console.log("ScanCache write"); + // console.log("ScanCache write"); await this.scanCache.insertOne({ hash: hash, data: data, tags: tags ?? [], addedAt: new Date() }, collectionOptions); } async cleanup() { - console.log("ScanCache cleanup"); + // console.log("ScanCache cleanup"); await this.scanCache.deleteMany({ addedAt: { $lt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 31)) }, hash: { $not$text: "http"} }); } } @@ -453,12 +449,12 @@ export class PerformanceTest { } async record(data: PerformanceDataSchema) { - console.log("PerformanceTest record"); + // console.log("PerformanceTest record"); data.timestamp = new Date(); await this.performanceData.insertOne(data, collectionOptions); } async read() { - console.log("PerformanceTest read"); + // console.log("PerformanceTest read"); return await this.performanceData.find({}).toArray(); } } @@ -482,18 +478,18 @@ export class ModNotes { } async create(guild: string, user: string, note: string | null) { - console.log("ModNotes create"); + // console.log("ModNotes create"); await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, { upsert: true }); } async read(guild: string, user: string) { - console.log("ModNotes read"); + // console.log("ModNotes read"); const entry = await this.modNotes.findOne({ guild: guild, user: user }); return entry?.note ?? null; } async delete(guild: string) { - console.log("ModNotes delete"); + // console.log("ModNotes delete"); await this.modNotes.deleteMany({ guild: guild }); } } @@ -509,24 +505,24 @@ export class Premium { } async updateUser(user: string, level: number) { - console.log("Premium updateUser"); + // console.log("Premium updateUser"); if(!(await this.userExists(user))) await this.createUser(user, level); await this.premium.updateOne({ user: user }, { $set: { level: level } }, { upsert: true }); } async userExists(user: string): Promise { - console.log("Premium userExists"); + // console.log("Premium userExists"); const entry = await this.premium.findOne({ user: user }); return entry ? true : false; } async createUser(user: string, level: number) { - console.log("Premium createUser"); + // console.log("Premium createUser"); await this.premium.insertOne({ user: user, appliesTo: [], level: level }, collectionOptions); } async hasPremium(guild: string): Promise<[boolean, string, number, boolean] | null> { - console.log("Premium hasPremium"); + // console.log("Premium hasPremium"); // [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]]; @@ -566,14 +562,14 @@ export class Premium { } async fetchUser(user: string): Promise { - console.log("Premium fetchUser"); + // console.log("Premium fetchUser"); const entry = await this.premium.findOne({ user: user }); if (!entry) return null; return entry; } async checkAllPremium(member?: GuildMember) { - console.log("Premium checkAllPremium"); + // console.log("Premium checkAllPremium"); const entries = await this.premium.find({}).toArray(); if(member) { const entry = entries.find(e => e.user === member.id); @@ -627,14 +623,14 @@ export class Premium { } async addPremium(user: string, guild: string) { - console.log("Premium addPremium"); + // console.log("Premium addPremium"); 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) { - console.log("Premium removePremium"); + // console.log("Premium removePremium"); this.cache.set(guild, [false, "", 0, false, new Date(Date.now() + this.cacheTimeout)]); return this.premium.updateOne({ user: user }, { $pull: { appliesTo: guild } }); } @@ -684,7 +680,7 @@ export interface GuildConfig { clean: { channels: string[]; allowed: { - user: string[]; + users: string[]; roles: string[]; } }