blob: 66d7e678ccf4286434932966e2524b1ec332493d [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
pineafan6702cef2022-06-13 17:52:37 +010043 async write(guild: string, set: object = {}, unset: string[] = []) {
44 let uo = {}
45 for (let key of unset) {
46 uo[key] = "";
47 }
48 await this.guilds.updateOne({ id: guild }, {
49 $unset: uo,
50 $set: set
51 }, { upsert: true });
52 }
53
54 async append(guild: string, key: string, value: any) {
55 if (Array.isArray(value)) {
56 await this.guilds.updateOne({ id: guild }, {
57 $addToSet: { [key]: { $each: value } }
58 }, { upsert: true });
59 } else {
60 await this.guilds.updateOne({ id: guild }, {
61 $addToSet: { [key]: value }
62 }, { upsert: true });
63 }
64 }
65
66 async remove(guild: string, key: string, value: any) {
67 if (Array.isArray(value)) {
68 await this.guilds.updateOne({ id: guild }, {
69 $pullAll: { [key]: value }
70 }, { upsert: true });
71 } else {
72 await this.guilds.updateOne({ id: guild }, {
73 $pullAll: { [key]: [value] }
74 }, { upsert: true });
75 }
pineafan6fb3e072022-05-20 19:27:23 +010076 }
77}
78
pineafan4edb7762022-06-26 19:21:04 +010079
80export class History {
81 histories: Collection<HistorySchema>;
82 defaultData: GuildConfig;
83
84 async setup() {
85 this.histories = database.collection<HistorySchema>("history");
86 return this;
87 }
88
89 async create(type: string, guild: string, user: Discord.User, moderator: Discord.User | null, reason: string | null, before?: null, after?: null, amount?: null) {
90 await this.histories.insertOne({
91 type: type,
92 guild: guild,
93 user: user.id,
94 moderator: moderator.id,
95 reason: reason,
96 occurredAt: new Date(),
97 before: before,
98 after: after,
99 amount: amount
100 });
101 }
102
103 async read(guild: string, user: string, year: number) {
104 let entry = (await this.histories.find({
105 guild: guild,
106 user: user,
107 occurredAt: {
108 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
109 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
110 }
111 }).toArray()) as HistorySchema[];
112 return entry;
113 }
114}
115
116export class ModNotes {
117 modNotes: Collection<ModNoteSchema>;
118 defaultData: GuildConfig;
119
120 async setup() {
121 this.modNotes = database.collection<ModNoteSchema>("modNotes");
122 return this;
123 }
124
125 async create(guild: string, user: string, note: string | null) {
126 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note }}, { upsert: true });
127 }
128
129 async read(guild: string, user: string) {
130 let entry = await this.modNotes.findOne({ guild: guild, user: user });
131 return entry?.note ?? null;
132 }
133}
134
135export class EventSchedulerDatabase {
136 events: Collection<EventSchedulerSchema>;
137 defaultData: GuildConfig;
138
139 async setup() {
140 this.events = database.collection<EventSchedulerSchema>("eventScheduler");
141 return this;
142 }
143
144 async create(timestamp: Date, data: object) {
145 await this.events.insertOne({ timestamp: timestamp, data: data});
146 }
147
148 async getNext() {
149 let entry = await this.events.findOne({ timestamp: { $lte: new Date() }});
150 return entry;
151 }
152
153 async remove(timestamp: Date, data: object) {
154 await this.events.deleteOne({ timestamp: timestamp, data: data});
155 }
156}
157
pineafan6fb3e072022-05-20 19:27:23 +0100158export interface GuildConfig {
159 id: string,
160 version: number,
161 singleEventNotifications: {
162 statsChannelDeleted: boolean
163 }
164 filters: {
165 images: {
166 NSFW: boolean,
167 size: boolean
168 },
169 malware: boolean,
170 wordFilter: {
171 enabled: boolean,
172 words: {
173 strict: string[],
174 loose: string[]
175 },
176 allowed: {
177 users: string[],
178 roles: string[],
179 channels: string[]
180 }
181 },
182 invite: {
183 enabled: boolean,
184 allowed: {
185 users: string[],
186 channels: string[],
187 roles: string[]
188 }
189 },
190 pings: {
191 mass: number,
192 everyone: boolean,
193 roles: boolean,
194 allowed: {
195 roles: string[],
196 rolesToMention: string[],
197 users: string[],
198 channels: string[]
199 }
200 }
201 }
202 welcome: {
203 enabled: boolean,
204 verificationRequired: {
205 message: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100206 role: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100207 },
pineafan6702cef2022-06-13 17:52:37 +0100208 welcomeRole: string | null,
209 channel: string | null,
210 message: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100211 }
212 stats: {
213 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100214 channel: string | null,
215 text: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100216 }[]
217 logging: {
218 logs: {
219 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100220 channel: string | null,
221 toLog: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100222 },
223 staff: {
pineafan6702cef2022-06-13 17:52:37 +0100224 channel: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100225 }
226 }
227 verify: {
228 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100229 role: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100230 }
231 tickets: {
232 enabled: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100233 category: string | null,
234 types: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100235 customTypes: string[],
pineafan6702cef2022-06-13 17:52:37 +0100236 useCustom: boolean,
237 supportRole: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100238 maxTickets: number
239 }
240 moderation: {
241 mute: {
242 timeout: boolean,
pineafan6702cef2022-06-13 17:52:37 +0100243 role: string | null,
244 text: string | null,
245 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100246 },
247 kick: {
pineafan6702cef2022-06-13 17:52:37 +0100248 text: string | null,
249 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100250 },
251 ban: {
pineafan6702cef2022-06-13 17:52:37 +0100252 text: string | null,
253 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100254 },
255 softban: {
pineafan6702cef2022-06-13 17:52:37 +0100256 text: string | null,
257 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100258 },
259 warn: {
pineafan6702cef2022-06-13 17:52:37 +0100260 text: string | null,
261 link: string | null
pineafan6fb3e072022-05-20 19:27:23 +0100262 },
263 role: {
pineafan6702cef2022-06-13 17:52:37 +0100264 role: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100265 }
266 }
267 tracks: {
268 name: string,
269 retainPrevious: boolean,
270 nullable: boolean,
271 track: string[],
272 manageableBy: string[]
273 }[]
274 roleMenu: {
275 enabled: boolean,
276 allowWebUI: boolean,
277 options: {
278 name: string,
279 description: string,
280 min: number,
281 max: number,
282 options: {
283 name: string,
pineafan4edb7762022-06-26 19:21:04 +0100284 description: string | null,
pineafan6fb3e072022-05-20 19:27:23 +0100285 role: string
286 }[]
287 }[]
288 }
289 tags: {}
pineafan4edb7762022-06-26 19:21:04 +0100290};
291
292export interface HistorySchema {
293 type: string,
294 guild: string,
295 user: string,
296 moderator: string | null,
297 reason: string,
298 occurredAt: Date,
299 before: string | null,
300 after: string | null,
301 amount: string | null
302}
303
304export interface ModNoteSchema {
305 guild: string,
306 user: string,
307 note: string
308}
309
310export interface EventSchedulerSchema {
311 timestamp: Date,
312 data: object
313}