/[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 415 by rakin, Mon Jul 29 17:30:07 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";
 import { z as zod, ZodSchema } from "zod";  
22  import KeyValuePair from "../../types/KeyValuePair";  import KeyValuePair from "../../types/KeyValuePair";
23  import Controller from "../Controller";  import Controller from "../Controller";
24  import RequireAuth from "../middleware/RequireAuth";  import RequireAuth from "../middleware/RequireAuth";
# Line 21  export default class ConfigController ex Line 39  export default class ConfigController ex
39          };          };
40      }      }
41    
42      private zodSchema() {      private zodSchema(id: string) {
43          const snowflake = zod.string().regex(/\d+/, { message: "The given value is not a Snowflake" });          const config = this.client.config.props[id];
44            return this.client.config.schema(config);
         const schema = zod.object({  
             "prefix": zod.string().optional(),  
             "debug": zod.boolean().optional(),  
             "mute_role": snowflake.optional(),  
             "gen_role": snowflake.optional(),  
             "logging_channel": snowflake.optional(),  
             "logging_channel_join_leave": snowflake.optional(),  
             "mod_role": snowflake.optional(),  
             "announcement_channel": snowflake.optional(),  
             "admin": snowflake.optional(),  
             "lockall": zod.array(zod.string()).optional(),  
             "warn_notallowed": zod.boolean().optional(),  
             "role_commands": zod.record(  
                 snowflake,  
                 zod.array(zod.string().min(1))  
             ).optional(),  
             "autoclear": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "channels": zod.array(snowflake).optional()  
             }).optional(),  
             "verification": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "role": snowflake.optional()  
             }).optional(),  
             "welcomer": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "channel": snowflake.optional(),  
                 "message": zod.string().min(1).or(zod.null()).optional(),  
                 "randomize": zod.boolean().optional()  
             }).optional(),  
             "cooldown": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "global": zod.any().optional(),  
                 "cmds": zod.object({}).optional()  
             }).optional(),  
             "starboard": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "reactions": zod.number().int().optional(),  
                 "channel": snowflake.optional()  
             }).optional(),  
             "autorole": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "roles": zod.array(snowflake).optional()  
             }).optional(),  
             "spam_filter": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "limit": zod.number().int().optional(),  
                 "time": zod.number().optional(),  
                 "diff": zod.number().optional(),  
                 "exclude": zod.array(snowflake).optional(),  
                 "samelimit": zod.number().int().optional(),  
                 "unmute_in": zod.number().optional()  
             }).optional(),  
             "raid": zod.object({  
                 "enabled": zod.boolean().optional(),  
                 "max_joins": zod.number().int().optional(),  
                 "time": zod.number().optional(),  
                 "channels": zod.array(snowflake).optional(),  
                 "exclude": zod.boolean().optional()  
             }).optional(),  
             "global_commands": zod.array(zod.string()).optional(),  
             "filters": zod.object({  
                 "ignore_staff": zod.boolean().optional(),  
                 "chars_repeated": zod.number().int().optional(),  
                 "words_repeated": zod.number().int().optional(),  
                 "words": zod.array(zod.string()).optional(),  
                 "tokens": zod.array(zod.string()).optional(),  
                 "invite_message": zod.string().optional(),  
                 "words_excluded": zod.array(snowflake).optional(),  
                 "domain_excluded": zod.array(snowflake).optional(),  
                 "invite_excluded": zod.array(snowflake).optional(),  
                 "words_enabled": zod.boolean().optional(),  
                 "invite_enabled": zod.boolean().optional(),  
                 "domain_enabled": zod.boolean().optional(),  
                 "regex": zod.boolean().optional(),  
                 "file_mimes_excluded": zod.array(zod.string()).optional(),  
                 "file_types_excluded": zod.array(zod.string()).optional(),  
                 "domains": zod.array(zod.string()).optional(),  
                 "regex_patterns": zod.array(zod.string()).optional(),  
                 "rickrolls_enabled": zod.boolean().optional(),  
                 "pings": zod.number().int().optional()  
             }).optional()  
         });  
   
         return schema;  
45      }      }
46    
47      public async index(request: Request) {      public async index(request: Request) {
# Line 127  export default class ConfigController ex Line 60  export default class ConfigController ex
60    
61      public async update(request: Request) {      public async update(request: Request) {
62          const { id } = request.params;          const { id } = request.params;
63          const { config } = request.body;          const { config: origconfig } = request.body;
64    
65          console.log(config);                  console.log(origconfig);        
66    
67            try {
68                const currentConfigDotObject = this.client.config.props[id];
69        
70                console.log("Current config: ", currentConfigDotObject);
71    
72                const result = this.zodSchema(id).safeParse(object(origconfig));
73    
74                if (!result?.success) {
75                    return this.response({ error: "The data schema does not match.", error_type: 'validation', errors: result.error.errors }, 422);
76                }
77    
78                const config = result.data;
79                const newConfig = merge.withOptions({ mergeArrays: false }, currentConfigDotObject, config);
80                const result2 = this.zodSchema(id).safeParse(newConfig);
81    
82                if (!result2?.success) {
83                    console.log(result2.error.errors);                
84                    return this.response({ error: 'Internal Server Error (500)', error_type: 'internal' }, 500);
85                }
86    
87                console.log('Final', newConfig);
88                this.client.config.props[id] = newConfig;
89                this.client.config.write();      
90                return { message: "Configuration updated", previous: dot(currentConfigDotObject), new: dot(this.client.config.props[id]) };    
91            }
92            catch (e) {
93                console.log(e);
94                return this.response({ error: 'Internal Server Error', error_type: 'internal' }, 500);
95            }
96        }
97    
98        public async update2(request: Request) {
99            const { id } = request.params;
100            const { config: origconfig } = request.body;
101    
102            console.log(origconfig);        
103    
104          try {          try {
105              const currentConfigDotObject = dot(this.client.config.props[id]);              const currentConfigDotObject = dot(this.client.config.props[id]);
106              let newConfigDotObject = {...currentConfigDotObject};              let newConfigDotObject = {...currentConfigDotObject};
107            
108              console.log("Input: ", config);              console.log("Current config: ", currentConfigDotObject);
109    
110              const result = this.zodSchema().safeParse(object({...config}));              const result = this.zodSchema(id).safeParse(object({...origconfig}));
111    
112              if (!result?.success) {              if (!result?.success) {
113                  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);
114              }              }
115    
116              for (const configKey in config) {              const config = result.data;
117    
118                console.log(config);            
119    
120                for (const key in config) {
121                    const configKey = key as keyof typeof config;
122                  const regexMatched = /(.+)\[\d+\]/g.test(configKey);                  const regexMatched = /(.+)\[\d+\]/g.test(configKey);
123                                    
124                  if (typeof currentConfigDotObject[configKey] === 'undefined' && !regexMatched) {                  if (typeof currentConfigDotObject[configKey] === 'undefined' && !regexMatched) {
125                      return this.response({ error: `The key '${configKey}' is not allowed` }, 422);                      console.log(configKey, config[configKey]);
126                        
127                        if (currentConfigDotObject[configKey] instanceof Array && config[configKey] instanceof Array) {
128                            console.log('Array');                        
129                        }
130                        else
131                            return this.response({ error: `The key '${configKey}' is not allowed` }, 422);
132                  }                  }
133    
134                  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]) {
135                      console.log(typeof config[configKey], typeof currentConfigDotObject[configKey]);                          console.log(typeof config[configKey], typeof currentConfigDotObject[configKey]);    
136                                            
137                      if (typeof currentConfigDotObject[configKey] === 'number' && typeof config[configKey] === 'string') {                      if (typeof currentConfigDotObject[configKey] === 'number' && typeof config[configKey] === 'string') {
138                          const int = parseInt(config[configKey]);                          const int = parseInt(config[configKey]!.toString());
139    
140                          if (int !== NaN) {                          if (int !== NaN) {
141                              newConfigDotObject[configKey] = int;                              newConfigDotObject[configKey] = int;
# Line 169  export default class ConfigController ex Line 150  export default class ConfigController ex
150                  console.log("Updating: ", configKey, config[configKey], newConfigDotObject[configKey]);                  console.log("Updating: ", configKey, config[configKey], newConfigDotObject[configKey]);
151              }              }
152    
153                const newObj = object({...newConfigDotObject});
154                const configObj = object({...config});
155    
156                // console.log("Newobj", newObj);
157                // console.log("Configobj", configObj);
158    
159              newConfigDotObject = merge.withOptions({ mergeArrays: false }, object({...newConfigDotObject}), object({...config}));              newConfigDotObject = merge.withOptions({ mergeArrays: false }, newObj, configObj);
160              console.log("Output: ", newConfigDotObject);              console.log("Output: ", newConfigDotObject);
161    
162              this.client.config.props[id] = newConfigDotObject;              this.client.config.props[id] = newConfigDotObject;

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26