blob: 8a5ca6f0e3e2f7253f5b327f3fcd7ab6a85919bd [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;
52 await this.guilds.updateOne({ id: guild }, out, { upsert: true });
pineafan6702cef2022-06-13 17:52:37 +010053 }
54
55 async append(guild: string, key: string, value: any) {
56 if (Array.isArray(value)) {
57 await this.guilds.updateOne({ id: guild }, {
58 $addToSet: { [key]: { $each: value } }
59 }, { upsert: true });
60 } else {
61 await this.guilds.updateOne({ id: guild }, {
62 $addToSet: { [key]: value }
63 }, { upsert: true });
64 }
65 }
66
pineafan0bc04162022-07-25 17:22:26 +010067 async remove(guild: string, key: string, value: any, innerKey?: string | null) {
68 console.log(Array.isArray(value))
pineafan02ba0232022-07-24 22:16:15 +010069 if (innerKey) {
70 await this.guilds.updateOne({ id: guild }, {
71 $pull: { [key]: { [innerKey]: { $eq: value } } }
72 }, { upsert: true });
pineafan0bc04162022-07-25 17:22:26 +010073 } else if (Array.isArray(value)) {
pineafan6702cef2022-06-13 17:52:37 +010074 await this.guilds.updateOne({ id: guild }, {
75 $pullAll: { [key]: value }
76 }, { upsert: true });
77 } else {
78 await this.guilds.updateOne({ id: guild }, {
79 $pullAll: { [key]: [value] }
80 }, { upsert: true });
81 }
pineafan6fb3e072022-05-20 19:27:23 +010082 }
pineafane23c4ec2022-07-27 21:56:27 +010083
84 async delete(guild: string) {
85 await this.guilds.deleteOne({ id: guild });
86 }
pineafan6fb3e072022-05-20 19:27:23 +010087}
88
pineafan4edb7762022-06-26 19:21:04 +010089
90export class History {
91 histories: Collection<HistorySchema>;
92 defaultData: GuildConfig;
93
94 async setup() {
95 this.histories = database.collection<HistorySchema>("history");
96 return this;
97 }
98
99 async create(type: string, guild: string, user: Discord.User, moderator: Discord.User | null, reason: string | null, before?: null, after?: null, amount?: null) {
100 await this.histories.insertOne({
101 type: type,
102 guild: guild,
103 user: user.id,
104 moderator: moderator.id,
105 reason: reason,
106 occurredAt: new Date(),
107 before: before,
108 after: after,
109 amount: amount
110 });
111 }
112
113 async read(guild: string, user: string, year: number) {
114 let entry = (await this.histories.find({
115 guild: guild,
116 user: user,
117 occurredAt: {
118 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
119 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
120 }
121 }).toArray()) as HistorySchema[];
122 return entry;
123 }
pineafane23c4ec2022-07-27 21:56:27 +0100124
125 async delete(guild: string) {
126 await this.histories.deleteMany({ guild: guild });
127 }
pineafan4edb7762022-06-26 19:21:04 +0100128}
129
130export class ModNotes {
131 modNotes: Collection<ModNoteSchema>;
132 defaultData: GuildConfig;
133
134 async setup() {
135 this.modNotes = database.collection<ModNoteSchema>("modNotes");
136 return this;
137 }
138
139 async create(guild: string, user: string, note: string | null) {
140 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note }}, { upsert: true });
141 }
142
143 async read(guild: string, user: string) {
144 let entry = await this.modNotes.findOne({ guild: guild, user: user });
145 return entry?.note ?? null;
146 }
147}
148
pineafan73a7c4a2022-07-24 10:38:04 +0100149export class Premium {
150 premium: Collection<PremiumSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100151
152 async setup() {
pineafan73a7c4a2022-07-24 10:38:04 +0100153 this.premium = database.collection<PremiumSchema>("premium");
pineafan4edb7762022-06-26 19:21:04 +0100154 return this;
155 }
156
pineafan73a7c4a2022-07-24 10:38:04 +0100157 async hasPremium(guild: string) {
158 let entry = await this.premium.findOne({ appliesTo: { $in: [guild] } });
pineafane23c4ec2022-07-27 21:56:27 +0100159 return entry !== null;
pineafan4edb7762022-06-26 19:21:04 +0100160 }
161}
162
pineafan6fb3e072022-05-20 19:27:23 +0100163export interface GuildConfig {
164 id: string,
165 version: number,
166 singleEventNotifications: {
167 statsChannelDeleted: boolean
168 }
169 filters: {
170 images: {
171 NSFW: boolean,
172 size: boolean
173 },
174 malware: boolean,
175 wordFilter: {
176 enabled: boolean,
177 words: {
178 strict: string[],
179 loose: string[]
180 },
181 allowed: {
182 users: string[],
183 roles: string[],
184 channels: string[]
185 }
186 },
187 invite: {
188 enabled: boolean,
189 allowed: {
190 users: string[],
191 channels: string[],
192 roles: string[]
193 }
194 },
195 pings: {
196 mass: number,
197 everyone: boolean,
198 roles: boolean,
199 allowed: {
200 roles: string[],
201 rolesToMention: string[],
202 users: string[],
203 channels: string[]
204 }
205 }
206 }
207 welcome: {
208 enabled: boolean,
209 verificationRequired: {
210 message: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100211 role: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100212 },
pineafan41d93562022-07-30 22:10:15 +0100213 role: string | null,
214 ping: string | null,
pineafan6702cef2022-06-13 17:52:37 +0100215 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}