/[sudobot]/branches/3.x/src/api/controllers/ConfigController.ts
ViewVC logotype

Annotation of /branches/3.x/src/api/controllers/ConfigController.ts

Parent Directory Parent Directory | Revision Log Revision Log


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26