/[sudobot]/trunk/src/api/controllers/ConfigController.ts
ViewVC logotype

Annotation of /trunk/src/api/controllers/ConfigController.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 389 - (hide annotations)
Mon Jul 29 17:29:55 2024 UTC (8 months, 3 weeks ago) by rakin
File MIME type: application/typescript
File size: 10990 byte(s)
style: fix with eslint
1 rakin 352 import { dot, object } from "dot-object";
2     import { body } from "express-validator";
3 rakin 389 import { z as zod } from "zod";
4 rakin 352 import KeyValuePair from "../../types/KeyValuePair";
5 rakin 326 import Controller from "../Controller";
6 rakin 349 import RequireAuth from "../middleware/RequireAuth";
7 rakin 353 import ValidatorError from "../middleware/ValidatorError";
8 rakin 349 import Request from "../Request";
9 rakin 370 import merge from 'ts-deepmerge';
10 rakin 326
11     export default class ConfigController extends Controller {
12 rakin 349 globalMiddleware(): Function[] {
13 rakin 353 return [RequireAuth, ValidatorError];
14 rakin 349 }
15    
16 rakin 352 middleware(): KeyValuePair<Function[]> {
17     return {
18     update: [
19     body(["config"]).isObject()
20     ]
21     };
22     }
23    
24 rakin 379 private zodSchema(id: string) {
25 rakin 370 const snowflake = zod.string().regex(/\d+/, { message: "The given value is not a Snowflake" });
26 rakin 379 const config = this.client.config.props[id];
27 rakin 370
28     const schema = zod.object({
29     "prefix": zod.string().optional(),
30     "debug": zod.boolean().optional(),
31     "mute_role": snowflake.optional(),
32     "gen_role": snowflake.optional(),
33     "logging_channel": snowflake.optional(),
34     "logging_channel_join_leave": snowflake.optional(),
35     "mod_role": snowflake.optional(),
36     "announcement_channel": snowflake.optional(),
37     "admin": snowflake.optional(),
38     "lockall": zod.array(zod.string()).optional(),
39     "warn_notallowed": zod.boolean().optional(),
40     "role_commands": zod.record(
41     snowflake,
42     zod.array(zod.string().min(1))
43 rakin 379 ).optional().default({}),
44 rakin 370 "autoclear": zod.object({
45     "enabled": zod.boolean().optional(),
46 rakin 379 "channels": zod.array(snowflake).optional().default(config.autoclear.channels)
47 rakin 370 }).optional(),
48     "verification": zod.object({
49     "enabled": zod.boolean().optional(),
50     "role": snowflake.optional()
51     }).optional(),
52     "welcomer": zod.object({
53     "enabled": zod.boolean().optional(),
54     "channel": snowflake.optional(),
55     "message": zod.string().min(1).or(zod.null()).optional(),
56     "randomize": zod.boolean().optional()
57     }).optional(),
58     "cooldown": zod.object({
59     "enabled": zod.boolean().optional(),
60     "global": zod.any().optional(),
61     "cmds": zod.object({}).optional()
62     }).optional(),
63     "starboard": zod.object({
64     "enabled": zod.boolean().optional(),
65     "reactions": zod.number().int().optional(),
66     "channel": snowflake.optional()
67     }).optional(),
68     "autorole": zod.object({
69     "enabled": zod.boolean().optional(),
70 rakin 379 "roles": zod.array(snowflake).optional().default(config.autorole.roles)
71 rakin 370 }).optional(),
72     "spam_filter": zod.object({
73     "enabled": zod.boolean().optional(),
74     "limit": zod.number().int().optional(),
75     "time": zod.number().optional(),
76     "diff": zod.number().optional(),
77 rakin 379 "exclude": zod.array(snowflake).optional().default(config.spam_filter.exclude),
78 rakin 370 "samelimit": zod.number().int().optional(),
79     "unmute_in": zod.number().optional()
80     }).optional(),
81     "raid": zod.object({
82     "enabled": zod.boolean().optional(),
83     "max_joins": zod.number().int().optional(),
84     "time": zod.number().optional(),
85 rakin 379 "channels": zod.array(snowflake).optional().default(config.raid.channels),
86 rakin 370 "exclude": zod.boolean().optional()
87     }).optional(),
88 rakin 379 "global_commands": zod.array(zod.string()).optional().default(config.global_commands),
89 rakin 370 "filters": zod.object({
90     "ignore_staff": zod.boolean().optional(),
91     "chars_repeated": zod.number().int().optional(),
92     "words_repeated": zod.number().int().optional(),
93 rakin 379 "words": zod.array(zod.string()).optional().default(config.filters.words),
94     "tokens": zod.array(zod.string()).optional().default(config.filters.tokens),
95 rakin 370 "invite_message": zod.string().optional(),
96 rakin 379 "words_excluded": zod.array(snowflake).optional().default(config.filters.words_excluded),
97     "domain_excluded": zod.array(snowflake).optional().default(config.filters.domain_excluded),
98     "invite_excluded": zod.array(snowflake).optional().default(config.filters.invite_excluded),
99 rakin 370 "words_enabled": zod.boolean().optional(),
100     "invite_enabled": zod.boolean().optional(),
101     "domain_enabled": zod.boolean().optional(),
102     "regex": zod.boolean().optional(),
103 rakin 379 "file_mimes_excluded": zod.array(zod.string()).optional().default(config.filters.file_mimes_excluded),
104     "file_types_excluded": zod.array(zod.string()).optional().default(config.filters.file_types_excluded),
105     "domains": zod.array(zod.string()).optional().default(config.filters.domains),
106     "regex_patterns": zod.array(zod.string()).optional().default(config.filters.regex_patterns),
107 rakin 370 "rickrolls_enabled": zod.boolean().optional(),
108     "pings": zod.number().int().optional()
109     }).optional()
110     });
111    
112     return schema;
113     }
114    
115 rakin 326 public async index(request: Request) {
116 rakin 349 const { id } = request.params;
117    
118     if (!request.user?.guilds.includes(id)) {
119     return this.response({ error: "You don't have permission to access configuration of this guild." }, 403);
120     }
121    
122     if (id === "global" || !this.client.config.props[id]) {
123     return this.response({ error: "No configuration found for the given guild ID" }, 404);
124     }
125    
126     return this.client.config.props[id];
127 rakin 326 }
128    
129     public async update(request: Request) {
130 rakin 352 const { id } = request.params;
131 rakin 379 const { config: origconfig } = request.body;
132 rakin 368
133 rakin 379 console.log(origconfig);
134 rakin 368
135 rakin 370 try {
136 rakin 379 const currentConfigDotObject = this.client.config.props[id];
137    
138     console.log("Current config: ", currentConfigDotObject);
139    
140     const result = this.zodSchema(id).safeParse(object(origconfig));
141    
142     if (!result?.success) {
143     return this.response({ error: "The data schema does not match.", error_type: 'validation', errors: result.error.errors }, 422);
144     }
145    
146     const config = result.data;
147     const newConfig = merge.withOptions({ mergeArrays: false }, currentConfigDotObject, config);
148     const result2 = this.zodSchema(id).safeParse(newConfig);
149    
150     if (!result2?.success) {
151     console.log(result2.error.errors);
152     return this.response({ error: 'Internal Server Error (500)', error_type: 'internal' }, 500);
153     }
154    
155     console.log('Final', newConfig);
156     this.client.config.props[id] = newConfig;
157     this.client.config.write();
158     return { message: "Configuration updated", previous: dot(currentConfigDotObject), new: dot(this.client.config.props[id]) };
159     }
160     catch (e) {
161     console.log(e);
162     return this.response({ error: 'Internal Server Error', error_type: 'internal' }, 500);
163     }
164     }
165    
166     public async update2(request: Request) {
167     const { id } = request.params;
168     const { config: origconfig } = request.body;
169    
170     console.log(origconfig);
171    
172     try {
173 rakin 370 const currentConfigDotObject = dot(this.client.config.props[id]);
174     let newConfigDotObject = {...currentConfigDotObject};
175    
176 rakin 379 console.log("Current config: ", currentConfigDotObject);
177 rakin 352
178 rakin 379 const result = this.zodSchema(id).safeParse(object({...origconfig}));
179 rakin 370
180     if (!result?.success) {
181     return this.response({ error: "The data schema does not match.", error_type: 'validation', errors: result.error.errors }, 422);
182 rakin 352 }
183    
184 rakin 379 const config = result.data;
185    
186     console.log(config);
187    
188     for (const key in config) {
189     const configKey = key as keyof typeof config;
190 rakin 370 const regexMatched = /(.+)\[\d+\]/g.test(configKey);
191 rakin 368
192 rakin 370 if (typeof currentConfigDotObject[configKey] === 'undefined' && !regexMatched) {
193 rakin 379 console.log(configKey, config[configKey]);
194    
195     if (currentConfigDotObject[configKey] instanceof Array && config[configKey] instanceof Array) {
196     console.log('Array');
197     }
198     else
199     return this.response({ error: `The key '${configKey}' is not allowed` }, 422);
200 rakin 370 }
201 rakin 368
202 rakin 370 if (!regexMatched && config[configKey] !== null && config[configKey] !== null && typeof config[configKey] !== typeof currentConfigDotObject[configKey]) {
203     console.log(typeof config[configKey], typeof currentConfigDotObject[configKey]);
204    
205     if (typeof currentConfigDotObject[configKey] === 'number' && typeof config[configKey] === 'string') {
206 rakin 379 const int = parseInt(config[configKey]!.toString());
207 rakin 370
208     if (int !== NaN) {
209     newConfigDotObject[configKey] = int;
210     console.log("Updating: ", configKey, config[configKey], newConfigDotObject[configKey]);
211     continue;
212     }
213     }
214    
215     return this.response({ error: `The key '${configKey}' has incompatible value type '${config[configKey] === null ? 'null' : typeof config[configKey]}'` }, 422);
216 rakin 368 }
217 rakin 370
218     console.log("Updating: ", configKey, config[configKey], newConfigDotObject[configKey]);
219 rakin 352 }
220    
221 rakin 379 const newObj = object({...newConfigDotObject});
222     const configObj = object({...config});
223 rakin 352
224 rakin 379 // console.log("Newobj", newObj);
225     // console.log("Configobj", configObj);
226    
227     newConfigDotObject = merge.withOptions({ mergeArrays: false }, newObj, configObj);
228 rakin 370 console.log("Output: ", newConfigDotObject);
229 rakin 353
230 rakin 370 this.client.config.props[id] = newConfigDotObject;
231     this.client.config.write();
232 rakin 353
233 rakin 370 return { message: "Configuration updated", previous: currentConfigDotObject, new: dot(this.client.config.props[id]) };
234     }
235     catch (e) {
236     console.log(e);
237     return this.response({ error: 'Internal Server Error', error_type: 'internal' }, 500);
238     }
239 rakin 326 }
240     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26