blob: 3d4ca782922e5e7a46eb887c68036a6d0c6aa918 [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import type Discord from "discord.js";
2import { Collection, MongoClient } from "mongodb";
Skyler Grey75ea9172022-08-06 10:22:23 +01003import config from "../config/main.json" assert { type: "json" };
pineafan4edb7762022-06-26 19:21:04 +01004
5const mongoClient = new MongoClient(config.mongoUrl);
pineafan63fc5e22022-08-04 22:04:10 +01006await mongoClient.connect();
pineafan4edb7762022-06-26 19:21:04 +01007const database = mongoClient.db("Nucleus");
pineafan6fb3e072022-05-20 19:27:23 +01008
pineafan4edb7762022-06-26 19:21:04 +01009export class Guilds {
pineafan6fb3e072022-05-20 19:27:23 +010010 guilds: Collection<GuildConfig>;
pineafan63fc5e22022-08-04 22:04:10 +010011 defaultData: GuildConfig | null;
12
13 constructor() {
pineafan4edb7762022-06-26 19:21:04 +010014 this.guilds = database.collection<GuildConfig>("guilds");
pineafan63fc5e22022-08-04 22:04:10 +010015 this.defaultData = null;
pineafan6fb3e072022-05-20 19:27:23 +010016 }
17
Skyler Greyad002172022-08-16 18:48:26 +010018 async setup(): Promise<Guilds> {
Skyler Grey11236ba2022-08-08 21:13:33 +010019 this.defaultData = (await import("../config/default.json", { assert: { type: "json" } }))
20 .default as unknown as GuildConfig;
21 return this;
pineafan63fc5e22022-08-04 22:04:10 +010022 }
23
Skyler Greyad002172022-08-16 18:48:26 +010024 async read(guild: string): Promise<GuildConfig> {
pineafan63fc5e22022-08-04 22:04:10 +010025 const entry = await this.guilds.findOne({ id: guild });
PineaFandf4996f2023-01-01 14:20:06 +000026 return Object.assign({}, this.defaultData, entry);
pineafan6fb3e072022-05-20 19:27:23 +010027 }
28
Skyler Grey11236ba2022-08-08 21:13:33 +010029 async write(guild: string, set: object | null, unset: string[] | string = []) {
pineafan63fc5e22022-08-04 22:04:10 +010030 // eslint-disable-next-line @typescript-eslint/no-explicit-any
31 const uo: Record<string, any> = {};
32 if (!Array.isArray(unset)) unset = [unset];
33 for (const key of unset) {
pineafan0bc04162022-07-25 17:22:26 +010034 uo[key] = null;
pineafan6702cef2022-06-13 17:52:37 +010035 }
Skyler Grey75ea9172022-08-06 10:22:23 +010036 const out = { $set: {}, $unset: {} };
37 if (set) out.$set = set;
38 if (unset.length) out.$unset = uo;
pineafan0bc04162022-07-25 17:22:26 +010039 await this.guilds.updateOne({ id: guild }, out, { upsert: true });
pineafan6702cef2022-06-13 17:52:37 +010040 }
41
pineafan63fc5e22022-08-04 22:04:10 +010042 // eslint-disable-next-line @typescript-eslint/no-explicit-any
pineafan6702cef2022-06-13 17:52:37 +010043 async append(guild: string, key: string, value: any) {
44 if (Array.isArray(value)) {
Skyler Grey75ea9172022-08-06 10:22:23 +010045 await this.guilds.updateOne(
46 { id: guild },
47 {
48 $addToSet: { [key]: { $each: value } }
49 },
50 { upsert: true }
51 );
pineafan6702cef2022-06-13 17:52:37 +010052 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +010053 await this.guilds.updateOne(
54 { id: guild },
55 {
56 $addToSet: { [key]: value }
57 },
58 { upsert: true }
59 );
pineafan6702cef2022-06-13 17:52:37 +010060 }
61 }
62
Skyler Grey75ea9172022-08-06 10:22:23 +010063 async remove(
64 guild: string,
65 key: string,
Skyler Greyc634e2b2022-08-06 17:50:48 +010066 // eslint-disable-next-line @typescript-eslint/no-explicit-any
Skyler Grey75ea9172022-08-06 10:22:23 +010067 value: any,
68 innerKey?: string | null
69 ) {
pineafan02ba0232022-07-24 22:16:15 +010070 if (innerKey) {
Skyler Grey75ea9172022-08-06 10:22:23 +010071 await this.guilds.updateOne(
72 { id: guild },
73 {
74 $pull: { [key]: { [innerKey]: { $eq: value } } }
75 },
76 { upsert: true }
77 );
pineafan0bc04162022-07-25 17:22:26 +010078 } else if (Array.isArray(value)) {
Skyler Grey75ea9172022-08-06 10:22:23 +010079 await this.guilds.updateOne(
80 { id: guild },
81 {
82 $pullAll: { [key]: value }
83 },
84 { upsert: true }
85 );
pineafan6702cef2022-06-13 17:52:37 +010086 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +010087 await this.guilds.updateOne(
88 { id: guild },
89 {
90 $pullAll: { [key]: [value] }
91 },
92 { upsert: true }
93 );
pineafan6702cef2022-06-13 17:52:37 +010094 }
pineafan6fb3e072022-05-20 19:27:23 +010095 }
pineafane23c4ec2022-07-27 21:56:27 +010096
97 async delete(guild: string) {
98 await this.guilds.deleteOne({ id: guild });
99 }
pineafan6fb3e072022-05-20 19:27:23 +0100100}
101
pineafan4edb7762022-06-26 19:21:04 +0100102export class History {
103 histories: Collection<HistorySchema>;
pineafan4edb7762022-06-26 19:21:04 +0100104
pineafan3a02ea32022-08-11 21:35:04 +0100105 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100106 this.histories = database.collection<HistorySchema>("history");
pineafan4edb7762022-06-26 19:21:04 +0100107 }
108
Skyler Grey75ea9172022-08-06 10:22:23 +0100109 async create(
110 type: string,
111 guild: string,
112 user: Discord.User,
113 moderator: Discord.User | null,
114 reason: string | null,
pineafan3a02ea32022-08-11 21:35:04 +0100115 before?: string | null,
116 after?: string | null,
117 amount?: string | null
Skyler Grey75ea9172022-08-06 10:22:23 +0100118 ) {
pineafan4edb7762022-06-26 19:21:04 +0100119 await this.histories.insertOne({
120 type: type,
121 guild: guild,
122 user: user.id,
pineafan3a02ea32022-08-11 21:35:04 +0100123 moderator: moderator ? moderator.id : null,
pineafan4edb7762022-06-26 19:21:04 +0100124 reason: reason,
125 occurredAt: new Date(),
pineafan3a02ea32022-08-11 21:35:04 +0100126 before: before ?? null,
127 after: after ?? null,
128 amount: amount ?? null
pineafan4edb7762022-06-26 19:21:04 +0100129 });
130 }
131
132 async read(guild: string, user: string, year: number) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100133 const entry = (await this.histories
134 .find({
135 guild: guild,
136 user: user,
137 occurredAt: {
138 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
139 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
140 }
141 })
142 .toArray()) as HistorySchema[];
pineafan4edb7762022-06-26 19:21:04 +0100143 return entry;
144 }
pineafane23c4ec2022-07-27 21:56:27 +0100145
146 async delete(guild: string) {
147 await this.histories.deleteMany({ guild: guild });
148 }
pineafan4edb7762022-06-26 19:21:04 +0100149}
150
PineaFan538d3752023-01-12 21:48:23 +0000151export class PerformanceTest {
152 performanceData: Collection<PerformanceDataSchema>;
153
154 constructor() {
155 this.performanceData = database.collection<PerformanceDataSchema>("performance");
156 }
157
158 async record(data: PerformanceDataSchema) {
159 data.timestamp = new Date();
160 await this.performanceData.insertOne(data);
161 }
162 async read() {
163 return await this.performanceData.find({}).toArray();
164 }
165}
166
167export interface PerformanceDataSchema {
168 timestamp?: Date;
169 discord: number;
170 databaseRead: number;
171 resources: {
172 cpu: number;
173 memory: number;
174 temperature: number;
175 }
176}
177
pineafan4edb7762022-06-26 19:21:04 +0100178export class ModNotes {
179 modNotes: Collection<ModNoteSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100180
pineafan3a02ea32022-08-11 21:35:04 +0100181 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100182 this.modNotes = database.collection<ModNoteSchema>("modNotes");
pineafan4edb7762022-06-26 19:21:04 +0100183 }
184
185 async create(guild: string, user: string, note: string | null) {
Skyler Grey11236ba2022-08-08 21:13:33 +0100186 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100187 }
188
189 async read(guild: string, user: string) {
pineafan63fc5e22022-08-04 22:04:10 +0100190 const entry = await this.modNotes.findOne({ guild: guild, user: user });
pineafan4edb7762022-06-26 19:21:04 +0100191 return entry?.note ?? null;
192 }
TheCodedProf267563a2023-01-21 17:00:57 -0500193
194 async delete(guild: string) {
195 await this.modNotes.deleteMany({ guild: guild });
196 }
pineafan4edb7762022-06-26 19:21:04 +0100197}
198
pineafan73a7c4a2022-07-24 10:38:04 +0100199export class Premium {
200 premium: Collection<PremiumSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100201
pineafan3a02ea32022-08-11 21:35:04 +0100202 constructor() {
pineafan73a7c4a2022-07-24 10:38:04 +0100203 this.premium = database.collection<PremiumSchema>("premium");
pineafan4edb7762022-06-26 19:21:04 +0100204 }
205
pineafan73a7c4a2022-07-24 10:38:04 +0100206 async hasPremium(guild: string) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100207 const entry = await this.premium.findOne({
208 appliesTo: { $in: [guild] }
209 });
TheCodedProf267563a2023-01-21 17:00:57 -0500210 if (!entry) return false;
211 return entry.expires.valueOf() > Date.now();
212 }
213
214 async fetchTotal(user: string): Promise<number> {
215 const entry = await this.premium.findOne({ user: user });
216 if (!entry) return 0;
217 return entry.appliesTo.length;
218 }
219
220 setPremium(user: string, guild: string) {
221 return this.premium.updateOne({ user: user }, { $addToSet: { appliesTo: guild } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100222 }
223}
224
pineafan6fb3e072022-05-20 19:27:23 +0100225export interface GuildConfig {
Skyler Grey75ea9172022-08-06 10:22:23 +0100226 id: string;
227 version: number;
PineaFan100df682023-01-02 13:26:08 +0000228 singleEventNotifications: Record<string, boolean>;
pineafan6fb3e072022-05-20 19:27:23 +0100229 filters: {
230 images: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100231 NSFW: boolean;
232 size: boolean;
233 };
234 malware: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100235 wordFilter: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100236 enabled: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100237 words: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100238 strict: string[];
239 loose: string[];
240 };
pineafan6fb3e072022-05-20 19:27:23 +0100241 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 users: string[];
243 roles: string[];
244 channels: string[];
245 };
246 };
pineafan6fb3e072022-05-20 19:27:23 +0100247 invite: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100248 enabled: boolean;
PineaFan538d3752023-01-12 21:48:23 +0000249 allowed: {
250 channels: string[];
251 roles: string[];
252 users: string[];
253 };
Skyler Grey75ea9172022-08-06 10:22:23 +0100254 };
pineafan6fb3e072022-05-20 19:27:23 +0100255 pings: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100256 mass: number;
257 everyone: boolean;
258 roles: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100259 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100260 roles: string[];
261 rolesToMention: string[];
262 users: string[];
263 channels: string[];
264 };
265 };
266 };
pineafan6fb3e072022-05-20 19:27:23 +0100267 welcome: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100268 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100269 role: string | null;
270 ping: string | null;
271 channel: string | null;
272 message: string | null;
273 };
274 stats: Record<string, { name: string; enabled: boolean }>;
pineafan6fb3e072022-05-20 19:27:23 +0100275 logging: {
276 logs: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100277 enabled: boolean;
278 channel: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100279 toLog: string;
Skyler Grey75ea9172022-08-06 10:22:23 +0100280 };
pineafan6fb3e072022-05-20 19:27:23 +0100281 staff: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100282 channel: string | null;
283 };
pineafan73a7c4a2022-07-24 10:38:04 +0100284 attachments: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100285 channel: string | null;
286 saved: Record<string, string>;
287 };
288 };
pineafan6fb3e072022-05-20 19:27:23 +0100289 verify: {
PineaFandf4996f2023-01-01 14:20:06 +0000290 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100291 role: string | null;
292 };
pineafan6fb3e072022-05-20 19:27:23 +0100293 tickets: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100294 enabled: boolean;
295 category: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100296 types: string;
297 customTypes: string[] | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100298 useCustom: boolean;
299 supportRole: string | null;
300 maxTickets: number;
301 };
pineafan6fb3e072022-05-20 19:27:23 +0100302 moderation: {
303 mute: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100304 timeout: boolean;
305 role: string | null;
306 text: string | null;
307 link: string | null;
308 };
pineafan6fb3e072022-05-20 19:27:23 +0100309 kick: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100310 text: string | null;
311 link: string | null;
312 };
pineafan6fb3e072022-05-20 19:27:23 +0100313 ban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100314 text: string | null;
315 link: string | null;
316 };
pineafan6fb3e072022-05-20 19:27:23 +0100317 softban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100318 text: string | null;
319 link: string | null;
320 };
pineafan6fb3e072022-05-20 19:27:23 +0100321 warn: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100322 text: string | null;
323 link: string | null;
324 };
pineafan6fb3e072022-05-20 19:27:23 +0100325 role: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100326 role: string | null;
TheCodedProfd9636e82023-01-17 22:13:06 -0500327 text: null;
328 link: null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100329 };
PineaFane6ba7882023-01-18 20:41:16 +0000330 nick: {
331 text: string | null;
332 link: string | null;
333 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100334 };
pineafan6fb3e072022-05-20 19:27:23 +0100335 tracks: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100336 name: string;
337 retainPrevious: boolean;
338 nullable: boolean;
339 track: string[];
340 manageableBy: string[];
341 }[];
pineafan6fb3e072022-05-20 19:27:23 +0100342 roleMenu: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100343 enabled: boolean;
344 allowWebUI: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100345 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100346 name: string;
347 description: string;
348 min: number;
349 max: number;
pineafan6fb3e072022-05-20 19:27:23 +0100350 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100351 name: string;
352 description: string | null;
353 role: string;
354 }[];
355 }[];
356 };
357 tags: Record<string, string>;
pineafan63fc5e22022-08-04 22:04:10 +0100358}
pineafan4edb7762022-06-26 19:21:04 +0100359
360export interface HistorySchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100361 type: string;
362 guild: string;
363 user: string;
364 moderator: string | null;
pineafan3a02ea32022-08-11 21:35:04 +0100365 reason: string | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100366 occurredAt: Date;
367 before: string | null;
368 after: string | null;
369 amount: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100370}
371
372export interface ModNoteSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100373 guild: string;
374 user: string;
pineafan3a02ea32022-08-11 21:35:04 +0100375 note: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100376}
377
pineafan73a7c4a2022-07-24 10:38:04 +0100378export interface PremiumSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100379 user: string;
380 level: number;
381 expires: Date;
382 appliesTo: string[];
383}