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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 370 by rakin, Mon Jul 29 17:29:50 2024 UTC revision 393 by rakin, Mon Jul 29 17:29:59 2024 UTC
# Line 1  Line 1 
1    /**
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";  import { dot, object } from "dot-object";
21  import { body } from "express-validator";  import { body } from "express-validator";
22  import { z as zod, ZodSchema } from "zod";  import { z as zod } from "zod";
23  import KeyValuePair from "../../types/KeyValuePair";  import KeyValuePair from "../../types/KeyValuePair";
24  import Controller from "../Controller";  import Controller from "../Controller";
25  import RequireAuth from "../middleware/RequireAuth";  import RequireAuth from "../middleware/RequireAuth";
# Line 21  export default class ConfigController ex Line 40  export default class ConfigController ex
40          };          };
41      }      }
42    
43      private zodSchema() {      private zodSchema(id: string) {
44          const snowflake = zod.string().regex(/\d+/, { message: "The given value is not a Snowflake" });          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({          const schema = zod.object({
48              "prefix": zod.string().optional(),              "prefix": zod.string().optional(),
# Line 39  export default class ConfigController ex Line 59  export default class ConfigController ex
59              "role_commands": zod.record(              "role_commands": zod.record(
60                  snowflake,                  snowflake,
61                  zod.array(zod.string().min(1))                  zod.array(zod.string().min(1))
62              ).optional(),              ).optional().default({}),
63              "autoclear": zod.object({              "autoclear": zod.object({
64                  "enabled": zod.boolean().optional(),                  "enabled": zod.boolean().optional(),
65                  "channels": zod.array(snowflake).optional()                  "channels": zod.array(snowflake).optional().default(config.autoclear.channels)
66              }).optional(),              }).optional(),
67              "verification": zod.object({              "verification": zod.object({
68                  "enabled": zod.boolean().optional(),                  "enabled": zod.boolean().optional(),
# Line 66  export default class ConfigController ex Line 86  export default class ConfigController ex
86              }).optional(),              }).optional(),
87              "autorole": zod.object({              "autorole": zod.object({
88                  "enabled": zod.boolean().optional(),                  "enabled": zod.boolean().optional(),
89                  "roles": zod.array(snowflake).optional()                  "roles": zod.array(snowflake).optional().default(config.autorole.roles)
90              }).optional(),              }).optional(),
91              "spam_filter": zod.object({              "spam_filter": zod.object({
92                  "enabled": zod.boolean().optional(),                  "enabled": zod.boolean().optional(),
93                  "limit": zod.number().int().optional(),                  "limit": zod.number().int().optional(),
94                  "time": zod.number().optional(),                  "time": zod.number().optional(),
95                  "diff": zod.number().optional(),                  "diff": zod.number().optional(),
96                  "exclude": zod.array(snowflake).optional(),                  "exclude": zod.array(snowflake).optional().default(config.spam_filter.exclude),
97                  "samelimit": zod.number().int().optional(),                  "samelimit": zod.number().int().optional(),
98                  "unmute_in": zod.number().optional()                  "unmute_in": zod.number().optional()
99              }).optional(),              }).optional(),
# Line 81  export default class ConfigController ex Line 101  export default class ConfigController ex
101                  "enabled": zod.boolean().optional(),                  "enabled": zod.boolean().optional(),
102                  "max_joins": zod.number().int().optional(),                  "max_joins": zod.number().int().optional(),
103                  "time": zod.number().optional(),                  "time": zod.number().optional(),
104                  "channels": zod.array(snowflake).optional(),                  "channels": zod.array(snowflake).optional().default(config.raid.channels),
105                  "exclude": zod.boolean().optional()                  "exclude": zod.boolean().optional()
106              }).optional(),              }).optional(),
107              "global_commands": zod.array(zod.string()).optional(),              "global_commands": zod.array(zod.string()).optional().default(config.global_commands),
108              "filters": zod.object({              "filters": zod.object({
109                  "ignore_staff": zod.boolean().optional(),                  "ignore_staff": zod.boolean().optional(),
110                  "chars_repeated": zod.number().int().optional(),                  "chars_repeated": zod.number().int().optional(),
111                  "words_repeated": zod.number().int().optional(),                  "words_repeated": zod.number().int().optional(),
112                  "words": zod.array(zod.string()).optional(),                  "words": zod.array(zod.string()).optional().default(config.filters.words),
113                  "tokens": zod.array(zod.string()).optional(),                  "tokens": zod.array(zod.string()).optional().default(config.filters.tokens),
114                  "invite_message": zod.string().optional(),                  "invite_message": zod.string().optional(),
115                  "words_excluded": zod.array(snowflake).optional(),                  "words_excluded": zod.array(snowflake).optional().default(config.filters.words_excluded),
116                  "domain_excluded": zod.array(snowflake).optional(),                  "domain_excluded": zod.array(snowflake).optional().default(config.filters.domain_excluded),
117                  "invite_excluded": zod.array(snowflake).optional(),                  "invite_excluded": zod.array(snowflake).optional().default(config.filters.invite_excluded),
118                  "words_enabled": zod.boolean().optional(),                  "words_enabled": zod.boolean().optional(),
119                  "invite_enabled": zod.boolean().optional(),                  "invite_enabled": zod.boolean().optional(),
120                  "domain_enabled": zod.boolean().optional(),                  "domain_enabled": zod.boolean().optional(),
121                  "regex": zod.boolean().optional(),                  "regex": zod.boolean().optional(),
122                  "file_mimes_excluded": zod.array(zod.string()).optional(),                  "file_mimes_excluded": zod.array(zod.string()).optional().default(config.filters.file_mimes_excluded),
123                  "file_types_excluded": zod.array(zod.string()).optional(),                  "file_types_excluded": zod.array(zod.string()).optional().default(config.filters.file_types_excluded),
124                  "domains": zod.array(zod.string()).optional(),                  "domains": zod.array(zod.string()).optional().default(config.filters.domains),
125                  "regex_patterns": zod.array(zod.string()).optional(),                  "regex_patterns": zod.array(zod.string()).optional().default(config.filters.regex_patterns),
126                  "rickrolls_enabled": zod.boolean().optional(),                  "rickrolls_enabled": zod.boolean().optional(),
127                  "pings": zod.number().int().optional()                  "pings": zod.number().int().optional()
128              }).optional()              }).optional()
# Line 127  export default class ConfigController ex Line 147  export default class ConfigController ex
147    
148      public async update(request: Request) {      public async update(request: Request) {
149          const { id } = request.params;          const { id } = request.params;
150          const { config } = request.body;          const { config: origconfig } = request.body;
151    
152          console.log(config);                  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 {          try {
192              const currentConfigDotObject = dot(this.client.config.props[id]);              const currentConfigDotObject = dot(this.client.config.props[id]);
193              let newConfigDotObject = {...currentConfigDotObject};              let newConfigDotObject = {...currentConfigDotObject};
194            
195              console.log("Input: ", config);              console.log("Current config: ", currentConfigDotObject);
196    
197              const result = this.zodSchema().safeParse(object({...config}));              const result = this.zodSchema(id).safeParse(object({...origconfig}));
198    
199              if (!result?.success) {              if (!result?.success) {
200                  return this.response({ error: "The data schema does not match.", error_type: 'validation', errors: result.error.errors }, 422);                  return this.response({ error: "The data schema does not match.", error_type: 'validation', errors: result.error.errors }, 422);
201              }              }
202    
203              for (const configKey in config) {              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);                  const regexMatched = /(.+)\[\d+\]/g.test(configKey);
210                                    
211                  if (typeof currentConfigDotObject[configKey] === 'undefined' && !regexMatched) {                  if (typeof currentConfigDotObject[configKey] === 'undefined' && !regexMatched) {
212                      return this.response({ error: `The key '${configKey}' is not allowed` }, 422);                      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]) {                  if (!regexMatched && config[configKey] !== null && config[configKey] !== null && typeof config[configKey] !== typeof currentConfigDotObject[configKey]) {
222                      console.log(typeof config[configKey], typeof currentConfigDotObject[configKey]);                          console.log(typeof config[configKey], typeof currentConfigDotObject[configKey]);    
223                                            
224                      if (typeof currentConfigDotObject[configKey] === 'number' && typeof config[configKey] === 'string') {                      if (typeof currentConfigDotObject[configKey] === 'number' && typeof config[configKey] === 'string') {
225                          const int = parseInt(config[configKey]);                          const int = parseInt(config[configKey]!.toString());
226    
227                          if (int !== NaN) {                          if (int !== NaN) {
228                              newConfigDotObject[configKey] = int;                              newConfigDotObject[configKey] = int;
# Line 169  export default class ConfigController ex Line 237  export default class ConfigController ex
237                  console.log("Updating: ", configKey, config[configKey], newConfigDotObject[configKey]);                  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 }, object({...newConfigDotObject}), object({...config}));              newConfigDotObject = merge.withOptions({ mergeArrays: false }, newObj, configObj);
247              console.log("Output: ", newConfigDotObject);              console.log("Output: ", newConfigDotObject);
248    
249              this.client.config.props[id] = newConfigDotObject;              this.client.config.props[id] = newConfigDotObject;

Legend:
Removed from v.370  
changed lines
  Added in v.393

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26