blob: 2624fc9874f29fa917124eb7768f89f7e9170496 [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import type Discord from "discord.js";
2import { Collection, MongoClient } from "mongodb";
PineaFan100df682023-01-02 13:26:08 +00003// @ts-expect-error
Skyler Grey75ea9172022-08-06 10:22:23 +01004import config from "../config/main.json" assert { type: "json" };
pineafan4edb7762022-06-26 19:21:04 +01005
6const mongoClient = new MongoClient(config.mongoUrl);
pineafan63fc5e22022-08-04 22:04:10 +01007await mongoClient.connect();
pineafan4edb7762022-06-26 19:21:04 +01008const database = mongoClient.db("Nucleus");
pineafan6fb3e072022-05-20 19:27:23 +01009
pineafan4edb7762022-06-26 19:21:04 +010010export class Guilds {
pineafan6fb3e072022-05-20 19:27:23 +010011 guilds: Collection<GuildConfig>;
pineafan63fc5e22022-08-04 22:04:10 +010012 defaultData: GuildConfig | null;
13
14 constructor() {
pineafan4edb7762022-06-26 19:21:04 +010015 this.guilds = database.collection<GuildConfig>("guilds");
pineafan63fc5e22022-08-04 22:04:10 +010016 this.defaultData = null;
pineafan6fb3e072022-05-20 19:27:23 +010017 }
18
Skyler Greyad002172022-08-16 18:48:26 +010019 async setup(): Promise<Guilds> {
PineaFan100df682023-01-02 13:26:08 +000020 // @ts-expect-error
Skyler Grey11236ba2022-08-08 21:13:33 +010021 this.defaultData = (await import("../config/default.json", { assert: { type: "json" } }))
22 .default as unknown as GuildConfig;
23 return this;
pineafan63fc5e22022-08-04 22:04:10 +010024 }
25
Skyler Greyad002172022-08-16 18:48:26 +010026 async read(guild: string): Promise<GuildConfig> {
pineafan63fc5e22022-08-04 22:04:10 +010027 const entry = await this.guilds.findOne({ id: guild });
PineaFandf4996f2023-01-01 14:20:06 +000028 return Object.assign({}, this.defaultData, entry);
pineafan6fb3e072022-05-20 19:27:23 +010029 }
30
Skyler Grey11236ba2022-08-08 21:13:33 +010031 async write(guild: string, set: object | null, unset: string[] | string = []) {
pineafan63fc5e22022-08-04 22:04:10 +010032 // eslint-disable-next-line @typescript-eslint/no-explicit-any
33 const uo: Record<string, any> = {};
34 if (!Array.isArray(unset)) unset = [unset];
35 for (const key of unset) {
pineafan0bc04162022-07-25 17:22:26 +010036 uo[key] = null;
pineafan6702cef2022-06-13 17:52:37 +010037 }
Skyler Grey75ea9172022-08-06 10:22:23 +010038 const out = { $set: {}, $unset: {} };
39 if (set) out.$set = set;
40 if (unset.length) out.$unset = uo;
pineafan0bc04162022-07-25 17:22:26 +010041 await this.guilds.updateOne({ id: guild }, out, { upsert: true });
pineafan6702cef2022-06-13 17:52:37 +010042 }
43
pineafan63fc5e22022-08-04 22:04:10 +010044 // eslint-disable-next-line @typescript-eslint/no-explicit-any
pineafan6702cef2022-06-13 17:52:37 +010045 async append(guild: string, key: string, value: any) {
46 if (Array.isArray(value)) {
Skyler Grey75ea9172022-08-06 10:22:23 +010047 await this.guilds.updateOne(
48 { id: guild },
49 {
50 $addToSet: { [key]: { $each: value } }
51 },
52 { upsert: true }
53 );
pineafan6702cef2022-06-13 17:52:37 +010054 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +010055 await this.guilds.updateOne(
56 { id: guild },
57 {
58 $addToSet: { [key]: value }
59 },
60 { upsert: true }
61 );
pineafan6702cef2022-06-13 17:52:37 +010062 }
63 }
64
Skyler Grey75ea9172022-08-06 10:22:23 +010065 async remove(
66 guild: string,
67 key: string,
Skyler Greyc634e2b2022-08-06 17:50:48 +010068 // eslint-disable-next-line @typescript-eslint/no-explicit-any
Skyler Grey75ea9172022-08-06 10:22:23 +010069 value: any,
70 innerKey?: string | null
71 ) {
pineafan63fc5e22022-08-04 22:04:10 +010072 console.log(Array.isArray(value));
pineafan02ba0232022-07-24 22:16:15 +010073 if (innerKey) {
Skyler Grey75ea9172022-08-06 10:22:23 +010074 await this.guilds.updateOne(
75 { id: guild },
76 {
77 $pull: { [key]: { [innerKey]: { $eq: value } } }
78 },
79 { upsert: true }
80 );
pineafan0bc04162022-07-25 17:22:26 +010081 } else if (Array.isArray(value)) {
Skyler Grey75ea9172022-08-06 10:22:23 +010082 await this.guilds.updateOne(
83 { id: guild },
84 {
85 $pullAll: { [key]: value }
86 },
87 { upsert: true }
88 );
pineafan6702cef2022-06-13 17:52:37 +010089 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +010090 await this.guilds.updateOne(
91 { id: guild },
92 {
93 $pullAll: { [key]: [value] }
94 },
95 { upsert: true }
96 );
pineafan6702cef2022-06-13 17:52:37 +010097 }
pineafan6fb3e072022-05-20 19:27:23 +010098 }
pineafane23c4ec2022-07-27 21:56:27 +010099
100 async delete(guild: string) {
101 await this.guilds.deleteOne({ id: guild });
102 }
pineafan6fb3e072022-05-20 19:27:23 +0100103}
104
pineafan4edb7762022-06-26 19:21:04 +0100105export class History {
106 histories: Collection<HistorySchema>;
pineafan4edb7762022-06-26 19:21:04 +0100107
pineafan3a02ea32022-08-11 21:35:04 +0100108 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100109 this.histories = database.collection<HistorySchema>("history");
pineafan4edb7762022-06-26 19:21:04 +0100110 }
111
Skyler Grey75ea9172022-08-06 10:22:23 +0100112 async create(
113 type: string,
114 guild: string,
115 user: Discord.User,
116 moderator: Discord.User | null,
117 reason: string | null,
pineafan3a02ea32022-08-11 21:35:04 +0100118 before?: string | null,
119 after?: string | null,
120 amount?: string | null
Skyler Grey75ea9172022-08-06 10:22:23 +0100121 ) {
pineafan4edb7762022-06-26 19:21:04 +0100122 await this.histories.insertOne({
123 type: type,
124 guild: guild,
125 user: user.id,
pineafan3a02ea32022-08-11 21:35:04 +0100126 moderator: moderator ? moderator.id : null,
pineafan4edb7762022-06-26 19:21:04 +0100127 reason: reason,
128 occurredAt: new Date(),
pineafan3a02ea32022-08-11 21:35:04 +0100129 before: before ?? null,
130 after: after ?? null,
131 amount: amount ?? null
pineafan4edb7762022-06-26 19:21:04 +0100132 });
133 }
134
135 async read(guild: string, user: string, year: number) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100136 const entry = (await this.histories
137 .find({
138 guild: guild,
139 user: user,
140 occurredAt: {
141 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
142 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
143 }
144 })
145 .toArray()) as HistorySchema[];
pineafan4edb7762022-06-26 19:21:04 +0100146 return entry;
147 }
pineafane23c4ec2022-07-27 21:56:27 +0100148
149 async delete(guild: string) {
150 await this.histories.deleteMany({ guild: guild });
151 }
pineafan4edb7762022-06-26 19:21:04 +0100152}
153
154export class ModNotes {
155 modNotes: Collection<ModNoteSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100156
pineafan3a02ea32022-08-11 21:35:04 +0100157 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100158 this.modNotes = database.collection<ModNoteSchema>("modNotes");
pineafan4edb7762022-06-26 19:21:04 +0100159 }
160
161 async create(guild: string, user: string, note: string | null) {
Skyler Grey11236ba2022-08-08 21:13:33 +0100162 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100163 }
164
165 async read(guild: string, user: string) {
pineafan63fc5e22022-08-04 22:04:10 +0100166 const entry = await this.modNotes.findOne({ guild: guild, user: user });
pineafan4edb7762022-06-26 19:21:04 +0100167 return entry?.note ?? null;
168 }
169}
170
pineafan73a7c4a2022-07-24 10:38:04 +0100171export class Premium {
172 premium: Collection<PremiumSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100173
pineafan3a02ea32022-08-11 21:35:04 +0100174 constructor() {
pineafan73a7c4a2022-07-24 10:38:04 +0100175 this.premium = database.collection<PremiumSchema>("premium");
pineafan4edb7762022-06-26 19:21:04 +0100176 }
177
pineafan73a7c4a2022-07-24 10:38:04 +0100178 async hasPremium(guild: string) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100179 const entry = await this.premium.findOne({
180 appliesTo: { $in: [guild] }
181 });
pineafane23c4ec2022-07-27 21:56:27 +0100182 return entry !== null;
pineafan4edb7762022-06-26 19:21:04 +0100183 }
184}
185
pineafan6fb3e072022-05-20 19:27:23 +0100186export interface GuildConfig {
Skyler Grey75ea9172022-08-06 10:22:23 +0100187 id: string;
188 version: number;
PineaFan100df682023-01-02 13:26:08 +0000189 singleEventNotifications: Record<string, boolean>;
pineafan6fb3e072022-05-20 19:27:23 +0100190 filters: {
191 images: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100192 NSFW: boolean;
193 size: boolean;
194 };
195 malware: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100196 wordFilter: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100197 enabled: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100198 words: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100199 strict: string[];
200 loose: string[];
201 };
pineafan6fb3e072022-05-20 19:27:23 +0100202 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100203 users: string[];
204 roles: string[];
205 channels: string[];
206 };
207 };
pineafan6fb3e072022-05-20 19:27:23 +0100208 invite: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100209 enabled: boolean;
210 channels: string[];
211 };
pineafan6fb3e072022-05-20 19:27:23 +0100212 pings: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100213 mass: number;
214 everyone: boolean;
215 roles: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100216 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100217 roles: string[];
218 rolesToMention: string[];
219 users: string[];
220 channels: string[];
221 };
222 };
223 };
pineafan6fb3e072022-05-20 19:27:23 +0100224 welcome: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100225 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100226 role: string | null;
227 ping: string | null;
228 channel: string | null;
229 message: string | null;
230 };
231 stats: Record<string, { name: string; enabled: boolean }>;
pineafan6fb3e072022-05-20 19:27:23 +0100232 logging: {
233 logs: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100234 enabled: boolean;
235 channel: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100236 toLog: string;
Skyler Grey75ea9172022-08-06 10:22:23 +0100237 };
pineafan6fb3e072022-05-20 19:27:23 +0100238 staff: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100239 channel: string | null;
240 };
pineafan73a7c4a2022-07-24 10:38:04 +0100241 attachments: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 channel: string | null;
243 saved: Record<string, string>;
244 };
245 };
pineafan6fb3e072022-05-20 19:27:23 +0100246 verify: {
PineaFandf4996f2023-01-01 14:20:06 +0000247 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100248 role: string | null;
249 };
pineafan6fb3e072022-05-20 19:27:23 +0100250 tickets: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100251 enabled: boolean;
252 category: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100253 types: string;
254 customTypes: string[] | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100255 useCustom: boolean;
256 supportRole: string | null;
257 maxTickets: number;
258 };
pineafan6fb3e072022-05-20 19:27:23 +0100259 moderation: {
260 mute: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100261 timeout: boolean;
262 role: string | null;
263 text: string | null;
264 link: string | null;
265 };
pineafan6fb3e072022-05-20 19:27:23 +0100266 kick: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100267 text: string | null;
268 link: string | null;
269 };
pineafan6fb3e072022-05-20 19:27:23 +0100270 ban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100271 text: string | null;
272 link: string | null;
273 };
pineafan6fb3e072022-05-20 19:27:23 +0100274 softban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100275 text: string | null;
276 link: string | null;
277 };
pineafan6fb3e072022-05-20 19:27:23 +0100278 warn: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100279 text: string | null;
280 link: string | null;
281 };
pineafan6fb3e072022-05-20 19:27:23 +0100282 role: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100283 role: string | null;
284 };
285 };
pineafan6fb3e072022-05-20 19:27:23 +0100286 tracks: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100287 name: string;
288 retainPrevious: boolean;
289 nullable: boolean;
290 track: string[];
291 manageableBy: string[];
292 }[];
pineafan6fb3e072022-05-20 19:27:23 +0100293 roleMenu: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100294 enabled: boolean;
295 allowWebUI: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100296 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100297 name: string;
298 description: string;
299 min: number;
300 max: number;
pineafan6fb3e072022-05-20 19:27:23 +0100301 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100302 name: string;
303 description: string | null;
304 role: string;
305 }[];
306 }[];
307 };
308 tags: Record<string, string>;
pineafan63fc5e22022-08-04 22:04:10 +0100309}
pineafan4edb7762022-06-26 19:21:04 +0100310
311export interface HistorySchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100312 type: string;
313 guild: string;
314 user: string;
315 moderator: string | null;
pineafan3a02ea32022-08-11 21:35:04 +0100316 reason: string | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100317 occurredAt: Date;
318 before: string | null;
319 after: string | null;
320 amount: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100321}
322
323export interface ModNoteSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100324 guild: string;
325 user: string;
pineafan3a02ea32022-08-11 21:35:04 +0100326 note: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100327}
328
pineafan73a7c4a2022-07-24 10:38:04 +0100329export interface PremiumSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100330 user: string;
331 level: number;
332 expires: Date;
333 appliesTo: string[];
334}