blob: ba1d89def459b318b691709c0a1e0d98044fe223 [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 ) {
pineafan63fc5e22022-08-04 22:04:10 +010070 console.log(Array.isArray(value));
pineafan02ba0232022-07-24 22:16:15 +010071 if (innerKey) {
Skyler Grey75ea9172022-08-06 10:22:23 +010072 await this.guilds.updateOne(
73 { id: guild },
74 {
75 $pull: { [key]: { [innerKey]: { $eq: value } } }
76 },
77 { upsert: true }
78 );
pineafan0bc04162022-07-25 17:22:26 +010079 } else if (Array.isArray(value)) {
Skyler Grey75ea9172022-08-06 10:22:23 +010080 await this.guilds.updateOne(
81 { id: guild },
82 {
83 $pullAll: { [key]: value }
84 },
85 { upsert: true }
86 );
pineafan6702cef2022-06-13 17:52:37 +010087 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +010088 await this.guilds.updateOne(
89 { id: guild },
90 {
91 $pullAll: { [key]: [value] }
92 },
93 { upsert: true }
94 );
pineafan6702cef2022-06-13 17:52:37 +010095 }
pineafan6fb3e072022-05-20 19:27:23 +010096 }
pineafane23c4ec2022-07-27 21:56:27 +010097
98 async delete(guild: string) {
99 await this.guilds.deleteOne({ id: guild });
100 }
pineafan6fb3e072022-05-20 19:27:23 +0100101}
102
pineafan4edb7762022-06-26 19:21:04 +0100103export class History {
104 histories: Collection<HistorySchema>;
pineafan4edb7762022-06-26 19:21:04 +0100105
pineafan3a02ea32022-08-11 21:35:04 +0100106 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100107 this.histories = database.collection<HistorySchema>("history");
pineafan4edb7762022-06-26 19:21:04 +0100108 }
109
Skyler Grey75ea9172022-08-06 10:22:23 +0100110 async create(
111 type: string,
112 guild: string,
113 user: Discord.User,
114 moderator: Discord.User | null,
115 reason: string | null,
pineafan3a02ea32022-08-11 21:35:04 +0100116 before?: string | null,
117 after?: string | null,
118 amount?: string | null
Skyler Grey75ea9172022-08-06 10:22:23 +0100119 ) {
pineafan4edb7762022-06-26 19:21:04 +0100120 await this.histories.insertOne({
121 type: type,
122 guild: guild,
123 user: user.id,
pineafan3a02ea32022-08-11 21:35:04 +0100124 moderator: moderator ? moderator.id : null,
pineafan4edb7762022-06-26 19:21:04 +0100125 reason: reason,
126 occurredAt: new Date(),
pineafan3a02ea32022-08-11 21:35:04 +0100127 before: before ?? null,
128 after: after ?? null,
129 amount: amount ?? null
pineafan4edb7762022-06-26 19:21:04 +0100130 });
131 }
132
133 async read(guild: string, user: string, year: number) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100134 const entry = (await this.histories
135 .find({
136 guild: guild,
137 user: user,
138 occurredAt: {
139 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
140 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
141 }
142 })
143 .toArray()) as HistorySchema[];
pineafan4edb7762022-06-26 19:21:04 +0100144 return entry;
145 }
pineafane23c4ec2022-07-27 21:56:27 +0100146
147 async delete(guild: string) {
148 await this.histories.deleteMany({ guild: guild });
149 }
pineafan4edb7762022-06-26 19:21:04 +0100150}
151
PineaFan538d3752023-01-12 21:48:23 +0000152export class PerformanceTest {
153 performanceData: Collection<PerformanceDataSchema>;
154
155 constructor() {
156 this.performanceData = database.collection<PerformanceDataSchema>("performance");
157 }
158
159 async record(data: PerformanceDataSchema) {
160 data.timestamp = new Date();
161 await this.performanceData.insertOne(data);
162 }
163 async read() {
164 return await this.performanceData.find({}).toArray();
165 }
166}
167
168export interface PerformanceDataSchema {
169 timestamp?: Date;
170 discord: number;
171 databaseRead: number;
172 resources: {
173 cpu: number;
174 memory: number;
175 temperature: number;
176 }
177}
178
pineafan4edb7762022-06-26 19:21:04 +0100179export class ModNotes {
180 modNotes: Collection<ModNoteSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100181
pineafan3a02ea32022-08-11 21:35:04 +0100182 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100183 this.modNotes = database.collection<ModNoteSchema>("modNotes");
pineafan4edb7762022-06-26 19:21:04 +0100184 }
185
186 async create(guild: string, user: string, note: string | null) {
Skyler Grey11236ba2022-08-08 21:13:33 +0100187 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100188 }
189
190 async read(guild: string, user: string) {
pineafan63fc5e22022-08-04 22:04:10 +0100191 const entry = await this.modNotes.findOne({ guild: guild, user: user });
pineafan4edb7762022-06-26 19:21:04 +0100192 return entry?.note ?? null;
193 }
194}
195
pineafan73a7c4a2022-07-24 10:38:04 +0100196export class Premium {
197 premium: Collection<PremiumSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100198
pineafan3a02ea32022-08-11 21:35:04 +0100199 constructor() {
pineafan73a7c4a2022-07-24 10:38:04 +0100200 this.premium = database.collection<PremiumSchema>("premium");
pineafan4edb7762022-06-26 19:21:04 +0100201 }
202
pineafan73a7c4a2022-07-24 10:38:04 +0100203 async hasPremium(guild: string) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100204 const entry = await this.premium.findOne({
205 appliesTo: { $in: [guild] }
206 });
pineafane23c4ec2022-07-27 21:56:27 +0100207 return entry !== null;
pineafan4edb7762022-06-26 19:21:04 +0100208 }
209}
210
pineafan6fb3e072022-05-20 19:27:23 +0100211export interface GuildConfig {
Skyler Grey75ea9172022-08-06 10:22:23 +0100212 id: string;
213 version: number;
PineaFan100df682023-01-02 13:26:08 +0000214 singleEventNotifications: Record<string, boolean>;
pineafan6fb3e072022-05-20 19:27:23 +0100215 filters: {
216 images: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100217 NSFW: boolean;
218 size: boolean;
219 };
220 malware: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100221 wordFilter: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100222 enabled: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100223 words: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100224 strict: string[];
225 loose: string[];
226 };
pineafan6fb3e072022-05-20 19:27:23 +0100227 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100228 users: string[];
229 roles: string[];
230 channels: string[];
231 };
232 };
pineafan6fb3e072022-05-20 19:27:23 +0100233 invite: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100234 enabled: boolean;
PineaFan538d3752023-01-12 21:48:23 +0000235 allowed: {
236 channels: string[];
237 roles: string[];
238 users: string[];
239 };
Skyler Grey75ea9172022-08-06 10:22:23 +0100240 };
pineafan6fb3e072022-05-20 19:27:23 +0100241 pings: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 mass: number;
243 everyone: boolean;
244 roles: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100245 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100246 roles: string[];
247 rolesToMention: string[];
248 users: string[];
249 channels: string[];
250 };
251 };
252 };
pineafan6fb3e072022-05-20 19:27:23 +0100253 welcome: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100254 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100255 role: string | null;
256 ping: string | null;
257 channel: string | null;
258 message: string | null;
259 };
260 stats: Record<string, { name: string; enabled: boolean }>;
pineafan6fb3e072022-05-20 19:27:23 +0100261 logging: {
262 logs: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100263 enabled: boolean;
264 channel: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100265 toLog: string;
Skyler Grey75ea9172022-08-06 10:22:23 +0100266 };
pineafan6fb3e072022-05-20 19:27:23 +0100267 staff: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100268 channel: string | null;
269 };
pineafan73a7c4a2022-07-24 10:38:04 +0100270 attachments: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100271 channel: string | null;
272 saved: Record<string, string>;
273 };
274 };
pineafan6fb3e072022-05-20 19:27:23 +0100275 verify: {
PineaFandf4996f2023-01-01 14:20:06 +0000276 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100277 role: string | null;
278 };
pineafan6fb3e072022-05-20 19:27:23 +0100279 tickets: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100280 enabled: boolean;
281 category: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100282 types: string;
283 customTypes: string[] | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100284 useCustom: boolean;
285 supportRole: string | null;
286 maxTickets: number;
287 };
pineafan6fb3e072022-05-20 19:27:23 +0100288 moderation: {
289 mute: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100290 timeout: boolean;
291 role: string | null;
292 text: string | null;
293 link: string | null;
294 };
pineafan6fb3e072022-05-20 19:27:23 +0100295 kick: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100296 text: string | null;
297 link: string | null;
298 };
pineafan6fb3e072022-05-20 19:27:23 +0100299 ban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100300 text: string | null;
301 link: string | null;
302 };
pineafan6fb3e072022-05-20 19:27:23 +0100303 softban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100304 text: string | null;
305 link: string | null;
306 };
pineafan6fb3e072022-05-20 19:27:23 +0100307 warn: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100308 text: string | null;
309 link: string | null;
310 };
pineafan6fb3e072022-05-20 19:27:23 +0100311 role: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100312 role: string | null;
313 };
314 };
pineafan6fb3e072022-05-20 19:27:23 +0100315 tracks: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100316 name: string;
317 retainPrevious: boolean;
318 nullable: boolean;
319 track: string[];
320 manageableBy: string[];
321 }[];
pineafan6fb3e072022-05-20 19:27:23 +0100322 roleMenu: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100323 enabled: boolean;
324 allowWebUI: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100325 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100326 name: string;
327 description: string;
328 min: number;
329 max: number;
pineafan6fb3e072022-05-20 19:27:23 +0100330 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100331 name: string;
332 description: string | null;
333 role: string;
334 }[];
335 }[];
336 };
337 tags: Record<string, string>;
pineafan63fc5e22022-08-04 22:04:10 +0100338}
pineafan4edb7762022-06-26 19:21:04 +0100339
340export interface HistorySchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100341 type: string;
342 guild: string;
343 user: string;
344 moderator: string | null;
pineafan3a02ea32022-08-11 21:35:04 +0100345 reason: string | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100346 occurredAt: Date;
347 before: string | null;
348 after: string | null;
349 amount: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100350}
351
352export interface ModNoteSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100353 guild: string;
354 user: string;
pineafan3a02ea32022-08-11 21:35:04 +0100355 note: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100356}
357
pineafan73a7c4a2022-07-24 10:38:04 +0100358export interface PremiumSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100359 user: string;
360 level: number;
361 expires: Date;
362 appliesTo: string[];
363}