blob: 2f04198e0e00b34e8ddec8d66f3d283228b88842 [file] [log] [blame]
pineafan4edb7762022-06-26 19:21:04 +01001import Discord from 'discord.js';
2import { Collection, MongoClient } from 'mongodb';
pineafan6702cef2022-06-13 17:52:37 +01003import structuredClone from '@ungap/structured-clone';
pineafan4edb7762022-06-26 19:21:04 +01004import config from '../config/main.json' assert {type: 'json'};
5
6
7const mongoClient = new MongoClient(config.mongoUrl);
8await mongoClient.connect()
9const database = mongoClient.db("Nucleus");
pineafan6fb3e072022-05-20 19:27:23 +010010
11
12export const Entry = data => {
13 data = data ?? {};
pineafan6702cef2022-06-13 17:52:37 +010014 data.getKey = key => data[key]
pineafan6fb3e072022-05-20 19:27:23 +010015 return {
16 get(target, prop, receiver) {
17 let dataToReturn = data[prop]
18 if (dataToReturn === null ) return Reflect.get(target, prop, receiver);
19 if (typeof dataToReturn === "object" && !Array.isArray(dataToReturn)) dataToReturn = new Proxy(
20 Reflect.get(target, prop, receiver),
21 Entry(dataToReturn),
22 )
23 return dataToReturn ?? Reflect.get(target, prop, receiver);
24 }
25 }
26}
27
28
pineafan4edb7762022-06-26 19:21:04 +010029export class Guilds {
pineafan6fb3e072022-05-20 19:27:23 +010030 guilds: Collection<GuildConfig>;
31 defaultData: GuildConfig;
pineafan4edb7762022-06-26 19:21:04 +010032 async setup() {
33 this.guilds = database.collection<GuildConfig>("guilds");
pineafan6fb3e072022-05-20 19:27:23 +010034 this.defaultData = (await import("../config/default.json", { assert: { type: "json" }})).default as unknown as GuildConfig;
35 return this;
36 }
37
38 async read(guild: string) {
39 let entry = await this.guilds.findOne({ id: guild });
pineafan6702cef2022-06-13 17:52:37 +010040 return new Proxy(structuredClone(this.defaultData), Entry(entry)) as unknown as GuildConfig
pineafan6fb3e072022-05-20 19:27:23 +010041 }
42
pineafane23c4ec2022-07-27 21:56:27 +010043 async write(guild: string, set: object | null, unset: string[] | string = []) {
pineafan6702cef2022-06-13 17:52:37 +010044 let uo = {}
pineafane23c4ec2022-07-27 21:56:27 +010045 if (!Array.isArray(unset)) unset = [unset]
pineafan6702cef2022-06-13 17:52:37 +010046 for (let key of unset) {
pineafan0bc04162022-07-25 17:22:26 +010047 uo[key] = null;
pineafan6702cef2022-06-13 17:52:37 +010048 }
pineafane23c4ec2022-07-27 21:56:27 +010049 let out = {$set: {}, $unset: {}}
pineafan0bc04162022-07-25 17:22:26 +010050 if (set) out["$set"] = set;
51 if (unset.length) out["$unset"] = uo;
pineafane23c4ec2022-07-27 21:56:27 +010052 console.log(out)
pineafan0bc04162022-07-25 17:22:26 +010053 await this.guilds.updateOne({ id: guild }, out, { upsert: true });
pineafan6702cef2022-06-13 17:52:37 +010054 }
55
56 async append(guild: string, key: string, value: any) {
57 if (Array.isArray(value)) {
58 await this.guilds.updateOne({ id: guild }, {
59 $addToSet: { [key]: { $each: value } }
60 }, { upsert: true });
61 } else {
62 await this.guilds.updateOne({ id: guild }, {
63 $addToSet: { [key]: value }
64 }, { upsert: true });
65 }
66 }
67
pineafan0bc04162022-07-25 17:22:26 +010068 async remove(guild: string, key: string, value: any, innerKey?: string | null) {
69 console.log(Array.isArray(value))
pineafan02ba0232022-07-24 22:16:15 +010070 if (innerKey) {
71 await this.guilds.updateOne({ id: guild }, {
72 $pull: { [key]: { [innerKey]: { $eq: value } } }
73 }, { upsert: true });
pineafan0bc04162022-07-25 17:22:26 +010074 } else if (Array.isArray(value)) {
pineafan6702cef2022-06-13 17:52:37 +010075 await this.guilds.updateOne({ id: guild }, {
76 $pullAll: { [key]: value }
77 }, { upsert: true });
78 } else {
79 await this.guilds.updateOne({ id: guild }, {
80 $pullAll: { [key]: [value] }
81 }, { upsert: true });
82 }
pineafan6fb3e072022-05-20 19:27:23 +010083 }
pineafane23c4ec2022-07-27 21:56:27 +010084
85 async delete(guild: string) {
86 await this.guilds.deleteOne({ id: guild });
87 }
pineafan6fb3e072022-05-20 19:27:23 +010088}
89
pineafan4edb7762022-06-26 19:21:04 +010090
91export class History {
92 histories: Collection<HistorySchema>;
93 defaultData: GuildConfig;
94
95 async setup() {
96 this.histories = database.collection<HistorySchema>("history");
97 return this;
98 }
99
100 async create(type: string, guild: string, user: Discord.User, moderator: Discord.User | null, reason: string | null, before?: null, after?: null, amount?: null) {
101 await this.histories.insertOne({
102 type: type,
103 guild: guild,
104 user: user.id,
105 moderator: moderator.id,
106 reason: reason,
107 occurredAt: new Date(),
108 before: before,
109 after: after,
110 amount: amount
111 });
112 }
113
114 async read(guild: string, user: string, year: number) {
115 let entry = (await this.histories.find({
116 guild: guild,
117 user: user,
118 occurredAt: {
119 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
120 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
121 }
122 }).toArray()) as HistorySchema[];
123 return entry;
124 }
pineafane23c4ec2022-07-27 21:56:27 +0100125
126 async delete(guild: string) {
127 await this.histories.deleteMany({ guild: guild });
128 }
pineafan4edb7762022-06-26 19:21:04 +0100129}
130
131export class ModNotes {
132 modNotes: Collection<ModNoteSchema>;
133 defaultData: GuildConfig;
134
135 async setup() {
136 this.modNotes = database.collection<ModNoteSchema>("modNotes");
137 return this;
138 }
139
140 async create(guild: string, user: string, note: string | null) {
141 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note }}, { upsert: true });
142 }
143
144 async read(guild: string, user: string) {
145 let entry = await this.modNotes.findOne({ guild: guild, user: user });
146 return entry?.note ?? null;
147 }
148}
149
pineafan73a7c4a2022-07-24 10:38:04 +0100150export class Premium {
151 premium: Collection<PremiumSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100152
153 async setup() {
pineafan73a7c4a2022-07-24 10:38:04 +0100154 this.premium = database.collection<PremiumSchema>("premium");
pineafan4edb7762022-06-26 19:21:04 +0100155 return this;
156 }
157
pineafan73a7c4a2022-07-24 10:38:04 +0100158 async hasPremium(guild: string) {
159 let entry = await this.premium.findOne({ appliesTo: { $in: [guild] } });
pineafane23c4ec2022-07-27 21:56:27 +0100160 return entry !== null;
pineafan4edb7762022-06-26 19:21:04 +0100161 }
162}
163
pineafan6fb3e072022-05-20 19:27:23 +0100164export interface GuildConfig {
165 id: string,
166 version: number,
167 singleEventNotifications: {
168 statsChannelDeleted: boolean
169 }
170 filters: {
171 images: {
172 NSFW: boolean,
173 size: boolean
174 },
175 malware: boolean,
176 wordFilter: {
177 enabled: boolean,
178 words: {
179 strict: string[],
180 loose: string[]
181 },
182 allowed: {
183 users: string[],
184 roles: string[],
185 channels: string[]
186 }
187 },
188 invite: {
189 enabled: boolean,
190 allowed: {
191 users: string[],
192 channels: string[],
193 roles: string[]
194 }
195 },
196 pings: {
197 mass: number,
198 everyone: boolean,
199 roles: boolean,
200 allowed: {
201 roles: string[],
202 rolesToMention: string[],
203 users: string[],
204 channels: string[]
205 }
206 }
207 }
208 welcome: {
209 enabled: boolean,
210 verificationRequired: {
211 message: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100212 role: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100213 },
pineafan6702cef2022-06-13 17:52:37 +0100214 welcomeRole: string | null,
215 channel: string | null,
216 message: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100217 }
pineafan02ba0232022-07-24 22:16:15 +0100218 stats: {}
pineafan6fb3e072022-05-20 19:27:23 +0100219 logging: {
220 logs: {
221 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100222 channel: string | null,
223 toLog: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100224 },
225 staff: {
pineafan6702cef2022-06-13 17:52:37 +0100226 channel: string | null,
pineafan73a7c4a2022-07-24 10:38:04 +0100227 },
228 attachments: {
229 channel: string | null,
230 saved: {} // {channelID+messageID: log url (string)}
pineafan6fb3e072022-05-20 19:27:23 +0100231 }
232 }
233 verify: {
234 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100235 role: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100236 }
237 tickets: {
238 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100239 category: string | null,
240 types: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100241 customTypes: string[],
pineafan6702cef2022-06-13 17:52:37 +0100242 useCustom: boolean,
243 supportRole: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100244 maxTickets: number
245 }
246 moderation: {
247 mute: {
248 timeout: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100249 role: string | null,
250 text: string | null,
251 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100252 },
253 kick: {
pineafan6702cef2022-06-13 17:52:37 +0100254 text: string | null,
255 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100256 },
257 ban: {
pineafan6702cef2022-06-13 17:52:37 +0100258 text: string | null,
259 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100260 },
261 softban: {
pineafan6702cef2022-06-13 17:52:37 +0100262 text: string | null,
263 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100264 },
265 warn: {
pineafan6702cef2022-06-13 17:52:37 +0100266 text: string | null,
267 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100268 },
269 role: {
pineafan6702cef2022-06-13 17:52:37 +0100270 role: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100271 }
272 }
273 tracks: {
274 name: string,
275 retainPrevious: boolean,
276 nullable: boolean,
277 track: string[],
278 manageableBy: string[]
279 }[]
280 roleMenu: {
281 enabled: boolean,
282 allowWebUI: boolean,
283 options: {
284 name: string,
285 description: string,
286 min: number,
287 max: number,
288 options: {
289 name: string,
pineafan4edb7762022-06-26 19:21:04 +0100290 description: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100291 role: string
292 }[]
293 }[]
294 }
295 tags: {}
pineafan4edb7762022-06-26 19:21:04 +0100296};
297
298export interface HistorySchema {
299 type: string,
300 guild: string,
301 user: string,
302 moderator: string | null,
303 reason: string,
304 occurredAt: Date,
305 before: string | null,
306 after: string | null,
307 amount: string | null
308}
309
310export interface ModNoteSchema {
311 guild: string,
312 user: string,
313 note: string
314}
315
pineafan73a7c4a2022-07-24 10:38:04 +0100316export interface PremiumSchema {
317 user: string,
318 level: number,
319 expires: Date,
320 appliesTo: string[]
pineafan4edb7762022-06-26 19:21:04 +0100321}