loads of new commands, updates and bug fixes
diff --git a/src/utils/calculate.ts b/src/utils/calculate.ts
index 26c231c..8a297b9 100644
--- a/src/utils/calculate.ts
+++ b/src/utils/calculate.ts
@@ -1,13 +1,13 @@
const logs = [
"channelUpdate",
- "channelPinsUpdate",
+ "channelPinsUpdate", // TODO
"emojiUpdate",
- "stickerUpdate",
+ "stickerUpdate", // TODO
"guildUpdate",
"guildMemberUpdate",
"guildMemberPunish",
- "guildEventUpdate",
- "guildEventMemberUpdate",
+ "guildEventUpdate", // TODO
+ "guildEventMemberUpdate", // TODO
"guildRoleUpdate",
"guildInviteUpdate",
"messageUpdate",
@@ -16,11 +16,11 @@
"messageReactionUpdate",
"messagePing",
"messageMassPing",
- "messageAnnounce",
+ "messageAnnounce", // TODO
"stageUpdate",
"threadUpdate",
- "voiceStateUpdate",
- "webhookUpdate"
+ "voiceStateUpdate", // TODO
+ "webhookUpdate" // TODO
]
const tickets = [
diff --git a/src/utils/database.ts b/src/utils/database.ts
index 53ccb97..4e37652 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -1,8 +1,10 @@
import { Collection, Db, MongoClient } from 'mongodb';
+import structuredClone from '@ungap/structured-clone';
export const Entry = data => {
data = data ?? {};
+ data.getKey = key => data[key]
return {
get(target, prop, receiver) {
let dataToReturn = data[prop]
@@ -38,11 +40,42 @@
async read(guild: string) {
let entry = await this.guilds.findOne({ id: guild });
- return new Proxy(this.defaultData, Entry(entry)) as unknown as GuildConfig
+ return new Proxy(structuredClone(this.defaultData), Entry(entry)) as unknown as GuildConfig
}
- async write(guild: string, config: GuildConfig) {
- await this.guilds.updateOne({ id: guild }, { $set: config }, { upsert: true });
+ async write(guild: string, set: object = {}, unset: string[] = []) {
+ let uo = {}
+ for (let key of unset) {
+ uo[key] = "";
+ }
+ await this.guilds.updateOne({ id: guild }, {
+ $unset: uo,
+ $set: set
+ }, { upsert: true });
+ }
+
+ async append(guild: string, key: string, value: any) {
+ if (Array.isArray(value)) {
+ await this.guilds.updateOne({ id: guild }, {
+ $addToSet: { [key]: { $each: value } }
+ }, { upsert: true });
+ } else {
+ await this.guilds.updateOne({ id: guild }, {
+ $addToSet: { [key]: value }
+ }, { upsert: true });
+ }
+ }
+
+ async remove(guild: string, key: string, value: any) {
+ if (Array.isArray(value)) {
+ await this.guilds.updateOne({ id: guild }, {
+ $pullAll: { [key]: value }
+ }, { upsert: true });
+ } else {
+ await this.guilds.updateOne({ id: guild }, {
+ $pullAll: { [key]: [value] }
+ }, { upsert: true });
+ }
}
}
@@ -94,64 +127,65 @@
enabled: boolean,
verificationRequired: {
message: boolean,
- role: string
+ role: string | null
},
- welcomeRole: string,
- channel: string,
- message: string
+ welcomeRole: string | null,
+ channel: string | null,
+ message: string | null,
}
stats: {
enabled: boolean,
- channel: string,
- text: string
+ channel: string | null,
+ text: string | null,
}[]
logging: {
logs: {
enabled: boolean,
- channel: string,
- toLog: string
+ channel: string | null,
+ toLog: string | null,
},
staff: {
- channel: string
+ channel: string | null,
}
}
verify: {
enabled: boolean,
- role: string
+ role: string | null,
}
tickets: {
enabled: boolean,
- category: string,
- types: string,
+ category: string | null,
+ types: string | null,
customTypes: string[],
- supportRole: string,
+ useCustom: boolean,
+ supportRole: string | null,
maxTickets: number
}
moderation: {
mute: {
timeout: boolean,
- role: string,
- text: string,
- link: string
+ role: string | null,
+ text: string | null,
+ link: string | null
},
kick: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
ban: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
softban: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
warn: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
role: {
- role: string
+ role: string | null,
}
}
tracks: {
diff --git a/src/utils/dualCollector.ts b/src/utils/dualCollector.ts
new file mode 100644
index 0000000..ae63757
--- /dev/null
+++ b/src/utils/dualCollector.ts
@@ -0,0 +1,49 @@
+import Discord from 'discord.js';
+import client from './client.js';
+import generateEmojiEmbed from "./generateEmojiEmbed.js";
+
+export default async function (m, interactionFilter, messageFilter) {
+ let out;
+ try {
+ out = await new Promise((resolve, reject) => {
+ let mes, int;
+ mes = m.createMessageComponentCollector({filter: (m) => interactionFilter(m), time: 600000})
+ .on("collect", (m) => { resolve(m); })
+ int = m.channel.createMessageCollector({filter: (m) => messageFilter(m), time: 600000})
+ .then("collect", (m) => { try {m.delete();} catch {}; resolve(m); })
+ mes.on("end", () => { int.stop(); })
+ int.on("end", () => { mes.stop(); })
+ })
+ } catch(e) {
+ console.log(e)
+ return null;
+ }
+
+ return out;
+}
+
+export async function modalInteractionCollector(m, modalFilter, interactionFilter) {
+ let out;
+ try {
+ out = await new Promise((resolve, reject) => {
+ let mod, int;
+ int = m.createMessageComponentCollector({filter: (m) => interactionFilter(m), time: 600000})
+ .on("collect", (m) => { resolve(m); })
+ mod = new Discord.InteractionCollector(
+ client, {
+ filter: (m) => modalFilter(m),
+ time: 600000
+ })
+ .on("collect", async (m) => {
+ int.stop();
+ (m as Discord.ModalSubmitInteraction).deferUpdate()
+ resolve((m as Discord.ModalSubmitInteraction)); })
+ int.on("end", () => { mod.stop(); })
+ mod.on("end", () => { int.stop(); })
+ })
+ } catch(e) {
+ console.log(e)
+ return null;
+ }
+ return out;
+}
\ No newline at end of file
diff --git a/src/utils/generateConfig.ts b/src/utils/generateConfig.ts
deleted file mode 100644
index 39b28b0..0000000
--- a/src/utils/generateConfig.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import * as fs from 'fs';
-
-function writeLogConfig(guild, logs) {
- if( !fs.existsSync(`./data/guilds/${guild.id}/config.json`) ) {
- fs.rmSync(`./data/guilds/${guild.id}/config.json`);
- }
- if( !fs.existsSync(`./data/guilds/${guild.id}/pins.json`) ) {
- let pins = guild.channels.cache.filter(c => c.type === "GUILD_TEXT").map(
- c => c.messages.fetchPinned().then(m => m.map(m => m.id))
- );
- fs.writeFileSync(`./data/guilds/${guild.id}/pins.json`, JSON.stringify(pins));
- }
- if( !fs.existsSync(`./data/guilds/${guild.id}/logs.json`) ) {
- fs.writeFileSync(`./data/guilds/${guild.id}/logs.json`, JSON.stringify([]));
- } else if( logs ) {
- fs.rmSync(`./data/guilds/${guild.id}/logs.json`);
- fs.writeFileSync(`./data/guilds/${guild.id}/logs.json`, JSON.stringify([]));
- }
- fs.writeFileSync(`./data/guilds/${guild.id}/config.json`, JSON.stringify({
- metadata: {
- premium: false
- },
- logs: {
- enabled: true,
- logChannel: guild.systemChannelId,
- toLog: "8be71",
- toIgnore: {
- bots: false,
- channels: [],
- members: [],
- roles: []
- }
- },
- userVerification: {
- enabled: false,
- roleID: null,
- customMessage: null
- },
- modmail: {
- enabled: false,
- categoryId: null,
- namingScheme: "rsm-{user}-{discriminator}",
- },
- welcome: {
- enabled: false,
- channelId: null,
- message: null,
- messageType: "embed",
- },
- filters: {
- images: {
- NSFW: true,
- size: true
- },
- malware: true,
- wordFilter: {
- enabled: true,
- words: {
- strict: [],
- loose: []
- },
- allowed: {
- users: [],
- roles: [],
- channels: []
- }
- },
- invite: {
- enabled: true,
- allowed: {
- users: [],
- channels: [],
- roles: []
- }
- },
- pings: {
- mass: 5,
- everyone: true,
- roles: true,
- allowed: {
- roles: [],
- rolesToMention: [],
- users: [],
- channels: []
- }
- }
- },
- tags: {}
- }));
-}
-
-export default writeLogConfig;
\ No newline at end of file
diff --git a/src/utils/log.ts b/src/utils/log.ts
index 238b6f4..19eb2b6 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -1,10 +1,10 @@
import * as fs from 'fs';
import * as Discord from 'discord.js';
import getEmojiByName from './getEmojiByName.js';
-import readConfig from './readConfig.js';
import { toHexArray } from './calculate.js';
import { promisify } from 'util';
import generateKeyValueList from './generateKeyValueList.js';
+import client from './client.js';
const wait = promisify(setTimeout);
@@ -52,8 +52,8 @@
return auditLog;
}
- async log(log: any, client): Promise<void> {
- let config = await readConfig(log.hidden.guild);
+ async log(log: any): Promise<void> {
+ let config = await client.database.read(log.hidden.guild);
if (!config.logging.logs.enabled) return;
if (!(log.meta.calculateType == true)) {
if(!toHexArray(config.logging.logs.toLog).includes(log.meta.calculateType)) return console.log('Not logging this type of event');
diff --git a/src/utils/memory.ts b/src/utils/memory.ts
index 0cbf955..7e21fa9 100644
--- a/src/utils/memory.ts
+++ b/src/utils/memory.ts
@@ -1,22 +1,31 @@
-import readConfig from "./readConfig.js";
+import client from "./client.js";
class Memory {
memory: {};
constructor() {
this.memory = {};
+
+ setInterval(() => {
+ for (let guild in this.memory) {
+ if (this.memory[guild].updated + 15 * 60 * 1000 < Date.now()) {
+ delete this.memory[guild];
+ }
+ }
+ }, 1000 * 60 * 30)
}
async readGuildInfo(guild: string): Promise<object> {
if (!this.memory[guild]) {
- let guildData = await readConfig(guild);
+ let guildData = await client.database.read(guild);
this.memory[guild] = {
+ lastUpdated: Date.now(),
filters: guildData.filters,
logging: guildData.logging,
tickets: guildData.tickets,
- }; // TODO: REMOVE GUILD FROM MEMORY WHEN THESE UPDATE
- } // TODO: Add a "lastAccessed" prop, delete after 15 minutes
+ };
+ };
return this.memory[guild];
}
}
-export default Memory;
\ No newline at end of file
+export default Memory;
diff --git a/src/utils/readConfig.ts b/src/utils/readConfig.ts
deleted file mode 100644
index b363fc0..0000000
--- a/src/utils/readConfig.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import client from './client.js';
-
-export default async function readConfig(guild: string): Promise<any> {
- return await client.database.read(guild);
-}
diff --git a/src/utils/singleNotify.ts b/src/utils/singleNotify.ts
index 4e9e6fe..a983478 100644
--- a/src/utils/singleNotify.ts
+++ b/src/utils/singleNotify.ts
@@ -1,4 +1,4 @@
-import readConfig from "./readConfig.js";
+import client from './client.js';
import generateEmojiEmbed from "./generateEmojiEmbed.js";
let severities = {
@@ -7,17 +7,18 @@
"Info": "Success"
}
-export default async function(client, type: string, guild: string, message: string, severity: string) {
- let config = await readConfig(guild);
- if (config.singleEventNotifications[type]) return;
- // TODO: Set config.singleEventNotifications[type] to true
- let channel = await client.channels.fetch(config.logging.staff);
- if (!channel) return;
+export default async function(type: string, guild: string, message: string, severity: string) {
+ let data = await client.database.read(guild);
+ if (data.singleEventNotifications[type]) return;
+ data.singleEventNotifications[type] = true;
+ client.database.write(guild, data);
try {
+ let channel = await client.channels.fetch(data.logging.staff.channel);
+ if (!channel) return;
await channel.send({embeds: [new generateEmojiEmbed()
.setTitle(`${severity} notification`)
.setDescription(message)
- .setColor(severities[severity])
+ .setStatus(severities[severity])
.setEmoji("CONTROL.BLOCKCROSS")
]})
} catch (err) {