blob: 7e80f966b2ab49fad82d2cf7950e25cd16004c44 [file] [log] [blame]
TheCodedProfcfe8e9a2023-02-26 17:28:09 -05001import type { ButtonStyle, GuildMember } from "discord.js";
pineafan63fc5e22022-08-04 22:04:10 +01002import type Discord from "discord.js";
3import { Collection, MongoClient } from "mongodb";
pineafana2e39c72023-02-21 18:37:32 +00004import config from "../config/main.js";
TheCodedProf633866f2023-02-03 17:06:00 -05005import client from "../utils/client.js";
pineafan4edb7762022-06-26 19:21:04 +01006
7const mongoClient = new MongoClient(config.mongoUrl);
pineafan63fc5e22022-08-04 22:04:10 +01008await mongoClient.connect();
pineafan4edb7762022-06-26 19:21:04 +01009const database = mongoClient.db("Nucleus");
pineafan6fb3e072022-05-20 19:27:23 +010010
pineafan4edb7762022-06-26 19:21:04 +010011export class Guilds {
pineafan6fb3e072022-05-20 19:27:23 +010012 guilds: Collection<GuildConfig>;
pineafan63fc5e22022-08-04 22:04:10 +010013 defaultData: GuildConfig | null;
14
15 constructor() {
pineafan4edb7762022-06-26 19:21:04 +010016 this.guilds = database.collection<GuildConfig>("guilds");
pineafan63fc5e22022-08-04 22:04:10 +010017 this.defaultData = null;
pineafan6fb3e072022-05-20 19:27:23 +010018 }
19
Skyler Greyad002172022-08-16 18:48:26 +010020 async setup(): Promise<Guilds> {
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 ) {
pineafan02ba0232022-07-24 22:16:15 +010072 if (innerKey) {
Skyler Grey75ea9172022-08-06 10:22:23 +010073 await this.guilds.updateOne(
74 { id: guild },
75 {
76 $pull: { [key]: { [innerKey]: { $eq: value } } }
77 },
78 { upsert: true }
79 );
pineafan0bc04162022-07-25 17:22:26 +010080 } else if (Array.isArray(value)) {
Skyler Grey75ea9172022-08-06 10:22:23 +010081 await this.guilds.updateOne(
82 { id: guild },
83 {
84 $pullAll: { [key]: value }
85 },
86 { upsert: true }
87 );
pineafan6702cef2022-06-13 17:52:37 +010088 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +010089 await this.guilds.updateOne(
90 { id: guild },
91 {
92 $pullAll: { [key]: [value] }
93 },
94 { upsert: true }
95 );
pineafan6702cef2022-06-13 17:52:37 +010096 }
pineafan6fb3e072022-05-20 19:27:23 +010097 }
pineafane23c4ec2022-07-27 21:56:27 +010098
99 async delete(guild: string) {
100 await this.guilds.deleteOne({ id: guild });
101 }
pineafan6fb3e072022-05-20 19:27:23 +0100102}
103
TheCodedProfcfe8e9a2023-02-26 17:28:09 -0500104interface TranscriptEmbed {
105 title?: string;
106 description?: string;
107 fields?: {
108 name: string;
109 value: string;
110 inline: boolean;
111 }[];
112 footer?: {
113 text: string;
114 iconURL?: string;
115 };
116}
117
118interface TranscriptComponent {
119 type: number;
120 style?: ButtonStyle;
121 label?: string;
122 description?: string;
123 placeholder?: string;
124 emojiURL?: string;
125}
126
127interface TranscriptAuthor {
128 username: string;
129 discriminator: number;
130 nickname?: string;
131 id: string;
132 iconURL?: string;
133 topRole: {
134 color: number;
135 badgeURL?: string;
136 }
137}
138
139interface TranscriptAttachment {
140 url: string;
141 filename: string;
142 size: number;
143 log?: string;
144}
145
146interface TranscriptMessage {
147 id: string;
148 author: TranscriptAuthor;
149 content?: string;
150 embeds?: TranscriptEmbed[];
151 components?: TranscriptComponent[][];
152 editedTimestamp?: number;
153 createdTimestamp: number;
154 flags?: string[];
155 attachments?: TranscriptAttachment[];
156 stickerURLs?: string[];
157 referencedMessage?: string | [string, string, string];
158}
159
160interface TranscriptSchema {
161 code: string;
162 for: TranscriptAuthor;
163 type: "ticket" | "purge"
164 guild: string;
165 channel: string;
166 messages: TranscriptMessage[];
167 createdTimestamp: number;
168 createdBy: TranscriptAuthor;
169}
170
171export class Transcript {
172 transcripts: Collection<TranscriptSchema>;
173
174 constructor() {
175 this.transcripts = database.collection<TranscriptSchema>("transcripts");
176 }
177
178 async create(transcript: Omit<TranscriptSchema, "code">) {
179 let code;
180 do {
181 code = Math.random().toString(36).substring(2, 16) + Math.random().toString(36).substring(2, 16);
182 } while (await this.transcripts.findOne({ code: code }));
183
184 const doc = await this.transcripts.insertOne(Object.assign(transcript, { code: code }));
185 if(doc.acknowledged) return code;
186 else return null;
187 }
188
189 async read(code: string) {
190 return await this.transcripts.findOne({ code: code });
191 }
192}
193
pineafan4edb7762022-06-26 19:21:04 +0100194export class History {
195 histories: Collection<HistorySchema>;
pineafan4edb7762022-06-26 19:21:04 +0100196
pineafan3a02ea32022-08-11 21:35:04 +0100197 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100198 this.histories = database.collection<HistorySchema>("history");
pineafan4edb7762022-06-26 19:21:04 +0100199 }
200
Skyler Grey75ea9172022-08-06 10:22:23 +0100201 async create(
202 type: string,
203 guild: string,
204 user: Discord.User,
205 moderator: Discord.User | null,
206 reason: string | null,
pineafan3a02ea32022-08-11 21:35:04 +0100207 before?: string | null,
208 after?: string | null,
209 amount?: string | null
Skyler Grey75ea9172022-08-06 10:22:23 +0100210 ) {
pineafan4edb7762022-06-26 19:21:04 +0100211 await this.histories.insertOne({
212 type: type,
213 guild: guild,
214 user: user.id,
pineafan3a02ea32022-08-11 21:35:04 +0100215 moderator: moderator ? moderator.id : null,
pineafan4edb7762022-06-26 19:21:04 +0100216 reason: reason,
217 occurredAt: new Date(),
pineafan3a02ea32022-08-11 21:35:04 +0100218 before: before ?? null,
219 after: after ?? null,
220 amount: amount ?? null
pineafan4edb7762022-06-26 19:21:04 +0100221 });
222 }
223
224 async read(guild: string, user: string, year: number) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100225 const entry = (await this.histories
226 .find({
227 guild: guild,
228 user: user,
229 occurredAt: {
230 $gte: new Date(year - 1, 11, 31, 23, 59, 59),
231 $lt: new Date(year + 1, 0, 1, 0, 0, 0)
232 }
233 })
234 .toArray()) as HistorySchema[];
pineafan4edb7762022-06-26 19:21:04 +0100235 return entry;
236 }
pineafane23c4ec2022-07-27 21:56:27 +0100237
238 async delete(guild: string) {
239 await this.histories.deleteMany({ guild: guild });
240 }
pineafan4edb7762022-06-26 19:21:04 +0100241}
242
TheCodedProfb5e9d552023-01-29 15:43:26 -0500243interface ScanCacheSchema {
244 addedAt: Date;
245 hash: string;
246 data: boolean;
247 tags: string[];
248}
249
250export class ScanCache {
251 scanCache: Collection<ScanCacheSchema>;
252
253 constructor() {
254 this.scanCache = database.collection<ScanCacheSchema>("scanCache");
255 }
256
257 async read(hash: string) {
258 return await this.scanCache.findOne({ hash: hash });
259 }
260
261 async write(hash: string, data: boolean, tags?: string[]) {
TheCodedProf1f675042023-02-16 17:01:29 -0500262 await this.scanCache.insertOne({ hash: hash, data: data, tags: tags ?? [], addedAt: new Date() });
TheCodedProfb5e9d552023-01-29 15:43:26 -0500263 }
264
265 async cleanup() {
266 await this.scanCache.deleteMany({ addedAt: { $lt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 31)) }, hash: { $not$text: "http"} });
267 }
268}
269
PineaFan538d3752023-01-12 21:48:23 +0000270export class PerformanceTest {
271 performanceData: Collection<PerformanceDataSchema>;
272
273 constructor() {
274 this.performanceData = database.collection<PerformanceDataSchema>("performance");
275 }
276
277 async record(data: PerformanceDataSchema) {
278 data.timestamp = new Date();
279 await this.performanceData.insertOne(data);
280 }
281 async read() {
282 return await this.performanceData.find({}).toArray();
283 }
284}
285
286export interface PerformanceDataSchema {
287 timestamp?: Date;
288 discord: number;
289 databaseRead: number;
290 resources: {
291 cpu: number;
292 memory: number;
293 temperature: number;
294 }
295}
296
pineafan4edb7762022-06-26 19:21:04 +0100297export class ModNotes {
298 modNotes: Collection<ModNoteSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100299
pineafan3a02ea32022-08-11 21:35:04 +0100300 constructor() {
pineafan4edb7762022-06-26 19:21:04 +0100301 this.modNotes = database.collection<ModNoteSchema>("modNotes");
pineafan4edb7762022-06-26 19:21:04 +0100302 }
303
304 async create(guild: string, user: string, note: string | null) {
Skyler Grey11236ba2022-08-08 21:13:33 +0100305 await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100306 }
307
308 async read(guild: string, user: string) {
pineafan63fc5e22022-08-04 22:04:10 +0100309 const entry = await this.modNotes.findOne({ guild: guild, user: user });
pineafan4edb7762022-06-26 19:21:04 +0100310 return entry?.note ?? null;
311 }
TheCodedProf267563a2023-01-21 17:00:57 -0500312
313 async delete(guild: string) {
314 await this.modNotes.deleteMany({ guild: guild });
315 }
pineafan4edb7762022-06-26 19:21:04 +0100316}
317
pineafan73a7c4a2022-07-24 10:38:04 +0100318export class Premium {
319 premium: Collection<PremiumSchema>;
pineafan4edb7762022-06-26 19:21:04 +0100320
pineafan3a02ea32022-08-11 21:35:04 +0100321 constructor() {
pineafan73a7c4a2022-07-24 10:38:04 +0100322 this.premium = database.collection<PremiumSchema>("premium");
pineafan4edb7762022-06-26 19:21:04 +0100323 }
324
TheCodedProf633866f2023-02-03 17:06:00 -0500325 async updateUser(user: string, level: number) {
326 if(!(await this.userExists(user))) await this.createUser(user, level);
327 await this.premium.updateOne({ user: user }, { $set: { level: level } }, { upsert: true });
328 }
329
330 async userExists(user: string): Promise<boolean> {
331 const entry = await this.premium.findOne({ user: user });
332 return entry ? true : false;
333 }
334
335 async createUser(user: string, level: number) {
336 await this.premium.insertOne({ user: user, appliesTo: [], level: level });
337 }
338
TheCodedProfaa3fe992023-02-25 21:53:09 -0500339 async hasPremium(guild: string): Promise<[boolean, string, number, boolean] | null> {
TheCodedProf94ff6de2023-02-22 17:47:26 -0500340 const entries = await this.premium.find({}).toArray();
341 const members = await (await client.guilds.fetch(guild)).members.fetch()
342 for(const {user} of entries) {
343 const member = members.get(user);
TheCodedProfaa3fe992023-02-25 21:53:09 -0500344 if(member) { //TODO: Notify user if they've given premium to a server that has since gotten premium via a mod.
TheCodedProf94ff6de2023-02-22 17:47:26 -0500345 const modPerms = //TODO: Create list in config for perms
346 member.permissions.has("Administrator") ||
347 member.permissions.has("ManageChannels") ||
348 member.permissions.has("ManageRoles") ||
349 member.permissions.has("ManageEmojisAndStickers") ||
350 member.permissions.has("ManageWebhooks") ||
351 member.permissions.has("ManageGuild") ||
352 member.permissions.has("KickMembers") ||
353 member.permissions.has("BanMembers") ||
354 member.permissions.has("ManageEvents") ||
355 member.permissions.has("ManageMessages") ||
356 member.permissions.has("ManageThreads")
357 const entry = entries.find(e => e.user === member.id);
TheCodedProfaa3fe992023-02-25 21:53:09 -0500358 if(entry && (entry.level === 3) && modPerms) return [true, member.id, entry.level, true];
TheCodedProf94ff6de2023-02-22 17:47:26 -0500359 }
360 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100361 const entry = await this.premium.findOne({
TheCodedProf94ff6de2023-02-22 17:47:26 -0500362 appliesTo: {
363 $elemMatch: {
364 $eq: guild
365 }
366 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100367 });
TheCodedProfaa3fe992023-02-25 21:53:09 -0500368 return entry ? [true, entry.user, entry.level, false] : null;
TheCodedProf267563a2023-01-21 17:00:57 -0500369 }
370
TheCodedProf633866f2023-02-03 17:06:00 -0500371 async fetchUser(user: string): Promise<PremiumSchema | null> {
TheCodedProf267563a2023-01-21 17:00:57 -0500372 const entry = await this.premium.findOne({ user: user });
TheCodedProf633866f2023-02-03 17:06:00 -0500373 if (!entry) return null;
374 return entry;
375 }
376
TheCodedProf94ff6de2023-02-22 17:47:26 -0500377 async checkAllPremium(member?: GuildMember) {
TheCodedProf633866f2023-02-03 17:06:00 -0500378 const entries = await this.premium.find({}).toArray();
TheCodedProf94ff6de2023-02-22 17:47:26 -0500379 if(member) {
380 const entry = entries.find(e => e.user === member.id);
381 if(entry) {
382 const expiresAt = entry.expiresAt;
383 if(expiresAt) expiresAt < Date.now() ? await this.premium.deleteOne({user: member.id}) : null;
384 }
385 const roles = member.roles;
386 let level = 0;
387 if (roles.cache.has("1066468879309750313")) {
TheCodedProf633866f2023-02-03 17:06:00 -0500388 level = 99;
TheCodedProf94ff6de2023-02-22 17:47:26 -0500389 } else if (roles.cache.has("1066465491713003520")) {
TheCodedProf633866f2023-02-03 17:06:00 -0500390 level = 1;
TheCodedProf94ff6de2023-02-22 17:47:26 -0500391 } else if (roles.cache.has("1066439526496604194")) {
TheCodedProf633866f2023-02-03 17:06:00 -0500392 level = 2;
TheCodedProf94ff6de2023-02-22 17:47:26 -0500393 } else if (roles.cache.has("1066464134322978912")) {
TheCodedProf633866f2023-02-03 17:06:00 -0500394 level = 3;
395 }
TheCodedProf94ff6de2023-02-22 17:47:26 -0500396 await this.updateUser(member.id, level);
TheCodedProf633866f2023-02-03 17:06:00 -0500397 if (level > 0) {
TheCodedProf94ff6de2023-02-22 17:47:26 -0500398 await this.premium.updateOne({ user: member.id }, {$unset: { expiresAt: ""}})
TheCodedProf633866f2023-02-03 17:06:00 -0500399 } else {
TheCodedProf94ff6de2023-02-22 17:47:26 -0500400 await this.premium.updateOne({ user: member.id }, {$set: { expiresAt: (Date.now() + (1000*60*60*24*3)) }})
401 }
402 } else {
403 const members = await (await client.guilds.fetch('684492926528651336')).members.fetch();
404 for(const {roles, id} of members.values()) {
405 const entry = entries.find(e => e.user === id);
406 if(entry) {
407 const expiresAt = entry.expiresAt;
408 if(expiresAt) expiresAt < Date.now() ? await this.premium.deleteOne({user: id}) : null;
409 }
410 let level: number = 0;
411 if (roles.cache.has("1066468879309750313")) {
412 level = 99;
413 } else if (roles.cache.has("1066465491713003520")) {
414 level = 1;
415 } else if (roles.cache.has("1066439526496604194")) {
416 level = 2;
417 } else if (roles.cache.has("1066464134322978912")) {
418 level = 3;
419 }
420 await this.updateUser(id, level);
421 if (level > 0) {
422 await this.premium.updateOne({ user: id }, {$unset: { expiresAt: ""}})
423 } else {
424 await this.premium.updateOne({ user: id }, {$set: { expiresAt: (Date.now() + (1000*60*60*24*3)) }})
425 }
TheCodedProf633866f2023-02-03 17:06:00 -0500426 }
427 }
TheCodedProf267563a2023-01-21 17:00:57 -0500428 }
429
TheCodedProffc420b72023-01-24 17:14:38 -0500430 addPremium(user: string, guild: string) {
TheCodedProf267563a2023-01-21 17:00:57 -0500431 return this.premium.updateOne({ user: user }, { $addToSet: { appliesTo: guild } }, { upsert: true });
pineafan4edb7762022-06-26 19:21:04 +0100432 }
TheCodedProffc420b72023-01-24 17:14:38 -0500433
434 removePremium(user: string, guild: string) {
435 return this.premium.updateOne({ user: user }, { $pull: { appliesTo: guild } });
436 }
pineafan4edb7762022-06-26 19:21:04 +0100437}
438
pineafan6fb3e072022-05-20 19:27:23 +0100439export interface GuildConfig {
Skyler Grey75ea9172022-08-06 10:22:23 +0100440 id: string;
441 version: number;
PineaFan100df682023-01-02 13:26:08 +0000442 singleEventNotifications: Record<string, boolean>;
pineafan6fb3e072022-05-20 19:27:23 +0100443 filters: {
444 images: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100445 NSFW: boolean;
446 size: boolean;
447 };
448 malware: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100449 wordFilter: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100450 enabled: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100451 words: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100452 strict: string[];
453 loose: string[];
454 };
pineafan6fb3e072022-05-20 19:27:23 +0100455 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100456 users: string[];
457 roles: string[];
458 channels: string[];
459 };
460 };
pineafan6fb3e072022-05-20 19:27:23 +0100461 invite: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100462 enabled: boolean;
PineaFan538d3752023-01-12 21:48:23 +0000463 allowed: {
464 channels: string[];
465 roles: string[];
466 users: string[];
467 };
Skyler Grey75ea9172022-08-06 10:22:23 +0100468 };
pineafan6fb3e072022-05-20 19:27:23 +0100469 pings: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100470 mass: number;
471 everyone: boolean;
472 roles: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100473 allowed: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100474 roles: string[];
475 rolesToMention: string[];
476 users: string[];
477 channels: string[];
478 };
479 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500480 clean: {
481 channels: string[];
482 allowed: {
483 user: string[];
484 roles: string[];
485 }
486 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100487 };
TheCodedProfbaee2c12023-02-18 16:11:06 -0500488 autoPublish: {
489 enabled: boolean;
490 channels: string[];
491 }
pineafan6fb3e072022-05-20 19:27:23 +0100492 welcome: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100493 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100494 role: string | null;
495 ping: string | null;
496 channel: string | null;
497 message: string | null;
498 };
499 stats: Record<string, { name: string; enabled: boolean }>;
pineafan6fb3e072022-05-20 19:27:23 +0100500 logging: {
501 logs: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100502 enabled: boolean;
503 channel: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100504 toLog: string;
Skyler Grey75ea9172022-08-06 10:22:23 +0100505 };
pineafan6fb3e072022-05-20 19:27:23 +0100506 staff: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100507 channel: string | null;
508 };
pineafan73a7c4a2022-07-24 10:38:04 +0100509 attachments: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100510 channel: string | null;
511 saved: Record<string, string>;
512 };
513 };
pineafan6fb3e072022-05-20 19:27:23 +0100514 verify: {
PineaFandf4996f2023-01-01 14:20:06 +0000515 enabled: boolean;
Skyler Grey75ea9172022-08-06 10:22:23 +0100516 role: string | null;
517 };
pineafan6fb3e072022-05-20 19:27:23 +0100518 tickets: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100519 enabled: boolean;
520 category: string | null;
Skyler Greyad002172022-08-16 18:48:26 +0100521 types: string;
522 customTypes: string[] | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100523 useCustom: boolean;
524 supportRole: string | null;
525 maxTickets: number;
526 };
pineafan6fb3e072022-05-20 19:27:23 +0100527 moderation: {
528 mute: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100529 timeout: boolean;
530 role: string | null;
531 text: string | null;
532 link: string | null;
533 };
pineafan6fb3e072022-05-20 19:27:23 +0100534 kick: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100535 text: string | null;
536 link: string | null;
537 };
pineafan6fb3e072022-05-20 19:27:23 +0100538 ban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100539 text: string | null;
540 link: string | null;
541 };
pineafan6fb3e072022-05-20 19:27:23 +0100542 softban: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100543 text: string | null;
544 link: string | null;
545 };
pineafan6fb3e072022-05-20 19:27:23 +0100546 warn: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100547 text: string | null;
548 link: string | null;
549 };
pineafan6fb3e072022-05-20 19:27:23 +0100550 role: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100551 role: string | null;
TheCodedProfd9636e82023-01-17 22:13:06 -0500552 text: null;
553 link: null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100554 };
PineaFane6ba7882023-01-18 20:41:16 +0000555 nick: {
556 text: string | null;
557 link: string | null;
558 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100559 };
pineafan6fb3e072022-05-20 19:27:23 +0100560 tracks: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100561 name: string;
562 retainPrevious: boolean;
563 nullable: boolean;
564 track: string[];
565 manageableBy: string[];
566 }[];
pineafan6fb3e072022-05-20 19:27:23 +0100567 roleMenu: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100568 enabled: boolean;
569 allowWebUI: boolean;
pineafan6fb3e072022-05-20 19:27:23 +0100570 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100571 name: string;
572 description: string;
573 min: number;
574 max: number;
pineafan6fb3e072022-05-20 19:27:23 +0100575 options: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100576 name: string;
577 description: string | null;
578 role: string;
579 }[];
580 }[];
581 };
582 tags: Record<string, string>;
pineafan63fc5e22022-08-04 22:04:10 +0100583}
pineafan4edb7762022-06-26 19:21:04 +0100584
585export interface HistorySchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100586 type: string;
587 guild: string;
588 user: string;
589 moderator: string | null;
pineafan3a02ea32022-08-11 21:35:04 +0100590 reason: string | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100591 occurredAt: Date;
592 before: string | null;
593 after: string | null;
594 amount: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100595}
596
597export interface ModNoteSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100598 guild: string;
599 user: string;
pineafan3a02ea32022-08-11 21:35:04 +0100600 note: string | null;
pineafan4edb7762022-06-26 19:21:04 +0100601}
602
pineafan73a7c4a2022-07-24 10:38:04 +0100603export interface PremiumSchema {
Skyler Grey75ea9172022-08-06 10:22:23 +0100604 user: string;
605 level: number;
Skyler Grey75ea9172022-08-06 10:22:23 +0100606 appliesTo: string[];
TheCodedProf633866f2023-02-03 17:06:00 -0500607 expiresAt?: number;
Skyler Grey75ea9172022-08-06 10:22:23 +0100608}