blob: 10b0ddbbf42510d1f216a913a349d32e20f91489 [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
TheCodedProffc420b72023-01-24 17:14:38 -0500220 addPremium(user: string, guild: string) {
TheCodedProf267563a2023-01-21 17:00:57 -0500221 return this.premium.updateOne({ user: user }, { $addToSet: { appliesTo: guild } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100222 }
TheCodedProffc420b72023-01-24 17:14:38 -0500223
224 removePremium(user: string, guild: string) {
225 return this.premium.updateOne({ user: user }, { $pull: { appliesTo: guild } });
226 }
pineafan4edb7762022-06-26 19:21:04 +0100227}
228
pineafan6fb3e072022-05-20 19:27:23 +0100229export interface GuildConfig {
Skyler Grey75ea9172022-08-06 10:22:23 +0100230 id: string;
231 version: number;
PineaFan100df682023-01-02 13:26:08 +0000232 singleEventNotifications: Record<string, boolean>;
pineafan6fb3e072022-05-20 19:27:23 +0100233 filters: {
234 images: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100235 NSFW: boolean;
236 size: boolean;
237 };
238 malware: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100239 wordFilter: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100240 enabled: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100241 words: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 strict: string[];
243 loose: string[];
244 };
pineafan6fb3e072022-05-20 19:27:23 +0100245 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100246 users: string[];
247 roles: string[];
248 channels: string[];
249 };
250 };
pineafan6fb3e072022-05-20 19:27:23 +0100251 invite: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100252 enabled: boolean;
PineaFan538d3752023-01-12 21:48:23 +0000253 allowed: {
254 channels: string[];
255 roles: string[];
256 users: string[];
257 };
Skyler Grey75ea9172022-08-06 10:22:23 +0100258 };
pineafan6fb3e072022-05-20 19:27:23 +0100259 pings: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100260 mass: number;
261 everyone: boolean;
262 roles: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100263 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100264 roles: string[];
265 rolesToMention: string[];
266 users: string[];
267 channels: string[];
268 };
269 };
270 };
pineafan6fb3e072022-05-20 19:27:23 +0100271 welcome: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100272 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100273 role: string | null;
274 ping: string | null;
275 channel: string | null;
276 message: string | null;
277 };
278 stats: Record<string, { name: string; enabled: boolean }>;
pineafan6fb3e072022-05-20 19:27:23 +0100279 logging: {
280 logs: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100281 enabled: boolean;
282 channel: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100283 toLog: string;
Skyler Grey75ea9172022-08-06 10:22:23 +0100284 };
pineafan6fb3e072022-05-20 19:27:23 +0100285 staff: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100286 channel: string | null;
287 };
pineafan73a7c4a2022-07-24 10:38:04 +0100288 attachments: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100289 channel: string | null;
290 saved: Record<string, string>;
291 };
292 };
pineafan6fb3e072022-05-20 19:27:23 +0100293 verify: {
PineaFandf4996f2023-01-01 14:20:06 +0000294 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100295 role: string | null;
296 };
pineafan6fb3e072022-05-20 19:27:23 +0100297 tickets: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100298 enabled: boolean;
299 category: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100300 types: string;
301 customTypes: string[] | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100302 useCustom: boolean;
303 supportRole: string | null;
304 maxTickets: number;
305 };
pineafan6fb3e072022-05-20 19:27:23 +0100306 moderation: {
307 mute: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100308 timeout: boolean;
309 role: string | null;
310 text: string | null;
311 link: string | null;
312 };
pineafan6fb3e072022-05-20 19:27:23 +0100313 kick: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100314 text: string | null;
315 link: string | null;
316 };
pineafan6fb3e072022-05-20 19:27:23 +0100317 ban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100318 text: string | null;
319 link: string | null;
320 };
pineafan6fb3e072022-05-20 19:27:23 +0100321 softban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100322 text: string | null;
323 link: string | null;
324 };
pineafan6fb3e072022-05-20 19:27:23 +0100325 warn: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100326 text: string | null;
327 link: string | null;
328 };
pineafan6fb3e072022-05-20 19:27:23 +0100329 role: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100330 role: string | null;
TheCodedProfd9636e82023-01-17 22:13:06 -0500331 text: null;
332 link: null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100333 };
PineaFane6ba7882023-01-18 20:41:16 +0000334 nick: {
335 text: string | null;
336 link: string | null;
337 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100338 };
pineafan6fb3e072022-05-20 19:27:23 +0100339 tracks: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100340 name: string;
341 retainPrevious: boolean;
342 nullable: boolean;
343 track: string[];
344 manageableBy: string[];
345 }[];
pineafan6fb3e072022-05-20 19:27:23 +0100346 roleMenu: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100347 enabled: boolean;
348 allowWebUI: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100349 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100350 name: string;
351 description: string;
352 min: number;
353 max: number;
pineafan6fb3e072022-05-20 19:27:23 +0100354 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100355 name: string;
356 description: string | null;
357 role: string;
358 }[];
359 }[];
360 };
361 tags: Record<string, string>;
pineafan63fc5e22022-08-04 22:04:10 +0100362}
pineafan4edb7762022-06-26 19:21:04 +0100363
364export interface HistorySchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100365 type: string;
366 guild: string;
367 user: string;
368 moderator: string | null;
pineafan3a02ea32022-08-11 21:35:04 +0100369 reason: string | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100370 occurredAt: Date;
371 before: string | null;
372 after: string | null;
373 amount: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100374}
375
376export interface ModNoteSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100377 guild: string;
378 user: string;
pineafan3a02ea32022-08-11 21:35:04 +0100379 note: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100380}
381
pineafan73a7c4a2022-07-24 10:38:04 +0100382export interface PremiumSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100383 user: string;
384 level: number;
385 expires: Date;
386 appliesTo: string[];
387}