#wip: Doing AnP Framwork Upgrade Scripts?

This commit is contained in:
KyMAN 2025-11-20 16:51:19 +01:00
parent f1338e0704
commit 15ba494ef8
63 changed files with 2578 additions and 177 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
*.[Ss]ecret.* *.[Ss]ecret.*
*.[Ss]ecrets.* *.[Ss]ecrets.*
__pycache__ __pycache__
.sass-cache

View File

@ -0,0 +1,3 @@
{
"espanol" : {}
}

View File

@ -0,0 +1,4 @@
[
"get:/ping ping@test",
"get:/ /Public"
]

View File

@ -0,0 +1,13 @@
{
"default_settings_files": ["/JSON/OpoTests.settings.json"],
"default_secrets_files": ["/JSON/OpoTests.secrets.json"],
"default_i18n_files": [
"/JSON/I18N/OpoTests.i18n.espanol.json",
"/JSON/I18N/OpoTests.i18n.galego.json",
"/JSON/I18N/OpoTests.i18n.english.json",
"/JSON/I18N/OpoTests.i18n.nihongo.json",
"/JSON/I18N/OpoTests.i18n.russkyi.json"
],
"default_language": "es",
"default_routes_files" : ["/JSON/OpoTests.routes.json"]
}

View File

@ -71,8 +71,12 @@ export const OpoTests = (function(){
/** @type {OpoTests} */ /** @type {OpoTests} */
const self = this; const self = this;
/** @type {Array.<Object.<string, any>>} */
this.database = []; this.database = [];
/** @type {Object.<string, string|Array.<string|number|Array.<any|null>>>} */
this.variables = {}; this.variables = {};
/** @type {Object.<string, string|Array.<string|number|Array.<any|null>>>} */
this.group_variables = {};
/** @type {SettingsManager} */ /** @type {SettingsManager} */
this.settings = new SettingsManager(self, inputs); this.settings = new SettingsManager(self, inputs);
@ -117,7 +121,7 @@ export const OpoTests = (function(){
}); });
}, next_callback); }, next_callback);
}, () => { }, () => {
console.log(["database", self.database, self.variables]); console.log(["database", self.database, self.variables, self.group_variables]);
self.main_form.build(); self.main_form.build();
}); });
}; };
@ -231,10 +235,11 @@ export const OpoTests = (function(){
* @returns {void} * @returns {void}
* @access private * @access private
*/ */
const add_to_variables = set => { const add_to_variables = (variables, set, group = null) => {
group && (variables = variables[group] || (variables[group] = {}));
Check.is_dictionary(set) && Check.is_dictionary(set) &&
Object.entries(set).forEach(([key, value]) => { Object.entries(set).forEach(([key, value]) => {
self.variables[key] = value; variables[key] = value;
}); });
}; };
@ -251,10 +256,15 @@ export const OpoTests = (function(){
try{ try{
self.database.push(...JSON.parse(responseText).map(item => { self.database.push(...JSON.parse(responseText).map(item => {
add_to_variables(item.variables); /** @type {string} */
const group = item.group || Utils.to_snake_case(item.origin + "_" + item.title);
add_to_variables(self.variables, item.variables);
item.group_variables && add_to_variables(self.group_variables, item.group_variables, item.group || (item.group = group));
item.queries = (item.queries || []).filter(subitem => { item.queries = (item.queries || []).filter(subitem => {
if(Check.is_dictionary(subitem)){ if(Check.is_dictionary(subitem)){
add_to_variables(subitem.variables); add_to_variables(self.variables, subitem.variables);
subitem.group_variables && add_to_variables(self.group_variables, item.group_variables, item.group || (item.group = group));
return true; return true;
}; };
return false; return false;

View File

@ -42,18 +42,20 @@ export const CapitalizeFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => format.execute( this.get = ([i, j], inputs, shared = {}, fragments = []) => format.execute([i, j],
Check.is_string(inputs) ? inputs : Check.is_string(inputs) ? inputs :
Check.is_string(inputs[0]) ? inputs[0] : Check.is_string(inputs[0]) ? inputs[0] :
"", shared, fragments).replace(/^./, character => character.toUpperCase()); "", shared, fragments).replace(/^./, character => character.toUpperCase());
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -61,7 +63,7 @@ export const CapitalizeFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => { this.check = ([i, j], string, inputs, shared = {}, fragments = []) => {
/** @type {string} */ /** @type {string} */
const substring = format.set_fragments_level(( const substring = format.set_fragments_level((
@ -70,7 +72,7 @@ export const CapitalizeFormat = (function(){
""), fragments); ""), fragments);
return ( return (
/\{[^\{\}]+\}/.test(substring) ? format.get_check_length(string, [substring], shared, fragments, false) : /\{[^\{\}]+\}/.test(substring) ? format.get_check_length([i, j], string, [substring], shared, fragments, false) :
FormatModule.prepare_result(string, substring, shared)); FormatModule.prepare_result(string, substring, shared));
}; };

View File

@ -37,22 +37,23 @@ export const MixFormat = (function(){
const constructor = () => { const constructor = () => {
format.modes.mix = self.get; format.modes.mix = self.get;
format.checks.mix = self.check; format.checks.mix = self.check;
format.modes.Mix = (inputs, shared, fragments) => self.get(inputs, { format.modes.Mix = ([i, j], inputs, shared, fragments) => self.get([i, j], inputs, {
...shared, capitalized : true ...shared, capitalized : true
}, fragments); }, fragments);
format.checks.Mix = (string, inputs, shared, fragments) => self.check(string, inputs, { format.checks.Mix = ([i, j], string, inputs, shared, fragments) => self.check([i, j], string, inputs, {
...shared, capitalized : true ...shared, capitalized : true
}, fragments); }, fragments);
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => { this.get = ([i, j], inputs, shared = {}, fragments = []) => {
/** @type {[string, Array.<string>]} */ /** @type {[string, Array.<string>]} */
const [separator, original_items] = ( const [separator, original_items] = (
@ -62,14 +63,14 @@ export const MixFormat = (function(){
Check.is_array(inputs) ? inputs : Check.is_array(inputs) ? inputs :
[]), []),
/** @type {Array.<string>} */ /** @type {Array.<string>} */
items = [...original_items]; items = format.get_list([i, j], [...original_items]);
/** @type {number} */ /** @type {number} */
let l = items.length, let l = items.length,
/** @type {string} */ /** @type {string} */
results; results;
Utils.randomize_array(items); Utils.randomize_array(items);
results = format.execute( results = format.execute([i, j],
l < 2 ? items.join("") : l < 2 ? items.join("") :
items.slice(0, l - 1).join(", ") + ( items.slice(0, l - 1).join(", ") + (
!separator ? " " : !separator ? " " :
@ -80,6 +81,7 @@ export const MixFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -87,19 +89,21 @@ export const MixFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => { this.check = ([i, j], string, inputs, shared = {}, fragments = []) => {
/** @type {[string, Array.<string>]} */ /** @type {[string, Array.<string>]} */
const [separator, items] = ( const [separator, original_items] = (
Check.is_string(inputs) ? ((_, separator, items) => [ Check.is_string(inputs) ? ((_, separator, items) => [
separator, items.split("|") separator, items.split("|")
])(...inputs.match(/^([^,]+),(.*)$/)) : ])(...inputs.match(/^([^,]+),(.*)$/)) :
Check.is_array(inputs) ? inputs : Check.is_array(inputs) ? inputs :
[]), []),
/** @type {Array.<string>} */
items = format.get_list([i, j], [...original_items]),
/** @type {number} */ /** @type {number} */
l = items.length; l = items.length;
return format.check_select(string, [[l, l], separator, items], shared, fragments); return format.check_select([i, j], string, [[l, l], separator, items], shared, fragments);
}; };
constructor(); constructor();

View File

@ -40,18 +40,20 @@ export const PlainFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => format.execute( this.get = ([i, j], inputs, shared = {}, fragments = []) => format.execute([i, j],
Check.is_string(inputs) ? inputs : Check.is_string(inputs) ? inputs :
Check.is_string(inputs[0]) ? inputs[0] : Check.is_string(inputs[0]) ? inputs[0] :
"", shared, fragments); "", shared, fragments);
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -59,7 +61,7 @@ export const PlainFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => { this.check = ([i, j], string, inputs, shared = {}, fragments = []) => {
/** @type {string} */ /** @type {string} */
const substring = format.set_fragments_level(( const substring = format.set_fragments_level((
@ -68,7 +70,7 @@ export const PlainFormat = (function(){
""), fragments); ""), fragments);
return ( return (
/\{[^\{\}]+\}/.test(format.set_fragments_level(substring, fragments)) ? format.get_check_length(string, [substring], shared, fragments, false) : /\{[^\{\}]+\}/.test(format.set_fragments_level(substring, fragments)) ? format.get_check_length([i, j], string, [substring], shared, fragments, false) :
FormatModule.prepare_result(string, substring, shared)); FormatModule.prepare_result(string, substring, shared));
}; };

View File

@ -40,18 +40,20 @@ export const RandomFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => format.execute(Utils.get_random( this.get = ([i, j], inputs, shared = {}, fragments = []) => format.execute([i, j], Utils.get_random(format.get_list([i, j], (
Check.is_string(inputs) ? inputs.split("|") : Check.is_string(inputs) ? inputs.split("|") :
Check.is_array(inputs[0]) ? inputs[0] : Check.is_array(inputs[0]) ? inputs[0] :
[]), shared, fragments); []))), shared, fragments);
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -59,21 +61,21 @@ export const RandomFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => { this.check = ([i, j], string, inputs, shared = {}, fragments = []) => {
/** @type {boolean} */ /** @type {boolean} */
let has_empty = false; let has_empty = false;
for(const option of ( for(const option of format.get_list([i, j], (
Check.is_string(inputs) ? inputs.split("|") : Check.is_string(inputs) ? inputs.split("|") :
Check.is_array(inputs[0]) ? inputs[0] : Check.is_array(inputs[0]) ? inputs[0] :
[])){ []))){
if(!option){ if(!option){
has_empty = true; has_empty = true;
continue; continue;
}; };
if(/\{[^\{\}]+\}/.test(format.set_fragments_level(option, fragments))) if(/\{[^\{\}]+\}/.test(format.set_fragments_level(option, fragments)))
return format.get_check_length(string, [option], shared, fragments, false); return format.get_check_length([i, j], string, [option], shared, fragments, false);
/** @type {number} */ /** @type {number} */
let length = FormatModule.prepare_result(string, option, shared); let length = FormatModule.prepare_result(string, option, shared);

View File

@ -39,13 +39,14 @@ export const RangeFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => { this.get = ([i, j], inputs, shared = {}, fragments = []) => {
if(Check.is_number(inputs = ( if(Check.is_number(inputs = (
Check.is_string(inputs) ? Utils.get_random(inputs.split("|")).split("-").map(Number) : Check.is_string(inputs) ? Utils.get_random(inputs.split("|")).split("-").map(Number) :
@ -63,6 +64,7 @@ export const RangeFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -70,7 +72,7 @@ export const RangeFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => FormatModule.check_range(string, inputs); this.check = ([i, j], string, inputs, shared = {}, fragments = []) => FormatModule.check_range(string, inputs);
constructor(); constructor();

View File

@ -37,22 +37,23 @@ export const SelectFormat = (function(){
const constructor = () => { const constructor = () => {
format.modes.select = self.get; format.modes.select = self.get;
format.checks.select = self.check; format.checks.select = self.check;
format.modes.Select = (inputs, shared, fragments) => self.get(inputs, { format.modes.Select = ([i, j], inputs, shared, fragments) => self.get([i, j], inputs, {
...shared, capitalized : true ...shared, capitalized : true
}, fragments); }, fragments);
format.checks.Select = (string, inputs, shared, fragments) => self.check(string, inputs, { format.checks.Select = ([i, j], string, inputs, shared, fragments) => self.check([i, j], string, inputs, {
...shared, capitalized : true ...shared, capitalized : true
}, fragments); }, fragments);
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => { this.get = ([i, j], inputs, shared = {}, fragments = []) => {
/** @type {[[number, number], string, Array.<string>]} */ /** @type {[[number, number], string, Array.<string>]} */
const [range, separator, original_items] = ( const [range, separator, original_items] = (
@ -62,13 +63,13 @@ export const SelectFormat = (function(){
Check.is_array(inputs) ? inputs : Check.is_array(inputs) ? inputs :
[]), []),
/** @type {number} */ /** @type {number} */
i = Utils.get_random(...range); k = Utils.get_random(...range);
if(!i) if(!k)
return ""; return "";
/** @type {Array.<string>} */ /** @type {Array.<string>} */
const items = [...original_items]; const items = format.get_list([i, j], [...original_items]);
/** @type {number} */ /** @type {number} */
let l = items.length, let l = items.length,
/** @type {string} */ /** @type {string} */
@ -79,7 +80,7 @@ export const SelectFormat = (function(){
else{ else{
Utils.randomize_array(items); Utils.randomize_array(items);
items.splice(0, l - i); items.splice(0, l - k);
l = items.length; l = items.length;
results = ( results = (
@ -90,12 +91,13 @@ export const SelectFormat = (function(){
separator) + items[l - 1]); separator) + items[l - 1]);
}; };
results = format.execute(results, shared, fragments); results = format.execute([i, j], results, shared, fragments);
return shared.capitalized ? results.replace(/^./, character => character.toUpperCase()) : results; return shared.capitalized ? results.replace(/^./, character => character.toUpperCase()) : results;
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -103,12 +105,20 @@ export const SelectFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => format.check_select(string, ( this.check = ([i, j], string, inputs, shared = {}, fragments = []) => {
/** @type {[[number, number], string, Array.<string>]} */
const [[minimum, maximum], separator, original_items] = (
Check.is_string(inputs) ? ((_, range, separator, options) => [ Check.is_string(inputs) ? ((_, range, separator, options) => [
range.split("-").map(Number), separator, options.split("|") range.split("-").map(Number), separator, options.split("|")
])(...inputs.match(/^([^,]+),([^,]+),(.*)$/)) : ])(...inputs.match(/^([^,]+),([^,]+),(.*)$/)) :
Check.is_array(inputs) ? inputs : Check.is_array(inputs) ? inputs :
[]), shared, fragments); []),
/** @type {Array.<string>} */
items = format.get_list([i, j], [...original_items]);
return format.check_select([i, j], string, [[minimum, maximum], separator, items], shared, fragments);
};
constructor(); constructor();

View File

@ -39,13 +39,14 @@ export const SerieFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!(string|Array.<any|null>)} inputs * @param {!(string|Array.<any|null>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.get = (inputs, shared = {}, fragments = []) => { this.get = ([i, j], inputs, shared = {}, fragments = []) => {
Check.is_string(inputs) && Check.is_string(inputs) &&
(inputs = inputs.split("|").map(range => range.split("-").map(Number))); (inputs = inputs.split("|").map(range => range.split("-").map(Number)));
@ -73,6 +74,7 @@ export const SerieFormat = (function(){
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} inputs * @param {!(string|Array.<string>)} inputs
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -80,7 +82,7 @@ export const SerieFormat = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check = (string, inputs, shared = {}, fragments = []) => FormatModule.check_range(string, inputs); this.check = ([i, j], string, inputs, shared = {}, fragments = []) => FormatModule.check_range(string, inputs);
constructor(); constructor();

View File

@ -85,6 +85,22 @@ export const FormatModule = (function(){
const constructor = () => {}; const constructor = () => {};
/** /**
* @param {![number, number]} coordenates
* @param {!string} key
* @returns {[string, ...(any|null)]|null}
* @access public
*/
this.get_variable = ([i, j], key) => {
// key == "l_40_2015" && console.log([i, j, key, ot.variables]);
return (
(ot.database[i].queries[j].own_variables && ot.database[i].queries[j].own_variables[key]) ||
(ot.group_variables[ot.database[i].group] && ot.group_variables[ot.database[i].group][key]) ||
ot.variables[key]
);
};
/**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} options * @param {!(string|Array.<string>)} options
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -93,15 +109,16 @@ export const FormatModule = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.get_check_length = (string, options, shared = {}, fragments = [], check_full = true) => { this.get_check_length = ([i, j], string, options, shared = {}, fragments = [], check_full = true) => {
/** @type {[boolean, number]} */ /** @type {[boolean, number]} */
const [has, length] = self.check(string, options, shared, fragments, check_full); const [has, length] = self.check([i, j], string, options, shared, fragments, check_full);
return has ? length : -1; return has ? length : -1;
}; };
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!(string|Array.<string>)} options * @param {!(string|Array.<string>)} options
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -110,7 +127,7 @@ export const FormatModule = (function(){
* @returns {[boolean, number]} * @returns {[boolean, number]}
* @access public * @access public
*/ */
this.check = (string, options, shared = {}, fragments = [], check_full = true) => { this.check = ([i, j], string, options, shared = {}, fragments = [], check_full = true) => {
/** @type {number} */ /** @type {number} */
let length = 0; let length = 0;
@ -132,10 +149,10 @@ export const FormatModule = (function(){
}); });
length = 0; length = 0;
return parts.every((part, i) => { return parts.every((part, k) => {
/** @type {number} */ /** @type {number} */
let j = -1; let m = -1;
/** @type {RegExpMatchArray} */ /** @type {RegExpMatchArray} */
const matches = part.match(/^\{([^\{\}]+)\}$/); const matches = part.match(/^\{([^\{\}]+)\}$/);
@ -148,15 +165,15 @@ export const FormatModule = (function(){
if(key in ot.variables){ if(key in ot.variables){
/** @type {[string, ...(any|null)]} */ /** @type {[string, ...(any|null)]} */
const [method, ...data] = ot.variables[key]; const [method, ...data] = self.get_variable([i, j], key);
method in self.checks && method in self.checks &&
// self.checks[method](clone, data, shared, fragments) != -1 && // self.checks[method]([i, j], clone, data, shared, fragments) != -1 &&
(j = self.checks[method](clone, data, shared, fragments)); (m = self.checks[method]([i, j], clone, data, shared, fragments));
}else if(parts[i + 1]){ }else if(parts[k + 1]){
// TEMPORARY SOLUTION. NEEDS BUILD REAL SOLUTION. // TEMPORARY SOLUTION. NEEDS BUILD REAL SOLUTION.
j = clone.indexOf(parts[i + 1]); m = clone.indexOf(parts[k + 1]);
}; };
}else{ }else{
@ -169,16 +186,16 @@ export const FormatModule = (function(){
const [method, data] = matches.slice(1, 3); const [method, data] = matches.slice(1, 3);
method in self.checks && method in self.checks &&
(j = self.checks[method](clone, data, shared, fragments)); (m = self.checks[method]([i, j], clone, data, shared, fragments));
}; };
}; };
}; };
j == -1 && (j = FormatModule.prepare_result(clone, part, shared)); m == -1 && (m = FormatModule.prepare_result(clone, part, shared));
if(j != -1){ if(m != -1){
clone = clone.slice(j); clone = clone.slice(m);
length += j; length += m;
return true; return true;
}; };
return false; return false;
@ -214,26 +231,31 @@ export const FormatModule = (function(){
); );
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
* @param {!Array.<string>} [fragments = []] * @param {!Array.<string>} [fragments = []]
* @returns {string} * @returns {string}
* @access public * @access public
*/ */
this.execute = (string, shared = {}, fragments = []) => ( this.execute = ([i, j], string, shared = {}, fragments = []) => (
FormatModule.recursive(self.build_fragments(string, fragments), substring => { FormatModule.recursive(self.build_fragments(string, fragments), substring => {
try{ try{
return substring.replace(/\{([^\{\}]+)\}/g, (original, key) => { return substring.replace(/\{([^\{\}]+)\}/g, (original, key) => {
if(/^[a-z0-9_]+$/i.test(key)){ if(/^[a-z0-9_]+$/i.test(key)){
if(key in shared) if(key in shared)
return shared[key]; return shared[key];
else if(key in ot.variables){
/** @type {[string, ...(any|null)]|null} */
const variable = self.get_variable([i, j], key);
if(variable){
/** @type {[string, ...(any|null)]} */ /** @type {[string, ...(any|null)]} */
const [method, ...data] = ot.variables[key]; const [method, ...data] = variable;
if(method in self.modes) if(method in self.modes)
return self.modes[method](data, shared, fragments); return self.modes[method]([i, j], data, shared, fragments);
}; };
}else{ }else{
@ -246,7 +268,7 @@ export const FormatModule = (function(){
const [method, data] = matches.slice(1, 3); const [method, data] = matches.slice(1, 3);
if(method in self.modes) if(method in self.modes)
return self.modes[method](data, shared, fragments); return self.modes[method]([i, j], data, shared, fragments);
}; };
}; };
return original return original
@ -259,6 +281,7 @@ export const FormatModule = (function(){
); );
/** /**
* @param {[number, number]} coordenates
* @param {!string} string * @param {!string} string
* @param {[[number, number], string, Array.<string>]} parameters * @param {[[number, number], string, Array.<string>]} parameters
* @param {!Object.<string, any|null>} [shared = {}] * @param {!Object.<string, any|null>} [shared = {}]
@ -266,7 +289,7 @@ export const FormatModule = (function(){
* @returns {number} * @returns {number}
* @access public * @access public
*/ */
this.check_select = (string, [[minimum, maximum], separator, items], shared = {}, fragments = []) => { this.check_select = ([i, j], string, [[minimum, maximum], separator, items], shared = {}, fragments = []) => {
/** @type {number} */ /** @type {number} */
let length = 0, let length = 0,
@ -291,16 +314,16 @@ export const FormatModule = (function(){
}; };
for(let i = 0; i < l; i ++){ for(let m = 0; m < l; m ++){
/** @type {number} */ /** @type {number} */
const item_length = ( const item_length = (
/\{[^\{\}]+\}/.test(self.set_fragments_level(items[i], shared, fragments)) ? self.get_check_length(string, [items[i]], shared, fragments, false) : /\{[^\{\}]+\}/.test(self.set_fragments_level(items[m], shared, fragments)) ? self.get_check_length([i, j], string, [items[m]], shared, fragments, false) :
FormatModule.prepare_result(string, items[i], shared)); FormatModule.prepare_result(string, items[m], shared));
if(item_length != -1){ if(item_length != -1){
string = string.substring(0, item_length); string = string.substring(0, item_length);
items.splice(i, 1); items.splice(m, 1);
length += item_length; length += item_length;
ok = true; ok = true;
break; break;
@ -322,6 +345,30 @@ export const FormatModule = (function(){
return k < minimum ? -1 : length; return k < minimum ? -1 : length;
}; };
/**
* @param {[number, number]} coordenates
* @param {!Array.<string>} items
* @returns {Array.<string>}
* @access public
*/
this.get_list = ([i, j], items) => items.reduce((items, item) => {
/** @type {RegExpMatchArray} */
const matches = item.match(/^list\:([a-z0-9_]+)$/i);
if(matches){
/** @type {string} */
const key = matches[1],
/** @type {[string, ...(any|null)]|null} */
variable = self.get_variable([i, j], key);
if(variable[0] == "list")
return items.concat(variable[1]);
};
return items.concat([item]);
}, []);
constructor(); constructor();
}; };

View File

@ -148,6 +148,16 @@ export const Utils = (function(){
upper ? "-" + upper.toLowerCase() : upper ? "-" + upper.toLowerCase() :
"-")); "-"));
/**
* @param {!string} string
* @returns {string}
* @access public
* @static
*/
Utils.to_snake_case = string => ("" + string).replace(/([A-Z]+)|[^a-z0-9]+/g, (_, upper) => (
upper ? "_" + upper.toLowerCase() :
"_"));
/** /**
* @param {!HTMLElement} item * @param {!HTMLElement} item
* @param {...Object.<string, any|null>} attributes * @param {...Object.<string, any|null>} attributes

View File

@ -55,6 +55,7 @@ export const TestsView = (function(){
]]; ]];
/** /**
* @param {![number, number]} coordenates
* @param {!Array.<[string, boolean, boolean]>} originals * @param {!Array.<[string, boolean, boolean]>} originals
* @param {!Array.<[string, boolean]>} raw_answers * @param {!Array.<[string, boolean]>} raw_answers
* @param {boolean} right * @param {boolean} right
@ -62,7 +63,7 @@ export const TestsView = (function(){
* @access public * @access public
* @static * @static
*/ */
const replace_answer = (originals, raw_answers, right, number_of_answers) => { const replace_answer = ([i, j], originals, raw_answers, right, number_of_answers) => {
/** @type {Array.<[string, boolean, boolean]>} */ /** @type {Array.<[string, boolean, boolean]>} */
const set = originals.filter(([_, ok]) => right ? ok : !ok); const set = originals.filter(([_, ok]) => right ? ok : !ok);
@ -78,7 +79,7 @@ export const TestsView = (function(){
if(!probability || Math.random() < probability){ if(!probability || Math.random() < probability){
/** @type {string} */ /** @type {string} */
const string_answer = dynamic ? ot.format.execute(answer) : answer; const string_answer = dynamic ? ot.format.execute([i, j], answer) : answer;
if(raw_answers.length < number_of_answers) if(raw_answers.length < number_of_answers)
raw_answers.some(([originals, ok]) => ok && originals == string_answer) || raw_answers.some(([originals, ok]) => ok && originals == string_answer) ||
@ -197,7 +198,7 @@ export const TestsView = (function(){
}; };
if(dynamic) if(dynamic)
answer = ot.format.execute(answer); answer = ot.format.execute([i, j], answer);
else else
originals.splice(k, 1); originals.splice(k, 1);
@ -212,6 +213,7 @@ export const TestsView = (function(){
// ), // ),
// ot.format.check( // ot.format.check(
// [i, j],
// answer, // answer,
// originals.map(([[base, __], right, _]) => ( // originals.map(([[base, __], right, _]) => (
// right ? base : null // right ? base : null
@ -225,6 +227,7 @@ export const TestsView = (function(){
// answer && // answer &&
// !raw_answers.some(([base, _]) => answer == base) && // !raw_answers.some(([base, _]) => answer == base) &&
// !ot.format.check( // !ot.format.check(
// [i, j],
// answer, // answer,
// originals.map(([[base, __], right, _]) => ( // originals.map(([[base, __], right, _]) => (
// right ? base : null // right ? base : null
@ -238,6 +241,7 @@ export const TestsView = (function(){
answer && answer &&
!(raw_answers.length && raw_answers.some(([base, _]) => answer == base)) && !(raw_answers.length && raw_answers.some(([base, _]) => answer == base)) &&
!ot.format.check( !ot.format.check(
[i, j],
answer, answer,
originals.map(([[base, __], right, _]) => ( originals.map(([[base, __], right, _]) => (
right ? base : null right ? base : null
@ -258,9 +262,9 @@ export const TestsView = (function(){
}; };
if(!raw_answers.some(([_, ok]) => ok) && (!data.allow_all_answers_false || !multiple_answers)) if(!raw_answers.some(([_, ok]) => ok) && (!data.allow_all_answers_false || !multiple_answers))
replace_answer(originals, raw_answers, true, number_of_answers); replace_answer([i, j], originals, raw_answers, true, number_of_answers);
else if(!raw_answers.some(([_, ok]) => !ok) && !data.allow_all_answers_true) else if(!raw_answers.some(([_, ok]) => !ok) && !data.allow_all_answers_true)
replace_answer(originals, raw_answers, false, number_of_answers); replace_answer([i, j], originals, raw_answers, false, number_of_answers);
raw_answers.length < number_of_answers && console.warn([q, raw_answers, memory]); raw_answers.length < number_of_answers && console.warn([q, raw_answers, memory]);
@ -291,7 +295,7 @@ export const TestsView = (function(){
ot.comp.i18n("unanswered") ot.comp.i18n("unanswered")
]] ]]
]], ]],
["p", null, ot.format.execute(Check.is_array(ot.database[i].queries[j].question) ? Utils.get_random(ot.database[i].queries[j].question) : ot.database[i].queries[j].question)], ["p", null, ot.format.execute([i, j], Check.is_array(ot.database[i].queries[j].question) ? Utils.get_random(ot.database[i].queries[j].question) : ot.database[i].queries[j].question)],
["ul", {class : "answers"}, answers.map((answer, i) => ["li", {data_i : i}, [ ["ul", {class : "answers"}, answers.map((answer, i) => ["li", {data_i : i}, [
ot.comp[multiple_answers ? "checkbox" : "radio"]("q" + q + "[]", false, (item, event) => { ot.comp[multiple_answers ? "checkbox" : "radio"]("q" + q + "[]", false, (item, event) => {

View File

@ -2,7 +2,9 @@
"/json/gemini/constitucion-espanola/gemini.ce.166.json", "/json/gemini/constitucion-espanola/gemini.ce.166.json",
"/json/kyman/comun/kyman.-1.leyes.json",
"/json/kyman/comun/kyman.-0.diccionario.json", "/json/kyman/comun/kyman.-0.diccionario.json",
"/json/kyman/comun/kyman.00.tipos-leyes.json", "/json/kyman/comun/kyman.00.tipos-leyes.json",
"/json/paco/constitucion/paco.ce.00.constitucion.json", "/json/paco/constitucion/paco.ce.00.constitucion.json",
"/json/paco/constitucion/paco.ce.01.0.constitucion.preliminar.json", "/json/paco/constitucion/paco.ce.01.0.constitucion.preliminar.json",
@ -26,6 +28,10 @@
"/json/kyman/especifico/kyman.02.hardware.00.ics.json", "/json/kyman/especifico/kyman.02.hardware.00.ics.json",
"/json/kyman/especifico/kyman.03.desarrollo.02.codificaciones-texto.json", "/json/kyman/especifico/kyman.03.desarrollo.02.codificaciones-texto.json",
"/json/kyman/especifico/kyman.aa.red-sara.json", "/json/kyman/especifico/kyman.aa.red-sara.json",
"/json/kyman/especifico/kyman.ab.eni.json",
"/json/kyman/especifico/kyman.ac.eni.preguntas-frecuentes.json",
"/json/kyman/especifico/software/kyman.00.ping.json",
"/data/json/baquedano/c-ejer-1-promo-sass-2025.json", "/data/json/baquedano/c-ejer-1-promo-sass-2025.json",
"/data/json/baquedano/c-ejer-1-libre-sas-2025.json", "/data/json/baquedano/c-ejer-1-libre-sas-2025.json",

View File

@ -11,6 +11,8 @@
"BOP" : ["rand", ["BOP", "Boletín Oficial de la Provincia"]], "BOP" : ["rand", ["BOP", "Boletín Oficial de la Provincia"]],
"DOGA" : ["rand", ["DOGA", "Diario Oficial de Galicia"]], "DOGA" : ["rand", ["DOGA", "Diario Oficial de Galicia"]],
"BOD" : ["rand", ["BOD", "Boletín Oficial de Defensa"]], "BOD" : ["rand", ["BOD", "Boletín Oficial de Defensa"]],
"TC" : ["rand", ["Tribunal Constitucional", "TC"]],
"AAPP" : ["rand", ["Administraciones Públicas", "AAPP"]],
"meses" : ["rand", ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]], "meses" : ["rand", ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]],
@ -33,7 +35,8 @@
"La Norma{rand:|s|ativa}{rand:| {rand:con|de} Rango {rand:de Ley|Reglamentario}}", "La Norma{rand:|s|ativa}{rand:| {rand:con|de} Rango {rand:de Ley|Reglamentario}}",
"La {rand:Resolu{rand:ción|tiva}|Orden{rand:|amiento}}{rand:| Judicial| Administrativa| Técnica| Ministerial}" "La {rand:Resolu{rand:ción|tiva}|Orden{rand:|amiento}}{rand:| Judicial| Administrativa| Técnica| Ministerial}"
]], ]],
"ley" : ["plain", "{tipo_ley_random_el} {range:1-99}/{rand:{range:1978-2025}|{range:1918-2025}}{rand:|, de {range:1-31} de {meses}}"], "ley" : ["plain", "{tipo_ley_random_el} {range:1-99}/{rand:{range:1918-2025}|{range:1918-2025}}{rand:|, de {range:1-31} de {meses}}"],
"ley_base" : ["plain", "{range:1-600}/{rand:{range:1918-2025}|{range:1918-2025}}{rand:|, de {range:1-31} de {meses}}"],
"cortes_generales" : ["rand", ["Cortes Generales", "Poder Legislativo"]], "cortes_generales" : ["rand", ["Cortes Generales", "Poder Legislativo"]],
"gobierno" : ["rand", ["Gobierno", "Poder Ejecutivo"]], "gobierno" : ["rand", ["Gobierno", "Poder Ejecutivo"]],
"poder_judicial" : ["rand", ["Poder Judicial", "{mix:y,Jueces|Tribunales}"]], "poder_judicial" : ["rand", ["Poder Judicial", "{mix:y,Jueces|Tribunales}"]],
@ -113,8 +116,6 @@
"27 de Septiembre de 2011", "27 de Septiembre de 2011",
"15 de Febrero de 2024" "15 de Febrero de 2024"
]], ]],
"ce78_alternativas" : ["rand", ["Ley de Leyes", "Carta Magna", "Norma Suprema"]],
"ce78" : ["plain", "{rand:{ce78_alternativas}|Constitución}{rand:| Española}{rand:| de 1978}"],
"ce78_establece" : ["mix", "y", [ "ce78_establece" : ["mix", "y", [
"la estructura del Estado", "la estructura del Estado",
"la organización de los poderes públicos", "la organización de los poderes públicos",
@ -254,68 +255,9 @@
"TREBEP" : ["rand", ["TREBEP", "Texto Refundido de la Ley del Estatuto Básico del Empleado Público", "{RDL} 5/2015{rand:|, de 30 de Octubre}"]], "TREBEP" : ["rand", ["TREBEP", "Texto Refundido de la Ley del Estatuto Básico del Empleado Público", "{RDL} 5/2015{rand:|, de 30 de Octubre}"]],
"EBEP" : ["rand", ["EBEP", "Estatuto Básico del Empleado Público", "Ley 7/2007{rand:|, de 12 de Abril}"]], "EBEP" : ["rand", ["EBEP", "Estatuto Básico del Empleado Público", "Ley 7/2007{rand:|, de 12 de Abril}"]],
"trebep_ley" : ["plain", "{RDL} 5/2015{rand:|, de 30 de Octubre}"], "RD" : ["rand", ["RD", "Real Decreto", "Decreto"]],
"trebep_nombre" : ["rand", [
"TREBEP",
"Texto Refundido de la Ley del Estatuto Básico del Empleado Público"
]],
"trebep" : ["rand", [
"{trebep_nombre}",
"{trebep_ley}{rand:|, por el que se aprueba el {trebep_nombre}}"
]],
"ebep_ley" : ["plain", "Ley 7/2007{rand:|, de 12 de Abril}"],
"ebep_nombre" : ["rand", [
"EBEP",
"Estatuto Básico del Empleado Público"
]],
"ebep" : ["rand", [
"{ebep_nombre}",
"{ebep_ley}{rand:|, por el que se aprueba el {ebep_nombre}}"
]],
"RD" : ["rand", ["{RD}", "Real Decreto", "Decreto"]],
"RD_RDL" : ["rand", ["{RDL}", "{RD}"]], "RD_RDL" : ["rand", ["{RDL}", "{RD}"]],
"LO" : ["rand", ["Ley Orgánica", "LO"]], "LO" : ["rand", ["Ley Orgánica", "LO"]],
"rd_364_1995_ley" : ["plain", "{rand:RD|RDL} 364/1995{rand:|, de 10 de Marzo}"],
"rd_364_1995_nombre" : ["plain", "Reglamento General de Ingreso del Personal al servicio de la Administración general del Estado y de Provisión de Puestos de Trabajo y Promoción Profesional de los Funcionarios Civiles de la Administración general del Estado"],
"rd_365_1995_ley" : ["plain", "{rand:RD|RDL} 365/1995{rand:|, de 10 de Marzo}"],
"rd_364_1995" : ["rand", [
"{rd_364_1995_nombre}",
"{rd_364_1995_ley}{rand:|, por el que se aprueba el {rd_364_1995_nombre}}"
]],
"rd_365_1995_nombre" : ["plain", "Reglamento de Situaciones Administrativas de los Funcionarios Civiles de la Administración General del Estado"],
"rd_365_1995" : ["rand", [
"{rd_365_1995_nombre}",
"{rd_365_1995_ley}{rand:|, por el que se aprueba el {rd_365_1995_nombre}}"
]],
"l_30_30_1984_ley" : ["plain", "Ley 30/1984{rand:|, de 2 de Agosto}"],
"l_30_30_1984_nombre" : ["plain", "Ley de Medidas para la Reforma de la Función Pública"],
"l_30_30_1984" : ["rand", [
"{l_30_30_1984_nombre}",
"{l_30_30_1984_ley}{rand:|, por el que se aprueba el {l_30_30_1984_nombre}}"
]],
"d_315_1964_ley" : ["plain", "Decreto 315/1964{rand:|, de 7 de Febrero}"],
"d_315_1964_nombre" : ["plain", "Ley articulada de Funcionarios Civiles del Estado"],
"d_315_1964" : ["rand", [
"{d_315_1964_nombre}",
"{d_315_1964_ley}{rand:|, por el que se aprueba el {d_315_1964_nombre}}"
]],
"TC" : ["rand", ["Tribunal Constitucional", "TC"]],
"rdl_2_2015_ley" : ["plain", "{RDL} 2/2015{rand:|, de 23 de Octubre}"],
"rdl_2_2015_nombre" : ["plain", "Texto Refundido de la Ley del Estatuto de los Trabajadores"],
"rdl_2_2015" : ["rand", [
"{rdl_2_2015_nombre}",
"{rdl_2_2015_ley}{rand:|, por el que se aprueba el {rdl_2_2015_nombre}}",
"Ley del Estatuto de los Trabajadores"
]],
"lo_2_1986_ley" : ["plain", "{LO} 2/1986{rand:|, de 13 de marzo}"],
"lo_2_1986_nombre" : ["plain", "Ley de Fuerzas y Cuerpos de Seguridad"],
"lo_2_1986" : ["plain", "{lo_2_1986_ley}{rand:|, {lo_2_1986_nombre}}"],
"l_53_1984_ley" : ["plain", "Ley 53/1984{rand:|, de 26 de Diciembre}"],
"l_53_1984_nombre" : ["plain", "Ley de Incompatibilidades del Personal al servicio de las Administraciones Públicas"],
"l_53_1984" : ["plain", "{l_53_1984_ley}{rand:|, {l_53_1984_nombre}}"],
"l_30_1984_ley" : ["plain", "Ley 30/1984{rand:|, de 2 de Agosto}"],
"l_30_1984_nombre" : ["plain", "Ley de Medidas para la Reforma de la Función Pública"],
"l_30_1984" : ["plain", "{l_30_1984_ley}{rand:|, {l_30_1984_nombre}}"],
"trebep_anos" : ["rand", ["2007", "2015", "1995", "1984", "1964", "1918"]], "trebep_anos" : ["rand", ["2007", "2015", "1995", "1984", "1964", "1918"]],
"trebep_meses" : ["rand", ["Febrero", "Marzo", "Agosto", "Octubre", "Noviembre", "Diciembre", "Julio"]], "trebep_meses" : ["rand", ["Febrero", "Marzo", "Agosto", "Octubre", "Noviembre", "Diciembre", "Julio"]],
"trebep_dias" : ["rand", ["1", "2", "10", "7", "23", "30", "31", "24"]], "trebep_dias" : ["rand", ["1", "2", "10", "7", "23", "30", "31", "24"]],
@ -340,7 +282,10 @@
"trebep_tv_ciii" : ["rand", ["Tercero", "3º", "Provisión de {mix:y,puestos de trabajo|movilidad}"]], "trebep_tv_ciii" : ["rand", ["Tercero", "3º", "Provisión de {mix:y,puestos de trabajo|movilidad}"]],
"trebep_tvi" : ["rand", ["VI", "Sexto", "6º", "Situaciones administrativas"]], "trebep_tvi" : ["rand", ["VI", "Sexto", "6º", "Situaciones administrativas"]],
"trebep_tvii" : ["rand", ["VII", "Séptimo", "7º", "Régimen disciplinario"]], "trebep_tvii" : ["rand", ["VII", "Séptimo", "7º", "Régimen disciplinario"]],
"trebep_tviii" : ["rand", ["VIII", "Octavo", "8º", "Cooperación entre las Administraciones Públicas"]] "trebep_tviii" : ["rand", ["VIII", "Octavo", "8º", "Cooperación entre las Administraciones Públicas"]],
"eni_nombre" : ["rand", ["ENI", "Esquema Nacional de Interoperabilidad"]],
"ens_nombre" : ["rand", ["ENS", "Esquema Nacional de Seguridad"]]
}, },
"queries" : [] "queries" : []

View File

@ -0,0 +1,131 @@
[{
"origin" : "KyMAN",
"sources" : [],
"title" : "Común - Leyes",
"group" : "kyman_comun_leyes",
"variables" : {
"l_30_30_1984_ley" : ["plain", "Ley 30/1984{rand:|, de 2 de Agosto}"],
"l_30_30_1984_nombre" : ["plain", "Ley de Medidas para la Reforma de la Función Pública"],
"l_30_30_1984" : ["rand", [
"{l_30_30_1984_nombre}",
"{l_30_30_1984_ley}{rand:|, por el que se aprueba el {l_30_30_1984_nombre}}"
]],
"ce78_alternativas" : ["rand", ["Ley de Leyes", "Carta Magna", "Norma Suprema"]],
"ce78" : ["plain", "{rand:{ce78_alternativas}|Constitución}{rand:| Española}{rand:| de 1978}"],
"trebep_ley" : ["plain", "{RDL} 5/2015{rand:|, de 30 de Octubre}"],
"trebep_nombre" : ["rand", [
"TREBEP",
"Texto Refundido de la Ley del Estatuto Básico del Empleado Público"
]],
"trebep" : ["rand", [
"{trebep_nombre}",
"{trebep_ley}{rand:|, por el que se aprueba el {trebep_nombre}}"
]],
"ebep_ley" : ["plain", "Ley 7/2007{rand:|, de 12 de Abril}"],
"ebep_nombre" : ["rand", [
"EBEP",
"Estatuto Básico del Empleado Público"
]],
"ebep" : ["rand", [
"{ebep_nombre}",
"{ebep_ley}{rand:|, por el que se aprueba el {ebep_nombre}}"
]],
"rgpd_ley" : ["plain", "Reglamento (UE) 2016/679{rand:|, de 27 de Abril}"],
"rgpd_nombre" : ["rand", ["Reglamento General de Protección de Datos", "RGPD"]],
"rgpd" : ["rand", [
"{rgpd_nombre}",
"{rgpd_ley}{rand:|, relativo a la protección de las personas físicas en lo que respecta al tratamiento de datos personales y a la libre circulación de estos datos{rand:| y por el que se deroga la {d_95_46_ce}}}"
]],
"lopd_ley" : ["plain", "Ley Orgánica 3/2018{rand:|, de 5 de Diciembre}"],
"lopd_nombre" : ["rand", [
"LOPD{rand:|GDD}",
"Ley Orgánica de Protección de Datos{rand:| Personales}{rand:| y garantía de los derechos digitales}",
"Ley Orgánica de Protección de Datos Personales y garantía de los derechos digitales"
]],
"lopd" : ["rand", [
"{lopd_nombre}",
"{lopd_ley}{rand:|, de Protección de Datos Personales y garantía de los derechos digitales}"
]],
"d_95_46_ce_ley" : ["plain", "Directiva 95/46/CE{rand:|, {mix:y,del Parlamento Europeo|del Consejo}}{rand:|, de 24 de Octubre de 1995}"],
"d_95_46_ce_nombre" : ["rand", ["Directiva de Protección de Datos"]],
"d_95_46_ce" : ["rand", [
"{d_95_46_ce_nombre}",
"{d_95_46_ce_ley}{rand:|, relativa a la protección de las personas físicas en lo respectivo al tratamiento de datos personales y a la libre circulación de estos datos}"
]],
"d_315_1964_ley" : ["plain", "Decreto 315/1964{rand:|, de 7 de Febrero}"],
"d_315_1964_nombre" : ["plain", "Ley articulada de Funcionarios Civiles del Estado"],
"d_315_1964" : ["rand", [
"{d_315_1964_nombre}",
"{d_315_1964_ley}{rand:|, por el que se aprueba el {d_315_1964_nombre}}"
]],
"rd_364_1995_ley" : ["plain", "{rand:RD|RDL} 364/1995{rand:|, de 10 de Marzo}"],
"rd_364_1995_nombre" : ["plain", "Reglamento General de Ingreso del Personal al servicio de la Administración general del Estado y de Provisión de Puestos de Trabajo y Promoción Profesional de los Funcionarios Civiles de la Administración general del Estado"],
"rd_364_1995" : ["rand", [
"{rd_364_1995_nombre}",
"{rd_364_1995_ley}{rand:|, por el que se aprueba el {rd_364_1995_nombre}}"
]],
"rd_365_1995_ley" : ["plain", "{rand:RD|RDL} 365/1995{rand:|, de 10 de Marzo}"],
"rd_365_1995_nombre" : ["plain", "Reglamento de Situaciones Administrativas de los Funcionarios Civiles de la Administración General del Estado"],
"rd_365_1995" : ["rand", [
"{rd_365_1995_nombre}",
"{rd_365_1995_ley}{rand:|, por el que se aprueba el {rd_365_1995_nombre}}"
]],
"rd_4_2010_ley" : ["plain", "{RD} 4/2010{rand:|, de 8 de Enero}"],
"rd_4_2010_nombre" : ["plain", "por el que se regula el {eni_nombre} en el ámbito de la Administración Electrónica"],
"rd_4_2010" : ["rand", [
"{rd_4_2010_nombre}",
"{rd_4_2010_ley}{rand:|, por el que se aprueba el {rd_4_2010_nombre}}"
]],
"rdl_2_2015_ley" : ["plain", "{RDL} 2/2015{rand:|, de 23 de Octubre}"],
"rdl_2_2015_nombre" : ["plain", "Texto Refundido de la Ley del Estatuto de los Trabajadores"],
"rdl_2_2015" : ["rand", [
"{rdl_2_2015_nombre}",
"{rdl_2_2015_ley}{rand:|, por el que se aprueba el {rdl_2_2015_nombre}}",
"{rand:|Ley del }Estatuto de los Trabajadores"
]],
"l_30_1984_ley" : ["plain", "Ley 30/1984{rand:|, de 2 de Agosto}"],
"l_30_1984_nombre" : ["plain", "Ley de Medidas para la Reforma de la Función Pública"],
"l_30_1984" : ["rand", [
"{l_30_1984_nombre}",
"{l_30_1984_ley}{rand:|, de Medidas para la Reforma de la Función Pública}"
]],
"l_53_1984_ley" : ["plain", "Ley 53/1984{rand:|, de 26 de Diciembre}"],
"l_53_1984_nombre" : ["plain", "Ley de Incompatibilidades del Personal al servicio de las Administraciones Públicas"],
"l_53_1984" : ["rand", [
"{l_53_1984_nombre}",
"{l_53_1984_ley}{rand:|, de Incompatibilidades del Personal al servicio de las Administraciones Públicas}"
]],
"l_11_2007_ley" : ["plain", "Ley 11/2007{rand:|, de 22 de Junio}"],
"l_11_2007_nombre" : ["plain", "Ley de Acceso Electrónico de los Ciudadanos a los Servicios Públicos"],
"l_11_2007" : ["rand", [
"{l_11_2007_nombre}",
"{l_11_2007_ley}{rand:|, de Acceso Electrónico de los Ciudadanos a los Servicios Públicos}"
]],
"l_39_2015_ley" : ["plain", "Ley 39/2015{rand:|, de 1 de Octubre}"],
"l_39_2015_nombre" : ["plain", "Ley del Procedimiento Administrativo Común de las Administraciones Públicas"],
"l_39_2015" : ["rand", [
"{l_39_2015_nombre}",
"{l_39_2015_ley}{rand:|, de Procedimiento Administrativo Común de las Administraciones Públicas}"
]],
"l_40_2015_ley" : ["plain", "Ley 40/2015{rand:|, de 1 de Octubre}"],
"l_40_2015_nombre" : ["plain", "Ley de Régimen Jurídico del Sector Público"],
"l_40_2015" : ["rand", [
"{l_40_2015_nombre}",
"{l_40_2015_ley}{rand:|, de Régimen Jurídico del Sector Público}"
]],
"lo_2_1986_ley" : ["plain", "{LO} 2/1986{rand:|, de 13 de marzo}"],
"lo_2_1986_nombre" : ["plain", "Ley Orgánica de Fuerzas y Cuerpos de Seguridad"],
"lo_2_1986" : ["rand", [
"{lo_2_1986_nombre}",
"{lo_2_1986_ley}{rand:|, de Fuerzas y Cuerpos de Seguridad}"
]]
}
}]

View File

@ -0,0 +1,302 @@
[{
"origin" : "KyMAN",
"sources" : [
"https://administracionelectronica.gob.es/ctt/verPestanaGeneral.htm?idIniciativa=eni",
"https://administracionelectronica.gob.es/pae_Home/pae_Estrategias/pae_Interoperabilidad_Inicio/pae_Esquema_Nacional_de_Interoperabilidad.html"
],
"title" : "Informática - ENI",
"group" : "kyman_informatica_entornos_eni",
"group_variables" : {
"entidades" : ["select", [1, 5], "y", [
"{gobierno}", "Sector Público", "normalización", "regulación", "Administración Electrónica",
"Seguridad de la Información", "Redes de Comunicaciones", "Protección de Datos",
"Servicios en la Nube", "Ciberseguridad"
]],
"ONG" : ["rand", ["ONG", "Organizaciones No Gubernamentales"]],
"articulo_156" : ["plain", "comprende el conjunto de {mix:y,criterios|recomendaciones} en materia de {mix:y,seguridad|conservación|normalización} {mix:y,de la información|de los formatos|de las aplicaciones} que deberán ser tenidos en cuenta por las Administraciones Públicas para la toma de decisiones tecnológicas que garanticen operatibilidad"],
"leyes_mal_ley" : ["rand", [
"{rd_4_2010_ley}", "{l_11_2007_ley}", "{l_40_2015_ley}", "{l_30_1984_ley}", "{l_53_1984_ley}",
"{lo_2_1986_ley}", "{rdl_2_2015_ley}", "{d_315_1964_ley}", "{rd_364_1995_ley}", "{rd_365_1995_ley}"
]],
"leyes_mal_nombre" : ["rand", [
"{rd_4_2010_nombre}", "{l_11_2007_nombre}", "{l_40_2015_nombre}", "{l_30_1984_nombre}", "{l_53_1984_nombre}",
"{lo_2_1986_nombre}", "{rdl_2_2015_nombre}", "{d_315_1964_nombre}", "{rd_364_1995_nombre}", "{rd_365_1995_nombre}"
]],
"leyes_mal" : ["rand", [
"{leyes_mal_nombre}",
"{leyes_mal_ley}{rand:|, {leyes_mal_nombre}}"
]]
},
"queries" : [{
"question" : "¿Qué es el {rand:ENI|{RD} 4/2010{rand:|, de 8 de Enero}}?",
"rights" : [
"Esquema Nacional de Interoperabilidad.",
"Un conjunto de {mix:y,principios|recomendaciones} para garantizar la interoperabilidad entre las Administraciones Públicas{rand:| Españolas}.",
"Establece los {mix:y,principios|directrices} de interoperabilidad en el {mix:y,intercambio|conservación} de la información electrónica por parte de Administraciones Públicas{rand:| Españolas}."
],
"wrongs" : [
"Un {OS} utilizado por las Administraciones Públicas{rand:| Españolas}.",
"Un protocolo de comunicación entre dispositivos electrónicos{rand:| utilizado en las Administraciones Públicas{rand:| Españolas}}.",
"Una {VPN} para empleados públicos{rand:| en el marco de las Administraciones Públicas{rand:| Españolas}}."
]
}, {
"question" : "¿Para quién va dirigido el {ENI}?",
"own_variables" : {
"seleccion_incorrecta" : ["Select", [1, 4], "y", [
"las Entidades Privadas que colaboren con las Administraciones Públicas{rand:| Españolas}",
"las Empresas Tecnológicas que provean servicios a las Administraciones Públicas{rand:| Españolas}",
"los Ciudadanos que interactúen con las Administraciones Públicas{rand:| Españolas}",
"las {ONG} que trabajen con las Administraciones Públicas{rand:| Españolas}",
"la Administración General del Estado",
"las Comunidades Autónomas",
"las Provincias",
"las {rand:Entidades|Administraciones} Locales",
"las Autoridades{rand:| Competentes}",
"{mix:y,los Cuerpos|las Fuerzas} de Seguridad{rand:| del Estado}",
"las Administraciones Públicas",
"la Ciudadanía"
]]
},
"rights" : [
"Para todas las Administraciones Públicas{rand:| Españolas}.",
"Para los {mix:y,organismos|entidades} del sector público{rand:| Español}."
],
"wrongs" : ["{rand:Sólo p|Únicamente p|P}ara {seleccion_incorrecta}."]
}, {
"own_variables" : {
"lista_correcta" : ["list", [
"el Ministerio para la Transformación Digital y la Función Pública",
"la Secretaría del Estado de Función Pública",
"la Secretaría General de Administración Digital"
]],
"seleccion_incorrecta" : ["Select", [1, 4], "y", [
"list:lista_correcta",
"la Delegación de la Junta Autonómica delegada para la Transformación Digital",
"la Delegación Provincial destinada a la Transformación Digital",
"las Entidades Locales de {select:1-3,y,Gran Población|participantes en la Red SARA|con capacidad para Ventanilla Única}",
"los Órganos Empresariales que requieran comunicación con el Estado{rand:| Español}",
"las Entidades {select:1-2,y,Jurídicas|Físicas} que quieran operar en el Estado{rand:| Español}"
]]
},
"question" : "¿Quiénes son los responsables del {ENI}{rand:| en cada Administración Pública}?",
"rights" : ["{Mix:y,list:lista_correcta}."],
"wrongs" : [
"No hay un responsable {rand:específico|designado|único}{rand:|, depende del ámbito donde se encuentre su marco de aplicación|, depende de cada Comunidad Autónoma}.",
"{seleccion_incorrecta}."
]
}, {
"question" : "¿Qué tipo de solución es el {ENI}?",
"rights" : ["Regulación."],
"wrongs" : ["{Select:1-5,y,Red de comunicaciones|Plataforma de servicios|Aplicación web|Software|Hardware|Protocolo de comunicación|Intranet de Seguridad|Ley{rand:| Orgánica}|Estatuto|Impositivo}."]
}, {
"question" : "¿Qué relación tiene el {ENI} con el {ENS}?",
"rights" : [
"Ambos son Esquemas Nacionales que regulan aspectos diferentes pero complementarios en la Administración Electrónica.",
"El {ENI} se centra en la interoperabilidad, mientras que el {ENS} se enfoca en la seguridad de los sistemas de información."
],
"wrongs" : [
"{Mix:y,el {ENI}|el {ENS}} son lo mismo, ambos regulan la seguridad en la Administración Electrónica{rand:| dentro del marco de las Administraciones Públicas{rand:| Españolas}}.",
"El {ENI} es una versión anterior del {ENS}, y ha sido reemplazado por este último.",
"No tienen ninguna relación, ya que uno es para {mix:y,la Administración Pública|el otro para empresas privadas}.",
"No tienen ninguna relación entre sí pues abordan temas completamente diferentes{rand:|: mientras uno se centra en el ámbito de {rand:la Seguridad|la Segmentación|los Servicios|los Servidores}, el otro se centra en la {rand:Intranet|Internet|Interoperabilidad}.}"
]
}, {
"question" : "¿Qué normativa complementa al {rand:ENI|Esquema Nacional de Interoperabilidad} en materia de interoperabilidad?",
"rights" : ["{RD} 4/2010{rand:|, de 8 de Enero}{rand:|, por el que se regula el Esquema Nacional de Interoperabilidad en el ámbito de la Administración Electrónica}."],
"wrongs" : [
"{rand:{RD_RDL}|Ley{rand:| Orgánica}} {rand:4/2010|311/2022}{rand:|, de {rand:8|2} de {rand:Enero|Mayo}}{rand:|, por el que se regula el Esquema Nacional de Seguridad}.",
"{rand:{RD_RDL}|Ley{rand:| Orgánica}} {ley_base}{rand:|, por la que se regula el Esquema Nacional de {select:1-2,y,Seguridad|Interoperabilidad}}."
]
}, {
"question" : "¿Cuál es el estado actual del {ENI}?",
"rights" : ["En producción."],
"wrongs" : [
"En desarrollo.",
"En fase de pruebas.",
"Obsoleto.",
"En revisión.",
"En periodo de aplicación{rand:| provisional| voluntaria}."
]
}, {
"question" : "¿Cuál es el área orgánica del {ENI}?",
"rights" : "Estatal.",
"wrongs" : ["Autonómica.", "Local.", "Privada.", "Mixta.", "Provincial.", "Internacional.", "Intereuropea."]
}, {
"question" : "¿Cuál es el ámbito funcional del {ENI}?",
"rights" : ["Administración Electrónica."],
"wrongs" : ["{Cap:{entidades}}."]
}, {
"question" : "¿Cuál es el área técnica del {ENI}?",
"rights" : ["{Mix:y,normalización|regulación}."],
"wrongs" : ["{Cap:{entidades}}."]
}, {
"question" : "¿Cuál es el área funcional del {ENI}?",
"rights" : ["{Mix:y,{gobierno}|Sector Público}."],
"wrongs" : ["{Cap:{entidades}}."]
}, {
"own_variables" : {
"respuesta_falsa" : ["Select", [1, 4], "y", [
"proporcionar un marco legal para la creación de nuevas tecnologías en el ámbito público",
"regular el uso de tecnologías específicas en las Administraciones Públicas{rand:| Españolas}",
"establecer un sistema de seguridad para proteger los datos de los ciudadanos en las Administraciones Públicas{rand:| Españolas}",
"crear una red de comunicaciones exclusiva para las Administraciones Públicas{rand:| Españolas}"
]]
},
"question" : "¿Cuál es la motivación por la cual se creó el {ENI}?",
"rights" : ["Ofrecer a los ciudadanos {mix:y,fluidez|eficacia|eficiencia} para garantizarles los {mix:y,derechos|principios}{rand:| mediante la cooperación entre las administraciones{rand:| con {mix:y,el desarrollo|la prestación|el despliegue} de servicios públicos}}."],
"wrongs" : ["{respuesta_falsa}."]
}, {
"own_variables" : {
"articulos_incorrectos" : ["rand", [
"Objeto", "Ámbito Subjetivo", "Principios Generales",
"Principios de intervención de las Administraciones Públicas para el desarrollo de una actividad"
]]
},
"question" : "¿Qué artículo de la {l_40_2015} incluye a la Interoperabilidad como principio de actuación de las Administraciones Públicas?",
"rights" : ["El artículo 3{rand:|, Principios Generales}."],
"wrongs" : ["El artículo {range:1-23}{rand:|, {articulos_incorrectos}}."]
}, {
"own_variables" : {
"garantias" : ["mix", "y", [
"la {mix:y,interoperabilidad|seguridad} de {mix:y,los sistemas|las soluciones} adoptados por cada una de ellas",
"la protección de los datos de carácter personal",
"el facilitar preferentemente la prestación conjunta de servicios a los interesados"
]]
},
"question" : "¿Qué nos dice el principio de actuación{rand:| en el artículo 3{rand:|, Principios Generales}} de la {l_40_2015}?",
"rights" : ["Las Administraciones Públicas estarán relacionadas entre sí a través de medios electrónicos{rand: que {rand:|garanticen|aseguren}|, {rand:asegurando|garantizando}} {garantias}."],
"wrongs" : ["Las Administraciones Públicas {rand:{rand:deberían|podrán}|estarán relacionadas entre sí a través de} utilizar medios electrónicos{rand: que {rand:|garanticen|aseguren}|, {rand:asegurando|garantizando}, sin necesidad de garantizar} {select:1-2,y,la interoperabilidad|la seguridad de los datos}{rand:| si así lo consideran oportuno| únicamente}."]
}, {
"own_variables" : {
"articulos_incorrectos" : ["rand", [
"Transparencia de tecnología entre Administraciones",
"Reutilización de {select:1-2,y,sistemas|aplicaciones} de propiedad de la Administración",
"{select:1-2,y,{eni_nombre}|{ens_nombre}}",
"Transmisiones de datos entre Administraciones Públicas"
]]
},
"question" : "¿Qué artículo de la {l_40_2015} {articulo_156}?",
"rights" : "El artículo 156{rand:|, {mix:y,{eni_nombre}|{ens_nombre}}}.",
"wrongs" : ["El artículo {rand:{range:155-158}|{range:1-300}}{rand:|, {articulos_incorrectos}}."]
}, {
"question" : "¿Qué nos dice el artículo 156{rand:|, {mix:y,{eni_nombre}|{ens_nombre}}} de la {l_40_2015}?",
"rights" : ["{Cap:{articulo_156}}."],
"wrongs" : [
"Establece que las Administraciones Públicas deben utilizar medios electrónicos para garantizar la interoperabilidad entre ellas.",
"Regula la creación de nuevas tecnologías en el ámbito público.",
"Establece un sistema de seguridad para proteger los datos de los ciudadanos en las Administraciones Públicas{rand:| Españolas}.",
"Crea una red de comunicaciones exclusiva para las Administraciones Públicas{rand:| Españolas}.",
"Comprende el conjunto de {select:1-3,y,criterios|recomendaciones|malas prácticas} en materia de {select:1-5,y,seguridad|conservación|normalización|digitalización|codificación|encriptación} {mix:y,de la información|de los formatos|de las aplicaciones} que deberán ser evitados por las Administraciones Públicas para la toma de decisiones tecnológicas que garanticen operatibilidad."
]
}, {
"own_variables" : {
"articulos_incorrectos" : ["rand", [
"Interoperabilidad de los Sistemas de Información",
"{mix:y,{eni_nombre}|{ens_nombre}}",
"Red de comunicaciones de las Administraciones Públicas españolas",
"Red integrada de Atención al Ciudadano"
]]
},
"question" : "¿En dónde fue establecido el {ENI} originalmente?",
"rights" : ["En el artículo {rand:42|{mix:y,{eni_nombre}|{ens_nombre}}} de la {l_11_2007}."],
"wrongs" : ["En el artículo {rand:{range:41-44}|{range:1-60}|{articulos_incorrectos}} {rand:de la {rand:{l_11_2007}|{l_40_2015}}|del {rd_4_2010}}."]
}, {
"question" : "¿En dónde fue materializado el {ENI}?",
"rights" : ["En {rd_4_2010}."],
"wrongs" : ["En {leyes_mal}."]
}, {
"question" : "¿Cuál es la finalidad de las {NTI} del {ENI}?",
"rights" : ["Concretar detalles para facilitar los aspectos más {mix:y,prácticos|operativos} de la interoperabilidad {mix:y,entre las Administraciones Públicas|con el ciudadano}."],
"wrongs" : [
"Establecer un marco legal para la creación de nuevas tecnologías en el ámbito público.",
"Regular el uso de tecnologías específicas {select:1-2,y,entre las Administraciones Públicas{rand: Españolas}|con los ciudadanos}.",
"Establecer un sistema de seguridad para proteger los datos de los ciudadanos en las Administraciones Públicas{rand: Españolas}.",
"Crear una red de comunicaciones exclusiva para las Administraciones Públicas{rand: Españolas}."
]
}, {
"question" : "¿Quién desarrolló el {ENI}?",
"rights" : ["El Ministerio de {mix:y,Política Territorial|Función Pública}."],
"wrongs" : [
"El Ministerio de {select:1-3,y,Seguridad|Defensa|de Transición Tecnológica}.",
"La Agencia Española de Protección de Datos.",
"El Instituto Nacional de Ciberseguridad.",
"La Secretaría de Estado de Digitalización e Inteligencia Artificial."
]
}, {
"question" : "¿Cuáles son los objetivos del {ENI}?",
"own_variables" : {
"objetivos" : ["lista", [
"comprender {mix:y,los criterios|las recomendaciones}",
"proporcionar los elementos",
"facilitar la implantación de las políticas de seguridad"
]]
},
"rights" : ["{Mix:y,list:objetivos}."],
"wrongs" : ["{Select:1-5,y,list:objetivos|garantizar conectivdad entre los sectores {mix:y,público|privado}|establecer un sistema de seguridad para proteger los datos de los ciudadanos|crear una red de comunicaciones exclusiva para las Administraciones Públicas}."]
}, {
"question" : "¿Cuáles son los elementos principales del {eni_nombre}?",
"own_variables" : {
"elementos" : ["list", [
"los principios básicos de la interoparagerabilidad",
"la interoperabilidad organizativa",
"la interoperabilidad semántica",
"la interoperabilidad técnica",
"{mix:y,las infraestructuras|los servicios} comunes",
"la utilización, preferiblemente, de la Red de comunciaciones de las Administraciones Públicas",
"la reutilización",
"la interoperabilidad {mix:y,de la firma electrónica|de los certificados}",
"la {mix:y,recuperación|conservación} del documento electrónico",
"las normas técnicas de interoperabilidad"
]],
"elementos_mal" : ["list", [
"la creación de nuevas tecnologías en el ámbito público",
"el uso de tecnologías específicas en las Administraciones Públicas",
"el establecimiento de un sistema de seguridad para proteger los datos de los ciudadanos",
"la creación de una red de comunicaciones exclusiva para las Administraciones Públicas",
"la implementación de software propietario en las Administraciones Públicas",
"la centralización de todos los datos en un único servidor nacional",
"la eliminación de la interoperabilidad entre diferentes sistemas",
"la reducción de la seguridad en los sistemas de información",
"la limitación del acceso a los servicios públicos digitales",
"la desactualización tecnológica de las infraestructuras públicas",
"la falta de formación del personal público en tecnologías de la información"
]]
},
"rights" : ["{Mix:y,list:elementos}."],
"wrongs" : ["{Select:1-12,y,list:elementos|list:elementos_mal}."]
}, {
"own_variables" : {
"leyes_mal" : ["select", [1, 4], "y", [
"de la {l_39_2015}",
"de la {l_40_2015}",
"del {rd_4_2010}",
"de la {l_53_1984}",
"de la {l_30_1984}",
"de la {l_11_2007}",
"de la {lo_2_1986}"
]],
"bien" : ["list", [
"el ámbito subjetivo",
"lo indicado sobre el sector público institucional"
]],
"mal" : ["list", [
"el ámbito territorial",
"lo indicado sobre el área orgánica"
]]
},
"question" : "¿En dónde se establece el ámbito de aplicación del {ENI}?",
"rights" : ["En el artículo 2 de {mix:y,la {l_39_2015}|la {l_40_2015}}{rand:|, sobre {mix:y,list:bien}}."],
"wrongs" : ["En {rand:el artículo {rand:{range:1-100}}|los artículos {select:1-5,y,{serie:1-100}|{serie:1-100}|{serie:1-100}|{serie:1-100}|{serie:1-100}}} {leyes_mal}{rand:|, sobre {mix:y,list:bien|list:mal}}."]
}, {
"own_variables" : {
"categorias" : ["list", [
"marco organizativo",
"marco operacional",
"medidas técnicas"
]]
},
"question" : "¿Cuáles son las categorías por las que se fundamenta la adecuación del {ENI}?",
"rights" : ["{Mix:y,list:categorias}."],
"wrongs" : ["{Select:1-5,y,list:categorias|marco legal|marco financiero|marco estratégico|marco tecnológico|marco social}."]
}]
}]

View File

@ -0,0 +1,40 @@
[{
"origin" : "KyMAN",
"sources" : [
"https://administracionelectronica.gob.es/ctt/verPestanaGeneral.htm?idIniciativa=eni",
"https://administracionelectronica.gob.es/pae_Home/pae_Estrategias/pae_Interoperabilidad_Inicio/pae_Esquema_Nacional_de_Interoperabilidad.html",
"https://administracionelectronica.gob.es/dam/jcr:85ca4b29-f229-413c-a533-a290bdb7bec6/ENI_Preguntas_frecuentes.pdf",
"https://administracionelectronica.gob.es/pae_Home/dam/jcr:c00307e0-1337-4b25-9728-d101c059cd3a/20131208_ENI_Preguntas_frecuentes.pdf"
],
"title" : "Informática - ENI - Preguntas Frecuentes",
"group" : "kyman_informatica_entornos_eni",
"group_variables" : {},
"queries" : [{
"question" : "¿Qué es el {ENI}?",
"rights" : [
"El {rd_4_2010}, regula el citado Esquema previsto en el artículo 156 de la {l_40_2015}, que sustituye al apartado 1 del artículo 42 de la {l_11_2007}.",
"Comprende el conjunto de {mix:y,criterios|recomendaciones} que deberían ser tenidos en cuenta por las {AAPP} para la toma de decisiones tecnológicas que garanticen la interoperabilidad.",
"La cooperación entre las {AAPP} es esencial para proporcionar los servicios a los ciudadanos y garantizarles su derecho a relacionarse electrónicamente con ellas. Dicha cooperación requiere unas condiciones tales que permitan que la misma se pueda llevar a cabo con fluidez, para lo cual es necesario que haya interoperabilidad.",
"El Esquema persigue la creación de las condiciones necesarias para garantizar nivel de interoperabilidad {mix:y,técnica|semántica|organizativa} de {mix:y,los sistemas|las aplicaciones} empleados por las {AAPP}, que permitan {mix:y,el ejercicio de los derechos|el cumplimiento de los deberes} a través del acceso electrónico a los servicios públicos, a la vez que redunda en beneficio de {mix:y,la eficacia|la eficiencia}.",
"Es el marco legal y técnico que define las normas para que los sistemas de información de las distintas {AAPP} españolas puedan comunicarse e intercambiar datos entre sí.",
"Un conjunto de criterios y recomendaciones (técnicos, semánticos y organizativos) que aseguran que las aplicaciones informáticas del sector público sean compatibles.",
"La normativa, recogida en el {rd_4_2010}, que permite la cooperación entre {AAPP} a nivel digital, facilitando la vida al ciudadano.",
"Es la estrategia del Estado para evitar que cada organismo público ({select:1-3,y,ministerios|ayuntamientos|{CCAA}|provincias} entre otros) desarrolle sistemas aislados que no pueden 'hablar' entre ellos.",
"Una pieza clave de la Administración electrónica que garantiza, por ejemplo, que un ciudadano no tenga que presentar un documento en un organismo si este ya obra en poder de otro.",
"Define los estándares comunes (como {mix:o,formatos de documento|firma electrónica|modelos de datos}) que debe usar el sector público para garantizar la compatibilidad."
],
"wrongs" : [
"El {rand:{rd_4_2010}|{rdl_2_2015}|{d_315_1964}|{rd_364_1995}|{rd_365_1995}}, regula el citado Esquema previsto en el artículo {range:1-200} de la {rand:{l_11_2007}|{l_40_2015}|{l_30_1984}|{l_53_1984}}, que sustituye al apartado {range:1-7} del artículo {range:1-200} de la {rand:{l_11_2007}|{l_40_2015}|{l_30_1984}|{l_53_1984}}.",
"Es un conjunto de normas jurídicas que regulan la seguridad de los sistemas de información de las {AAPP}.",
"Es un marco normativo que establece los requisitos mínimos de seguridad para los sistemas de información de las {AAPP}.",
"Es un conjunto de directrices para la gestión de la seguridad de la información en las {AAPP}.",
"Es el {ENS}, una normativa complementaria que establece las medidas de índole {select:1-2,y,técnica|organizativa} necesarias para proteger los sistemas de información de ciberataques, robos de datos y otras amenazas digitales.",
"Una directiva de la {EU}, de obligado cumplimiento para todos los estados miembros, que regula {select:1-3,y,el mercado único digital|el comercio electrónico transfronterizo|la portabilidad de servicios de streaming} entre países.",
"Un programa de software específico, similar a {select:1-2,o,un {OS}|un antivirus avanzado}, que el {rand:{gobierno}|Gobierno central} obliga a instalar en todos los servidores de las {AAPP} para centralizar la gestión de las bases de datos.",
"El organismo público, dependiente del Ministerio de {select:1-2,y,Asuntos Económicos|Transformación Digital}, que se encarga de gestionar {select:1-3,y,la red de fibra óptica nacional|{Red_SARA}|de auditar la ciberseguridad de las entidades{rand:| {select:1-3,y,locales|nacionales|provinciales|autonómicas|estatales|públicas|privadas}}}.",
"El {rgpd} en España, enfocada exclusivamente en {select:1-2,y,la privacidad del ciudadano|el derecho al olvido}.",
"Un plan del {gobierno} para fomentar la internacionalización de las empresas tecnológicas españolas, facilitando su expansión a mercados latinoamericanos.",
"El portal web oficial donde los ciudadanos pueden {select:1-2,y,consultar todas las leyes publicadas en el {BOE}|acceder al Punto de Acceso General (administracion.gob.es) para realizar trámites}."
]
}]
}]

View File

@ -0,0 +1,10 @@
[{
"origin" : "KyMAN",
"sources" : [
"https://administracionelectronica.gob.es/pae_Home/pae_Estrategias/pae_Seguridad_Inicio/pae_Esquema_Nacional_de_Seguridad.html"
],
"title" : "Informática - ENS",
"group" : "kyman_informatica_entornos_ens",
"group_variables" : {},
"queries" : []
}]

View File

@ -431,6 +431,7 @@
"AI_DL" : ["rand", ["DL", "Deep Learning", "Aprendizaje Profundo"]], "AI_DL" : ["rand", ["DL", "Deep Learning", "Aprendizaje Profundo"]],
"AI_CV" : ["rand", ["CV", "Computer Vision", "Visión por Computadora"]], "AI_CV" : ["rand", ["CV", "Computer Vision", "Visión por Computadora"]],
"AI_RL" : ["rand", ["RL", "Reinforcement Learning", "Aprendizaje por Refuerzo"]], "AI_RL" : ["rand", ["RL", "Reinforcement Learning", "Aprendizaje por Refuerzo"]],
"TTL" : ["rand", ["TTL", "Time to Live", "Tiempo de Vida"]],
"broadcast" : ["rand", ["Broadcast", "Difusión"]], "broadcast" : ["rand", ["Broadcast", "Difusión"]],
"multicast" : ["rand", ["Multicast", "Multidifusión"]], "multicast" : ["rand", ["Multicast", "Multidifusión"]],
@ -470,6 +471,40 @@
"Red_SARA_a" : ["rand", ["a la Red SARA", "al Sistema de Aplicaciones y Redes para las Administraciones"]], "Red_SARA_a" : ["rand", ["a la Red SARA", "al Sistema de Aplicaciones y Redes para las Administraciones"]],
"Red_IA" : ["rand", ["Red IA", "Intranet Administrativa"]], "Red_IA" : ["rand", ["Red IA", "Intranet Administrativa"]],
"sTESTA" : ["rand", ["sTESTA", "Secured Trans European Services for Telematics between Administrations", "Servicios Telemáticos Seguros Trans Europeos entre Administraciones"]], "sTESTA" : ["rand", ["sTESTA", "Secured Trans European Services for Telematics between Administrations", "Servicios Telemáticos Seguros Trans Europeos entre Administraciones"]],
"RedIRIS" : ["rand", ["RedIRIS", "Red de la Infraestructura de Investigación y Educación Española"]] "RedIRIS" : ["rand", ["RedIRIS", "Red de la Infraestructura de Investigación y Educación Española"]],
"ENI" : ["rand", ["ENI", "Esquema Nacional de Interoperabilidad", "{RD} 4/2010{rand:|, de 8 de Enero}{rand:|, por el que se regula el Esquema Nacional de Interoperabilidad en el ámbito de la Administración Electrónica}"]],
"ENS" : ["rand", ["ENS", "Esquema Nacional de Segridad", "{RD} 311/2022{rand:|, de 2 de Mayo}{rand:|, por el que se regula el Esquema Nacional de Seguridad}"]],
"NTI" : ["rand", ["NTI", "Norma Técnica de Interoperabilidad"]],
"osi1" : ["rand", [
"Capa {rand:de Física|1} del Modelo {OSI}",
"Capa {rand:de Acceso al Medio|del Medio|1} del Modelo {TCP_IP}"
]],
"osi2" : ["rand", [
"Capa {rand:de Enlace{rand:| de Red}|2} del Modelo {OSI}",
"Capa {rand:de Acceso al Medio|del Medio|1} del Modelo {TCP_IP}"
]],
"osi3" : ["rand", [
"Capa {rand:de Red|3} del Modelo {OSI}",
"Capa {rand:de Internet|Network|2} del Modelo {TCP_IP}"
]],
"osi4" : ["rand", [
"Capa {rand:de Transporte|4} del Modelo {OSI}",
"Capa {rand:de Transporte|3} del Modelo {TCP_IP}"
]],
"osi5" : ["rand", [
"Capa {rand:de Sesión|5} del Modelo {OSI}",
"Capa {rand:de Aplicación|4} del Modelo {TCP_IP}"
]],
"osi6" : ["rand", [
"Capa {rand:de Presentación|6} del Modelo {OSI}",
"Capa {rand:de Aplicación|4} del Modelo {TCP_IP}"
]],
"osi7" : ["rand", [
"Capa {rand:de Aplicación|7} del Modelo {OSI}",
"Capa {rand:de Aplicación|4} del Modelo {TCP_IP}"
]]
} }
}] }]

View File

@ -0,0 +1,69 @@
[{
"origin" : "KyMAN",
"sources" : [],
"title" : "Software - Comando Ping",
"group" : "kyman_software_comando_ping",
"queries" : [{
"question" : "¿Qué es el comando ping?",
"rights" : [
"Es una herramienta de red utilizada para comprobar la conectividad entre dos dispositivos en una red {IP}.",
"Funciona enviando paquetes {ICMP} de solicitud de eco a la dirección {IP} de destino y esperando una respuesta de eco.",
"Mide el tiempo que tarda en recibir una respuesta, lo que ayuda {mix:y,a diagnosticar problemas de red|a determinar la latencia entre los dispositivos}.",
"Es comúnmente utilizado por {select:1-2,y,administradores de red|usuarios} para verificar si un host está {mix:y,accesible|funcionando correctamente}."
],
"wrongs" : [
"Es una herramienta de edición de texto utilizada para {select:1-2,y,crear|modificar} archivos de configuración de red.",
"Es un protocolo de seguridad utilizado para proteger las comunicaciones en redes inalámbricas.",
"Es una aplicación de monitoreo de red que proporciona estadísticas detalladas sobre el tráfico de datos en tiempo real."
]
}, {
"question" : "¿En qué capa de red trabaja el comando ping?",
"rights" : ["En la {osi3}{rand:|, ya que utiliza el protocolo {ICMP} para {mix:y,enviar|recibir} mensajes entre dispositivos}."],
"wrongs" : [
"En la {osi7}, ya que se utiliza para {mix:y,interactuar con servicios de red|gestionar conexiones de red}.",
"En la {osi6}, ya que se encarga de la representación y codificación de datos para la transmisión.",
"En la {osi5}, ya que se encarga de la negociación de sesiones entre dispositivos en una red.",
"En la {osi4}, ya que se encarga de {select:1-2,y,la gestión de conexiones|el control de flujo} entre dispositivos.",
"En la {osi2}, ya que se encarga de la transmisión de datos entre dispositivos en una red local.",
"En la {osi1}, ya que se ocupa de la transmisión {select:1-2,o,de señales eléctricas|de radio} entre dispositivos."
]
}]
}, {
"origin" : "KyMAN",
"sources" : [],
"title" : "Software - Comando Ping",
"group" : "kyman_software_comando_ping",
"queries" : [{
"question" : "¿Qué hace el parámetro {rand:{rand:-|/}i en Windows|-t en Linux} en el comando ping?",
"rights" : ["Establece el {TTL}{rand:| de los paquetes enviados {ICMP}}."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro {rand:-|/}t en Windows en el comando ping?",
"rights" : ["Hace que el comando ping envíe paquetes {ICMP} de forma continua hasta que se interrumpa manualmente."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro {rand:{rand:-|/}n en Windows|-c en Linux} en el comando ping?",
"rights" : ["Especifica el número de paquetes {ICMP} que se enviarán durante la prueba de ping."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro {rand:{rand:-|/}l en Windows|-s en Linux} en el comando ping?",
"rights" : ["Especifica el tamaño, en bytes, de los paquetes {ICMP} que se enviarán."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro {rand:{rand:-|/}a en Windows|-a en Linux} en el comando ping?",
"rights" : ["Resuelve y muestra el nombre de host asociado a la dirección {IP} de destino."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro -4 en el comando ping?",
"rights" : ["Fuerza al comando ping a utilizar la {IPv4} para la comunicación."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro -6 en el comando ping?",
"rights" : ["Fuerza al comando ping a utilizar la {IPv6} para la comunicación."],
"brothers_are_wrongs" : true
}, {
"question" : "¿Qué hace el parámetro {rand:-|/}w en el comando ping?",
"rights" : ["Especifica el tiempo de espera, en milisegundos, para recibir una respuesta antes de considerar que el paquete se ha perdido."],
"brothers_are_wrongs" : true
}]
}]

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Callable
from Interfaces.OpoTestsInterface import OpoTestsInterface
from Models.RequestModel import RequestModel
class ControllersAbstract:
def __init__(self:Self,
ot:OpoTestsInterface,
actions:dict[str, Callable[[RequestModel], tuple[Any|None, dict[str, Any|None]]]]
) -> None:
self.ot:OpoTestsInterface = ot
self.__actions:dict[str, Callable[[RequestModel], tuple[Any|None, dict[str, Any|None]]]] = actions
def add(self:Self, key:str, action:Callable[[RequestModel], tuple[Any|None, dict[str, Any|None]]], overwrite:bool = False) -> None:
if overwrite or key not in self.__actions:
self.__actions[key] = action
def get(self:Self,
key:str,
request:RequestModel
) -> tuple[Any|None, dict[str, Any|None]]|None:
return self.__actions[key](request) if key in self.__actions else None

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional from typing import Self, Any, Optional
from Managers.SettingsManager import SettingsManager from Managers.SettingsManager import SettingsManager
@ -7,6 +8,12 @@ from Drivers.HTTPSocketDriver import HTTPSocketDriver
from Drivers.FilesDriver import FilesDriver from Drivers.FilesDriver import FilesDriver
from traceback import format_stack as trace_format_stack from traceback import format_stack as trace_format_stack
from traceback import extract_tb as extract_traceback from traceback import extract_tb as extract_traceback
from Managers.QuestionsManager import QuestionsManager
from Managers.UsersManager import UsersManager
from Modules.FormatModule import FormatModule
from Managers.ControllersManager import ControllersManager
from Managers.RoutesManager import RoutesManager
from Utils.Check import Check
from Utils.Patterns import RE from Utils.Patterns import RE
from Utils.Utils import Utils from Utils.Utils import Utils
from datetime import datetime from datetime import datetime
@ -16,6 +23,8 @@ class OpoTests:
def __init__(self:Self, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None) -> None: def __init__(self:Self, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None) -> None:
key:str
self.__print_format:str = "[{type}] {yyyy}{mm}{dd} {hh}{ii}{ss} [{line}]{file}({method}): {message}" self.__print_format:str = "[{type}] {yyyy}{mm}{dd} {hh}{ii}{ss} [{line}]{file}({method}): {message}"
self.__exception_format:str = " '{file}({method})[{line}]'{lines}\n\n{exception_message}" self.__exception_format:str = " '{file}({method})[{line}]'{lines}\n\n{exception_message}"
@ -27,10 +36,22 @@ class OpoTests:
self.i18n:I18NManager = I18NManager(self) self.i18n:I18NManager = I18NManager(self)
self.files:FilesDriver = FilesDriver(self) self.files:FilesDriver = FilesDriver(self)
self.http_server:HTTPSocketDriver = HTTPSocketDriver(self) self.http_server:HTTPSocketDriver = HTTPSocketDriver(self)
self.users:UsersManager = UsersManager(self)
self.questions:QuestionsManager = QuestionsManager(self)
self.format:FormatModule = FormatModule(self)
self.controllers:ControllersManager = ControllersManager(self)
self.routes:RoutesManager = RoutesManager(self)
self.http_server.start() for key in ("settings", "i18n", "files", "users", "questions", "format", "controllers", "routes", "http_server"):
getattr(getattr(self, key), "start")()
def print(self:Self, _type:str, string:str, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, default_message:str = None, i:int = 0) -> None: def print(self:Self,
_type:str,
string:str,
inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None,
default_message:str = None,
i:int = 0
) -> None:
date:datetime = datetime.now() date:datetime = datetime.now()
own:dict[str, Any|None] = { own:dict[str, Any|None] = {
@ -54,6 +75,9 @@ class OpoTests:
own["yyyy"] = ("0000" + str(own["year"]))[-4:] own["yyyy"] = ("0000" + str(own["year"]))[-4:]
if "end" in own:
own["message"] += own["end"]
print(Utils.string_variables(self.__print_format, own)) print(Utils.string_variables(self.__print_format, own))
def exception(self, def exception(self,
@ -84,4 +108,27 @@ class OpoTests:
data["end"] = Utils.string_variables(self.__exception_format, data) data["end"] = Utils.string_variables(self.__exception_format, data)
message and self.print("exception", message, data, i + 1) message and self.print("exception", message, data, None, i + 1)
def load_json_data(self:Self,
inputs:Optional[str|dict[str, Any|None]|list[Any|None]|tuple[Any|None]],
only_dictionaries:bool = True
) -> list[dict[str, Any|None]|list[Any|None]|tuple[Any|None]]:
json_items:list[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = []
if Check.is_dictionary(inputs):
json_items += [inputs]
elif Check.is_array(inputs):
if only_dictionaries:
for item in inputs:
if Check.is_dictionary(item):
json_items += [item]
else:
json_items += self.load_json_data(item, only_dictionaries)
else:
json_items += [inputs]
elif Check.is_string(inputs):
json_items += self.load_json_data(Utils.json_decode(inputs) or self.files.load(inputs, True), only_dictionaries)
return json_items

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Abstracts.ControllersAbstract import ControllersAbstract
from Interfaces.OpoTestsInterface import OpoTestsInterface
from Models.RequestModel import RequestModel
from typing import Any, Self
class TestController(ControllersAbstract):
def __init__(self:Self, ot:OpoTestsInterface) -> None:
super().__init__(ot, {
"ping": self.ping
})
def ping(self:Self, request:RequestModel) -> tuple[Any|None, dict[str, Any|None]]:
return ("pong", {"mime" : "text/plain"})

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self from typing import Self
from Interfaces.OpoTestsInterface import OpoTestsInterface from Interfaces.OpoTestsInterface import OpoTestsInterface
@ -21,6 +22,9 @@ class FilesDriver:
mimetypes.init() mimetypes.init()
def start(self:Self) -> None:
pass
def fix_path(self:Self, path:str) -> str: def fix_path(self:Self, path:str) -> str:
return RE.SLASHES.sub(self.__slash, path) return RE.SLASHES.sub(self.__slash, path)
@ -36,13 +40,13 @@ class FilesDriver:
return absolute_path return absolute_path
return None return None
def load(self:Self, path:str) -> bytes|None: def load(self:Self, path:str, as_string:bool = False) -> bytes|str|None:
absolute:str = self.get_absolute_path(path) absolute:str = self.get_absolute_path(path)
if absolute and is_file(absolute): if absolute and is_file(absolute):
try: try:
with open(absolute, "rb") as file: with open(absolute, "r" if as_string else "rb") as file:
return file.read() return file.read()
except Exception as exception: except Exception as exception:
print(["files_load", exception]) print(["files_load", exception])

View File

@ -1,28 +1,40 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from threading import Thread from threading import Thread
from typing import Any, Self, Optional from typing import Any, Self, Optional
from Interfaces.OpoTestsInterface import OpoTestsInterface from Interfaces.OpoTestsInterface import OpoTestsInterface
from Models.RequestModel import RequestModel
from socket import socket as Socket from socket import socket as Socket
from socket import AF_INET as ADDRESS_FAMILY_IPV4 from socket import AF_INET as ADDRESS_FAMILY_IPV4
from socket import SOCK_STREAM as SOCKET_STREAM from socket import SOCK_STREAM as SOCKET_STREAM
from socket import SOL_SOCKET as SOCKET_LAYER from socket import SOL_SOCKET as SOCKET_LAYER
from socket import SO_REUSEADDR as SOCKET_REUSE_ADDRESS from socket import SO_REUSEADDR as SOCKET_REUSE_ADDRESS
from Utils.Patterns import RE from Utils.Utils import Utils
from Utils.Check import Check
class HTTPSocketDriver: class HTTPSocketDriver:
def __init__(self:Self, ot:OpoTestsInterface, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list] = None) -> None: def __init__(self:Self, ot:OpoTestsInterface, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list] = None) -> None:
self.ot:OpoTestsInterface = ot self.ot:OpoTestsInterface = ot
self.__inputs:dict[str, Any|None] = Utils.get_dictionary(inputs)
self.__socket:Socket|None = None self.__socket:Socket|None = None
self.__address:str = self.ot.settings.get(("address", "http_address"), inputs, "localhost") self.__address:str = "localhost"
self.__port:int = self.ot.settings.get(("port", "http_port"), inputs, 8080) self.__port:int = 8080
self.__maximum_connections:int = self.ot.settings.get(("maximum_connections", "http_maximum_connections"), inputs, 5) self.__maximum_connections:int = 5
self.__cache_size:int = self.ot.settings.get(("cache_size", "http_cache_size"), inputs, 1024) self.__cache_size:int = 1024
self.__public_path:str = self.ot.settings.get(("public_path", "http_public_path"), inputs, "/Public") self.__public_path:str = "/Public"
self.__index_files:list[str] = ["index.html", "index.htm"]
self.__working:bool = False self.__working:bool = False
def update(self:Self) -> None:
self.__address = self.ot.settings.get(("address", "http_address"), self.__inputs, self.__address)
self.__port = self.ot.settings.get(("port", "http_port"), self.__inputs, self.__port)
self.__maximum_connections = self.ot.settings.get(("maximum_connections", "http_maximum_connections"), self.__inputs, self.__maximum_connections)
self.__cache_size = self.ot.settings.get(("cache_size", "http_cache_size"), self.__inputs, self.__cache_size)
self.__public_path = self.ot.settings.get(("public_path", "http_public_path"), self.__inputs, self.__public_path)
self.__index_files = self.ot.settings.get(("index_files", "http_index_files"), self.__inputs, self.__index_files)
def __listen(self:Self) -> None: def __listen(self:Self) -> None:
while self.__working: while self.__working:
try: try:
@ -31,6 +43,8 @@ class HTTPSocketDriver:
address:str address:str
port:int port:int
data:bytes = b"" data:bytes = b""
response:Any|None
parameters:dict[str, Any|None]
client, (address, port) = self.__socket.accept() client, (address, port) = self.__socket.accept()
@ -42,21 +56,34 @@ class HTTPSocketDriver:
if len(buffer) < self.__cache_size: if len(buffer) < self.__cache_size:
break break
file_data:bytes|None response, parameters = self.ot.routes.go(RequestModel(data.decode("utf-8"), {
"address" : address,
"port" : port,
"client" : client,
"public_path" : self.__public_path,
"index_files" : ["", *self.__index_files]
}))
for index in ("", "/index.html", "/index.htm"): client.sendall(
str(Utils.string_variables((
"{http_protocol}/{http_version} {http_code} {http_message}\r\n" +
"Content-Type: {mime}"
), {
"http_protocol" : "HTTP",
"http_version" : "1.1",
"http_code" : 200,
"http_message" : "OK",
"mime" : "text/plain",
**parameters
})).encode("utf-8") +
b"\r\n\r\n" +
(
str(response).encode("utf-8") if Check.is_string(response) else
response if Check.is_bytes(response) else
Utils.json_encode(response).encode("utf-8") if Check.is_json_object(response) else
bytes(response))
)
path:str = self.__public_path + RE.LINE.match(data.decode("utf-8")).group(1).split(" ")[1] + index
file_data = self.ot.files.load(path)
if file_data is not None:
break
if not file_data:
client.sendall(b"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\n\r\n404 Not Found")
else:
client.sendall(b"HTTP/1.1 200 OK\r\nContent-Type: " + self.ot.files.get_mime(path).encode("utf-8") + b"\r\n\r\n" + file_data)
client.close() client.close()
except Exception as exception: except Exception as exception:
@ -70,6 +97,8 @@ class HTTPSocketDriver:
self.__working = True self.__working = True
self.__socket = Socket(ADDRESS_FAMILY_IPV4, SOCKET_STREAM) self.__socket = Socket(ADDRESS_FAMILY_IPV4, SOCKET_STREAM)
self.update()
try: try:
self.__socket.setsockopt(SOCKET_LAYER, SOCKET_REUSE_ADDRESS, 1) self.__socket.setsockopt(SOCKET_LAYER, SOCKET_REUSE_ADDRESS, 1)

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Callable
class ControllersAbstractInterface:
def add(self:Self, key:str, action:Callable[[
dict[str, Any|None],
dict[str, Any|None]
], Any|None], overwrite:bool = False) -> None:pass
def get(self:Self,
action:str,
variables:dict[str, Any|None],
inputs:dict[str, Any|None]
) -> Any|None:pass

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Callable
from Interfaces.ControllersAbstractInterface import ControllersAbstractInterface
class ControllersManagerInterface:
def start(self:Self) -> None:pass
def add(self:Self, inputs:str|ControllersAbstractInterface|list|tuple, overwrite:bool = False) -> None:pass
def get(self:Self, key:str, action:str) -> Callable[[
dict[str, Any|None],
dict[str, Any|None]
], Any|None]|None:pass

View File

@ -1,13 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self from typing import Self
class FilesDriverInterface: class FilesDriverInterface:
def start(self:Self) -> None:pass
def fix_path(self:Self, path:str) -> str:pass def fix_path(self:Self, path:str) -> str:pass
def get_absolute_path(self:Self, path:str) -> str|None:pass def get_absolute_path(self:Self, path:str) -> str|None:pass
def load(self:Self, path:str) -> bytes|None:pass def load(self:Self, path:str, as_string:bool = False) -> bytes|str|None:pass
def get_mime(self:Self, path:str) -> str|None:pass def get_mime(self:Self, path:str) -> str|None:pass

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.FormatModuleInterface import FormatModuleInterface
from typing import Any, Self, Optional
class FormatModeInterface:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:pass
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:pass
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:pass

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.OpoTestsInterface import OpoTestsInterface
from typing import Self, Any
class FormatModuleInterface:
def __init__(self:Self, op:OpoTestsInterface) -> None:
self.op:OpoTestsInterface = op
def start(self:Self) -> None:pass
@staticmethod
def set_fragments_level(string:str, fragments:list[str]) -> str:pass
@classmethod
def build_fragments(cls:type[Self], string:str, fragments:list[str] = []) -> str:pass
def execute(self:Self,
i:int,
string:str,
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:pass
@staticmethod
def prepare_result(string:str, option:str, shared:dict[str, Any|None]) -> int:pass
def check(self:Self,
i:int,
string:str,
options:str|list[str],
shared:dict[str, Any|None] = {},
fragments:list[str] = [],
check_full:bool = True
) -> tuple[bool, int]:pass
def get_check_length(self:Self,
i:int,
string:str,
options:str|list[str],
shared:dict[str, Any|None] = {},
fragments:list[str] = [],
check_full:bool = True
) -> int:pass
def check_select(self:Self,
i:int,
string:str,
options:tuple[tuple[int, int], str, list[str]],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str|None:pass
def get_list(self:Self, i:int, items:list[str]) -> list[str]:pass
@staticmethod
def check_range(string:str, inputs:str|list[str]) -> int:pass

View File

@ -1,4 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self
class HTTPSocketDriverInterface: class HTTPSocketDriverInterface:
pass
def start(self:Self) -> None:pass

View File

@ -1,7 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Optional from typing import Any, Optional, Self
class I18NManagerInterface: class I18NManagerInterface:
def start(self:Self) -> None:pass
def get(self, texts:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> str|None:pass def get(self, texts:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> str|None:pass

View File

@ -1,10 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional from typing import Self, Any, Optional
from Interfaces.SettingsManagerInterface import SettingsManagerInterface from Interfaces.SettingsManagerInterface import SettingsManagerInterface
from Interfaces.I18NManagerInterface import I18NManagerInterface from Interfaces.I18NManagerInterface import I18NManagerInterface
from Interfaces.HTTPSocketDriverInterface import HTTPSocketDriverInterface from Interfaces.HTTPSocketDriverInterface import HTTPSocketDriverInterface
from Interfaces.FilesDriverInterface import FilesDriverInterface from Interfaces.FilesDriverInterface import FilesDriverInterface
from Interfaces.QuestionsManagerInterface import QuestionsManagerInterface
from Interfaces.UsersManagerInterface import UsersManagerInterface
from Interfaces.RoutesManagerInterface import RoutesManagerInterface
from Interfaces.ControllersManagerInterface import ControllersManagerInterface
class OpoTestsInterface: class OpoTestsInterface:
@ -13,6 +18,10 @@ class OpoTestsInterface:
self.i18n:I18NManagerInterface = None self.i18n:I18NManagerInterface = None
self.http_server:HTTPSocketDriverInterface = None self.http_server:HTTPSocketDriverInterface = None
self.files:FilesDriverInterface = None self.files:FilesDriverInterface = None
self.users:UsersManagerInterface = None
self.questions:QuestionsManagerInterface = None
self.routes:RoutesManagerInterface = None
self.controllers:ControllersManagerInterface = None
def print(self:Self, _type:str, string:str, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, i:int = 0) -> None:pass def print(self:Self, _type:str, string:str, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, i:int = 0) -> None:pass
@ -22,3 +31,8 @@ class OpoTestsInterface:
variables:Optional[dict[str, Any]|list|tuple] = None, variables:Optional[dict[str, Any]|list|tuple] = None,
i:Optional[int] = 1 i:Optional[int] = 1
) -> None:pass ) -> None:pass
def load_json_data(self:Self,
inputs:Optional[str|dict[str, Any|None]|list[Any|None]|tuple[Any|None]],
only_dictionaries:bool = True
) -> list[dict[str, Any|None]|list[Any|None]|tuple[Any|None]]:pass

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
class QuestionsManagerInterface:
def start(self:Self) -> None:pass
def update(self:Self) -> None:pass
def empty(self:Self) -> None:pass
def add(self:Self,
inputs:dict[str, Any|None]|list[Any|None]|tuple[Any|None]|str,
overwrite:bool = False
) -> None:pass
def get_value(self:Self, key:str, i:Optional[int] = None) -> Any|None:pass

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self
from Models.RouteModel import RouteModel
class RoutesManagerInterface:
def start(self:Self) -> None:pass
def add(self:Self, inputs:str|RouteModel|list|tuple, overwrite:bool = False) -> None:pass
def go(self:Self, method:str, request:str, inputs:dict) -> None:pass

View File

@ -1,7 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Optional from typing import Any, Optional, Self
class SettingsManagerInterface: class SettingsManagerInterface:
def start(self:Self) -> None:pass
def get(self, keys:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> Any|None:pass def get(self, keys:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> Any|None:pass

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self
class UsersManagerInterface:
def start(self:Self) -> None:pass
def update(self:Self) -> None:pass
def empty(self:Self) -> None:pass
def add(self:Self, inputs:dict[str, str]|list|tuple|str, overwrite:bool = False) -> None:pass
def validate(self:Self, nick:str, password:str) -> bool:pass

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any
from Interfaces.ControllersAbstractInterface import ControllersAbstractInterface
from Interfaces.OpoTestsInterface import OpoTestsInterface
from Models.RequestModel import RequestModel
class ControllersManager:
def __init__(self:Self, ot:OpoTestsInterface) -> None:
self.ot:OpoTestsInterface = ot
self.__controllers:dict[str, ControllersAbstractInterface] = {}
def start(self:Self) -> None:
pass
def add(self:Self, inputs:str|ControllersAbstractInterface|list|tuple, overwrite:bool = False) -> None:
item:dict[str, ControllersAbstractInterface]
for item in self.ot.load_json_data(inputs, False) or (inputs,):
key:str
controller:ControllersAbstractInterface
for key, controller in item.items():
if overwrite or key not in self.__controllers:
self.__controllers[key] = controller
def get(self:Self,
key:str,
action:str,
request:RequestModel
) -> tuple[Any|None, dict[str, Any|None]]|None:
return self.__controllers[key].get(action, request) if key in self.__controllers else None

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.OpoTestsInterface import OpoTestsInterface from Interfaces.OpoTestsInterface import OpoTestsInterface
from typing import Any, Optional, Self from typing import Any, Optional, Self
@ -15,6 +16,37 @@ class I18NManager:
self.__default_language:str = "espanol" self.__default_language:str = "espanol"
self.__language_selected:str = "espanol" self.__language_selected:str = "espanol"
def start(self:Self) -> None:
key:str
self.__default_language = self.ot.settings.get(("default_language", "i18n_default_language"), None, self.__default_language)
self.__language_selected = self.ot.settings.get(("language_selected", "i18n_language_selected"), None, self.__language_selected)
for key in ("default_i18n_files", "default_i18n", "i18n_files", "i18n"):
self.add(self.ot.settings.get(key), True)
def add(self:Self, inputs:dict[str, Any|None]|str|list|tuple, overwrite:bool = False) -> None:
set:dict[str, Any|None]
for set in self.ot.load_json_data(inputs):
language:str
sentences:dict[str, str|list|tuple|None]
for language, sentences in set.items():
if Check.is_dictionary(sentences):
key:str
text:str|list[str]|tuple[str]|None
if language not in self.__sentences:
self.__sentences[language] = {}
for key, text in sentences.items():
if overwrite or key not in self.__sentences[language]:
self.__sentences[language][key] = text
def get(self:Self, texts:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> str|None: def get(self:Self, texts:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> str|None:
keys:list[str] = Utils.get_keys(texts) keys:list[str] = Utils.get_keys(texts)

View File

@ -0,0 +1,94 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.OpoTestsInterface import OpoTestsInterface
from typing import Self, Any, Optional
from Models.QuestionModel import QuestionModel
from Models.SetModel import SetModel
class QuestionsManager:
def __init__(self:Self, ot:OpoTestsInterface) -> None:
self.ot:OpoTestsInterface = ot
self.__sets:list[SetModel] = []
self.__groups:list[str] = []
self.__groups_variables:list[dict[str, Any]] = []
self.__questions:list[QuestionModel] = []
self.__variables:dict[str, Any] = {}
def start(self:Self) -> None:
pass
def update(self:Self) -> None:
pass
def empty(self:Self) -> None:
self.__sets = []
self.__groups = []
self.__groups_variables:list[dict[str, Any]] = []
self.__questions = []
def add(self:Self,
inputs:dict[str, Any|None]|list[Any|None]|tuple[Any|None]|str,
overwrite:bool = False
) -> None:
set_data:dict[str, Any|None]
for set_data in self.ot.load_json_data(inputs):
set:SetModel = SetModel(set_data, len(self.__sets))
group_done:bool = False
key:str
question_data:dict[str, Any|None]
group_variables:dict[str, Any|None]|None = set_data.get("group_variables")
variables:dict[str, Any|None]|None = set_data.get("variables")
variables and self.__variables.update(variables)
for set.group_i, key in enumerate(self.__groups):
if key == set.group:
group_done = True
group_variables and self.__groups_variables[set.group_i].update(group_variables)
break
if not group_done:
set.group_i += 1
self.__groups += [set.group]
if group_variables:
self.__groups_variables += [group_variables]
for question_data in set_data.get("queries", []):
variables:dict[str, Any|None]|None = question_data.get("variables")
question:QuestionModel = QuestionModel(question_data, set)
allowed:bool = True
variables and self.__variables.update(variables)
for i, existing_question in enumerate(self.__questions):
if (
existing_question.set == question.set and
existing_question.group == question.group and
len(existing_question.questions) == len(question.questions) and
not any(question_string != question.questions[j] for j, question_string in enumerate(existing_question.questions))
):
if overwrite:
self.__questions[i] = question
allowed = False
break
if allowed:
self.__questions += [question]
def get_value(self:Self, key:str, i:Optional[int] = None) -> Any|None:
set:dict[str, Any]
for set in ([] if i is None else [
self.__questions[i].own_variables,
self.__groups_variables[self.__questions[i].group]
]) + [self.__variables]:
if key in set:
return set[key]
return None

View File

@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any
from Interfaces.OpoTestsInterface import OpoTestsInterface
from Models.RouteModel import RouteModel
from re import Match as REMatch
from Models.RequestModel import RequestModel
from Utils.Check import Check
from Utils.Utils import Utils
class RoutesManager:
def __init__(self:Self, ot:OpoTestsInterface) -> None:
self.ot:OpoTestsInterface = ot
self.__routes:tuple[RouteModel] = tuple()
def start(self:Self) -> None:
key:str
for key in ("default_routes_files", "default_routes", "routes_files", "routes"):
self.add(self.ot.settings.get(key, []), True)
def add(self:Self, inputs:str|RouteModel|list|tuple, overwrite:bool = False) -> None:
item:str|RouteModel|list|tuple
for item in self.ot.load_json_data(inputs, False) or (inputs,):
if Check.is_string(item):
route:RouteModel = RouteModel(item)
if route.done:
self.__routes += (route,)
else:
self.add(item, overwrite)
elif isinstance(item, RouteModel):
if item.done:
self.__routes += (item,)
elif Check.is_array(item):
if len(item) == 6 and all(subitem is None or Check.is_string(subitem) for subitem in item):
route:RouteModel = RouteModel(item)
if route.done:
self.__routes += (route,)
continue
for subitem in item:
self.add(subitem, overwrite)
def go(self:Self, request:RequestModel) -> tuple[Any|None, int]:
route:RouteModel
for route in self.__routes:
if route.method == request.method:
matches:REMatch = route.request.match(request.request)
if not matches:
continue
request.variables_request = {
route.variables[i] : value for i, value in enumerate(matches.groups()[1:])
}
if route.path:
for index in request.index_files:
path:str = request.public_path + '/' + request.request + ('/' + index if index else '')
data:bytes|None = self.ot.files.load(path)
if data is not None:
return (data, {"mime" : self.ot.files.get_mime(path)})
elif route.controller:
data:tuple[Any|None, dict[str, Any|None]]|None = self.ot.controllers.get(
route.controller,
route.action,
request
)
if data is not None:
return data
return (Utils.json_encode({
"ok" : False,
"code" : 404,
"message" : "Not found"
}), {
"http_code" : 404,
"mime" : "application/json"
})

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.OpoTestsInterface import OpoTestsInterface from Interfaces.OpoTestsInterface import OpoTestsInterface
from typing import Any, Optional, Self from typing import Any, Optional, Self
@ -6,13 +7,54 @@ from Utils.Utils import Utils
class SettingsManager: class SettingsManager:
DEFAULT_SETTINGS:dict[str, Any|None] = {} DEFAULT_SETTINGS:dict[str, Any|None] = {
"default_settings_files" : ["/JSON/OpoTests.settings.json"],
"default_secrets_files" : ["/JSON/OpoTests.secrets.json"]
}
def __init__(self:Self, ot:OpoTestsInterface, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None) -> None: def __init__(self:Self,
ot:OpoTestsInterface,
inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None
) -> None:
self.ot:OpoTestsInterface = ot self.ot:OpoTestsInterface = ot
self.__customs:dict[str, Any|None] = Utils.get_dictionary(inputs) self.__customs:dict[str, Any|None] = Utils.get_dictionary(inputs)
self.__settings:dict[str, Any|None] = {} self.__settings:dict[str, Any|None] = {}
self.__secrets:dict[str, Any|None] = {} self.__secrets:dict[str, Any|None] = {}
def start(self:Self) -> None:
key:str
for key in ("default_settings_files", "default_settings", "settings_files", "settings"):
self.add(self.get(key), True)
for key in ("default_secrets_files", "default_secrets", "secrets_files", "secrets"):
self.add_secrets(self.get(key), True)
def add(self:Self, inputs:dict[str, Any|None]|str|list|tuple, overwrite:bool = False) -> None:
set:dict[str, Any|None]
for set in self.ot.load_json_data(inputs):
key:str
value:Any|None
for key, value in set.items():
if overwrite or key not in self.__settings:
self.__settings[key] = value
def add_secrets(self:Self, inputs:dict[str, Any|None]|str|list|tuple, overwrite:bool = False) -> None:
set:dict[str, Any|None]
for set in self.ot.load_json_data(inputs):
key:str
value:Any|None
for key, value in set.items():
if overwrite or key not in self.__secrets:
self.__secrets[key] = value
def get(self:Self, keys:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> Any|None: def get(self:Self, keys:str|list|tuple, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None, _default:Optional[Any] = None) -> Any|None:
return Utils.get_values(keys, (inputs, self.__customs, self.__secrets, self.__settings, self.DEFAULT_SETTINGS), _default) return Utils.get_values(keys, (inputs, self.__customs, self.__secrets, self.__settings, self.DEFAULT_SETTINGS), _default)

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.OpoTestsInterface import OpoTestsInterface
from typing import Self
from Models.UserModel import UserModel
class UsersManager:
def __init__(self:Self, op:OpoTestsInterface) -> None:
self.op:OpoTestsInterface = op
self.__users:list[UserModel] = []
def start(self:Self) -> None:
pass
def update(self:Self) -> None:
pass
def empty(self:Self) -> None:
self.__users = []
def add(self:Self, inputs:dict[str, str]|list|tuple|str, overwrite:bool = False) -> None:
users:dict[str, str]
for users in self.op.load_json_data(inputs):
nick:str
password:str
for nick, password in users.items():
i:int
user:UserModel
allowed:bool = True
for i, user in enumerate(self.__users):
if user.name == nick:
if overwrite:
self.__users[i] = UserModel(nick, password)
allowed = False
break
if allowed:
self.__users += [UserModel(nick, password)]
def validate(self:Self, nick:str, password:str) -> bool:
user:UserModel
for user in self.__users:
if user.name == nick and user.password == password:
return True
return False

View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any
from Utils.Check import Check
from Models.SetModel import SetModel
class QuestionModel:
def __init__(self:Self, data:dict[str, str|list[str]|bool|None], set:SetModel) -> None:
questions:str|list[str] = data.get("questions", [])
self.set:int = set.i
self.group:int = set.group_i
self.questions:list[str] = questions if Check.is_array(questions) else [questions]
self.rights:list[str] = data.get("rights")
self.wrongs:list[str] = data.get("wrongs", [])
self.own_variables:dict[str, Any] = data.get("own_variables", {})
self.brothers_are_wrongs:bool = data.get("brothers_are_wrongs", True)

View File

@ -0,0 +1,78 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self
from Utils.Check import Check
from Utils.Patterns import RE
from Utils.Utils import Utils
from re import Match as REMatch
from socket import socket as Socket
class RequestModel:
def __init__(self:Self, data:str, inputs:dict[str, Any|None]) -> None:
header:list[str]
line:str
self.address:str = inputs.get("address")
self.port:int = inputs.get("port")
self.client:Socket = inputs.get("client")
self.public_path:str = inputs.get("public_path")
self.index_files:list[str] = inputs.get("index_files")
self.method:str
self.request:str
self.protocol:str
self.protocol_version:str
self.variables_get:dict[str, str] = {}
self.variables_post:dict[str, str] = {}
self.variables_request:dict[str, str] = {}
self.headers:dict[str, str] = {}
self.body:str|None
header, self.body = (lambda header, body:(
RE.NEW_LINE.split(str(header).strip()), body
))(*RE.HTTP_BLOCKS.match(data).groups())
(
self.method,
self.request,
self.variables_get,
self.protocol,
self.protocol_version
) = (lambda method, request, variables, protocol, protocol_version:(
str(method).lower(),
request,
self.parse_variables(variables),
protocol,
protocol_version
))(*RE.HTTP_REQUEST.match(header[0]).groups())
for line in header[1:]:
key:str
value:str
key, value = RE.HEADER_LINE.match(line).groups()
self.headers[key.strip().lower()] = value.strip()
self.variables_post = self.parse_variables(self.body or "")
@staticmethod
def parse_variables_set(data:str) -> dict[str, str]:
json:dict[str, str]|list[Any|None]|tuple[Any|None]|None = Utils.json_decode(data)
if Check.is_dictionary(json):
return json
return {key : value for key, value in RE.URI_VARIABLES.findall(data) or []}
@classmethod
def parse_variables(cls:type[Self], data:str|None) -> dict[str, str]:
return cls.parse_variables_set(
Utils.base64_decode(data) or data
) if data else {}
def set_request_variables(self:Self, matches:REMatch, keys:tuple[str]) -> None:
self.variables_request = {keys[i] : value for i, value in enumerate(matches.groups()[1:])}

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any
from Utils.Check import Check
from Utils.Utils import Utils
from Utils.Patterns import RE
from re import Match as REMatch
from re import Pattern as REPattern
from re import compile as re_compile
class RouteModel:
def __init__(self:Self, inputs:str|list|tuple) -> None:
self.method:str
self.request:REPattern
self.controller:str
self.action:str
self.path:str|None
self.variables:tuple[str] = tuple()
self.permissions:list[str] = []
self.done:bool = False
if Check.is_string(inputs):
inputs = RE.ROUTE_ITEM.match(inputs).groups()
if Check.is_array(inputs):
self.done = True
(
self.method, self.request, self.action, self.controller, self.path, self.permissions
) = (lambda method, request, controller, action, path, permissions:(
method.lower(),
re_compile(r'^' + RE.ROUTE_RE_FORMAT.sub(
self.format_request_item,
RE.STRING_VARIABLES.sub(self.__add_variable, request)
) + (r'' if path else ('' if request[-1] == '/' else r'\/') + r'?$')),
controller,
action,
path,
(
[] if not permissions else
str(permissions).split(",") if Check.is_string(permissions) else
list(permissions) if Check.is_array(permissions) else
[])
))(*inputs)
def __add_variable(self:Self, key:str) -> str:
self.variables += (key,)
return r'([^\/]+)'
@staticmethod
def format_request_item(matches:REMatch) -> str:
character:str = matches.group(2)
return '\\' + character if character else matches.group(1)

16
Python/Models/SetModel.py Normal file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any
from Utils.Utils import Utils
class SetModel:
def __init__(self:Self, data:dict[str, Any|None], i:int) -> None:
self.origin:str = data.get("origin", "")
self.title:str = data.get("title", "")
self.group:None = data.get("group") or Utils.to_snake(self.title)
self.i:int = i
self.group_i:int
self.sources:list[str] = data.get("sources", [])
self.variables:dict[str, Any] = data.get("own_variables", {})

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self
from Utils.Check import Check
class UserModel:
def __init__(self:Self, *arguments:list[dict[str, str]|str]) -> None:
self.name:str
self.password:str
if Check.is_dictionary(arguments[0]):
data:dict[str, str] = arguments[0]
self.name, self.password = data.get("name", ""), data.get("password", "")
else:
self.name, self.password = arguments

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Check import Check
from Utils.Patterns import RE
class CapitalizeFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
return RE.CAPITAL_CASE.sub(lambda matches:(
matches.group(1).upper()
), self.format.execute(i, (
inputs if Check.is_string(inputs) else
inputs[0] if Check.is_string(inputs[0]) else
""), shared, fragments))
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
substring:str = self.format.set_fragments_level((
inputs if Check.is_string(inputs) else
inputs[0] if Check.is_string(inputs[0]) else
""), fragments)
has_variables:bool = RE.FRAGMENT_VARIABLES.search(substring) is not None
return (
self.format.get_check_length(i, string, substring, shared, fragments, False) if has_variables else
self.format.prepare_result(string, substring, shared))

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Patterns import RE
from Utils.Check import Check
from Utils.Utils import Utils
class MixFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
self.capitalize:bool = bool(options and options.get("capitalized"))
def __get_separator_and_items(self:Self, i:int, inputs:str|list[Any|None]) -> tuple[str, list[str]]:
separator:str
original_items:list[str]
separator, original_items = (
(lambda _, separator, options:(
separator, str(options).split("|")
))(*RE.BASIC_MODE_SPLIT.match(inputs).groups()) if Check.is_string(inputs) else
inputs if Check.is_array(inputs) else
(None, None))
return separator, self.format.get_list(i, original_items)
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
separator:str
items:list[str]
l:int
results:str
separator, items = self.__get_separator_and_items(i, inputs)
l = len(items)
Utils.randomize_array(items)
results = self.format.execute(i, (
"".join(items) if l < 2 else
", ".join(items[:l - 1]) + (
" " if not separator else
" " + separator.strip() + " " if RE.IS_SEPARATOR.match(separator) else
separator) + items[l - 1]), shared, fragments)
return RE.CAPITAL_CASE.sub(lambda matches:(
matches.group(1).upper()
), results) if self.capitalize else results
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
separator:str
items:list[str]
l:int
separator, items = self.__get_separator_and_items(i, inputs)
l = len(items)
return self.format.check_select(i, string, ((l, l), separator, items), shared, fragments)

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Patterns import RE
from Utils.Check import Check
class PlainFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
return self.format.execute(i, (
inputs if Check.is_string(inputs) else
inputs[0] if Check.is_string(inputs[0]) else
""), shared, fragments)
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
substring:str = self.format.set_fragments_level((
inputs if Check.is_string(inputs) else
inputs[0] if Check.is_string(inputs[0]) else
""), fragments)
has_variables:bool = RE.FRAGMENT_VARIABLES.search(substring) is not None
return (
self.format.get_check_length(i, string, substring, shared, fragments, False) if has_variables else
self.format.prepare_result(string, substring, shared))

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Patterns import RE
from Utils.Check import Check
from Utils.Utils import Utils
class RandomFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
return self.format.execute(i, Utils.get_random(self.format.get_list(i, (
inputs.split("|") if Check.is_string(inputs) else
inputs[0] if Check.is_array(inputs[0]) else
""))), shared, fragments)
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
has_empty:bool = False
option:str
for option in self.format.get_list(i, (
inputs.split("|") if Check.is_string(inputs) else
inputs[0] if Check.is_array(inputs[0]) else
"")):
if option == "":
if not has_empty:
has_empty = True
continue
if RE.FRAGMENT_VARIABLES.match(self.format.set_fragments_level(option, fragments)):
return self.format.get_check_length(i, string, option, shared, fragments, False)
length:int = self.format.prepare_result(string, option, shared)
if length != -1:
return length
return 0 if has_empty else -1

View File

@ -0,0 +1,48 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Patterns import RE
from Utils.Check import Check
from Utils.Utils import Utils
class RangeFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
inputs = (
[
int(value) for value in str(Utils.get_random(inputs.split("|"))).split("-")
] if Check.is_string(inputs) else
inputs if Check.is_array(inputs) else
[])
if Check.is_number(inputs):
return str(inputs)
l = len(inputs)
return str(
None if not l else
inputs[0] if l == 1 else
Utils.get_random(*inputs))
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
return self.format.check_range(string, inputs)

View File

@ -0,0 +1,94 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Patterns import RE
from Utils.Check import Check
from Utils.Utils import Utils
class SelectFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
self.capitalize:bool = bool(options and options.get("capitalized"))
def __get_separator_and_items(self:Self, i:int, inputs:str|list[Any|None]) -> tuple[tuple[int, int], str, list[str]]:
range:tuple[int, int]
separator:str
original_items:list[str]
separator, original_items = (
(lambda _, range, separator, options:(
tuple(int(value) for value in range.split("-")), separator, str(options).split("|")
))(*RE.SELECT_MODE_SPLIT.match(inputs).groups()) if Check.is_string(inputs) else
inputs if Check.is_array(inputs) else
(None, None, None))
return range, separator, self.format.get_list(i, original_items)
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
range:tuple[int, int]
separator:str
items:list[str]
range, separator, items = self.__get_separator_and_items(i, inputs)
k = Utils.get_random(*range)
if not k:
return ""
l:int = len(items)
results:str
if l < 2:
results = "".join(items)
else:
Utils.randomize_array(items)
items = items[:k]
l = len(items)
results = (
items[0] if l < 2 else
", ".join(items[:l - 1]) + (
" " if not separator else
" " + separator.strip() + " " if RE.IS_SEPARATOR.match(separator) else
separator) + items[l - 1])
results = self.format.execute(i, results, shared, fragments)
return RE.CAPITAL_CASE.sub(lambda matches:(
matches.group(1).upper()
), results) if self.capitalize else results
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
minimum:int
maximum:int
separator:str
items:list[str]
l:int
(minimum, maximum), separator, items = self.__get_separator_and_items(i, inputs)
return self.format.check_select(i, string, (
(minimum, maximum), separator, items
), shared, fragments)

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional
from Interfaces.FormatModuleInterface import FormatModuleInterface
from Utils.Patterns import RE
from Utils.Check import Check
from Utils.Utils import Utils
class SerieFormat:
def __init__(self:Self,
format:FormatModuleInterface,
options:Optional[dict[str, Any|None]] = None
) -> None:
self.format:FormatModuleInterface = format
def get(self:Self,
i:int,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
inputs = (
[
int(value) for value in str(Utils.get_random(inputs.split("|"))).split("-")
] if Check.is_string(inputs) else
inputs if Check.is_array(inputs) else
[])
serie:int|None = shared.get("serie")
range:int|list[int]|list[int, int]
if serie is not None:
inputs = [range for range in inputs if (
serie < range if not Check.is_array(range) else
serie < range[0] if len(range) == 1 else
serie < range[1])]
range = Utils.get_random(*inputs)
if not Check.is_array(range):
shared["serie"] = range
return str(range)
if len(range) == 1:
shared["serie"] = range[0]
return str(range[0])
value:int
while True:
value = Utils.get_random(*range)
if value > serie:
break
serie = value
return str(value)
def check(self:Self,
i:int,
string:str,
inputs:str|list[Any|None],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> int:
return self.format.check_range(string, inputs)

View File

@ -0,0 +1,310 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Interfaces.OpoTestsInterface import OpoTestsInterface
from typing import Self, Any
from Utils.Patterns import RE
from Utils.Check import Check
from Utils.Utils import Utils
from re import Match as REMatch
from Interfaces.FormatModeInterface import FormatModeInterface
from Modules.Format.CapitalizeFormat import CapitalizeFormat
from Modules.Format.MixFormat import MixFormat
from Modules.Format.PlainFormat import PlainFormat
from Modules.Format.RandomFormat import RandomFormat
from Modules.Format.RangeFormat import RangeFormat
from Modules.Format.SelectFormat import SelectFormat
from Modules.Format.SerieFormat import SerieFormat
class FormatModule:
def __init__(self:Self, op:OpoTestsInterface) -> None:
self.op:OpoTestsInterface = op
self.modes:dict[str, FormatModeInterface] = {}
for keys, mode in (
(("capitalize", "cap", "capital", "Cap", "Capitalize", "Capital"), CapitalizeFormat(self)),
(("mix", "mixin"), MixFormat(self)),
(("Mix", "Mixin"), MixFormat(self, {"capitalized" : True})),
(("plain",), PlainFormat(self)),
(("rand", "random"), RandomFormat(self)),
(("range",), RangeFormat(self)),
(("select",), SelectFormat(self)),
(("Select",), SelectFormat(self, {"capitalized" : True})),
(("serie",), SerieFormat(self)),
):
for key in keys:
self.modes[key] = mode
def start(self:Self) -> None:
pass
@staticmethod
def set_fragments_level(string:str, fragments:list[str]) -> str:
return RE.FRAGMENT_PATTERN.sub(lambda matches:fragments[int(matches.group(1))], string)
@staticmethod
def __build_fragment(matches:REMatch, fragments:list[str]) -> str:
fragments += [matches.group(1)]
return "$$$" + str(len(fragments) - 1) + "$$$"
@classmethod
def build_fragments(cls:type[Self], string:str, fragments:list[str] = []) -> str:
return cls.set_fragments_level(Utils.recursive(string, lambda string:(
RE.FRAGMENT_VARIABLES.sub(lambda matches:(
cls.__build_fragment(matches, fragments)
), string)
)), fragments)
def __process_variable(self:Self,
i:int,
original:str,
key:str,
shared:dict[str, Any|None],
fragments:list[str]
) -> str:
if Check.is_key(key):
if key in shared:
return str(shared[key])
variable:list[Any|None] = self.op.questions.get_value(key, i)
method:str
data:list[Any|None]
if variable is not None:
method, *data = variable
if method in self.modes:
return self.modes[method].get(i, data, shared, fragments)
else:
matches:REMatch|None = RE.FORMAT_SPLIT.match(key)
if matches:
method, *data = matches.groups()[1:3]
if method in self.modes:
return self.modes[method].get(i, data, shared, fragments)
return original
def __execute_varibles(self:Self,
i:int,
string:str,
shared:dict[str, Any|None],
fragments:list[str]
) -> str:
try:
return RE.FRAGMENT_VARIABLES.sub(lambda matches:(
self.__process_variable(i, *matches.groups()[0:2], shared, fragments)
), string)
except Exception as exception:
print(exception)
return string
def execute(self:Self,
i:int,
string:str,
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str:
return Utils.recursive(self.build_fragments(string, fragments), lambda string:(
self.__execute_varibles(i, string, shared, fragments)
))
@staticmethod
def prepare_result(string:str, option:str, shared:dict[str, Any|None]) -> int:
if string.lower().startswith(option.lower()):
if "capitalized" not in shared or shared["capitalized"]:
shared["capitalized"] = False
return len(option)
return -1
def check(self:Self,
i:int,
string:str,
options:str|list[str],
shared:dict[str, Any|None] = {},
fragments:list[str] = [],
check_full:bool = True
) -> tuple[bool, int]:
length:int = 0
option:str
ok:bool = True
string = string.lower()
for option in Utils.get_array(options):
clone:str = "" + string
option_fragmented:str = self.build_fragments(option, fragments)
i:int = 0
length = 0
while True:
matches:REMatch|None = RE.FORMAT_PARTS.search(option_fragmented)
if not matches:
break
part:str = matches.group(0)
m:int = -1
key:str = matches.group(1)
method:str
data:list[Any|None]
if key:
if Check.is_key(key):
method, *data = self.op.questions.get_value(key, i)
if method in self.modes:
m = self.modes[method].check(i, clone, data, shared, fragments, clone, check_full)
# JS FormatModule lines 174-177.
else:
submatches:REMatch|None = RE.FORMAT_SPLIT.match(key)
if submatches:
method, *data = submatches.groups()[1:3]
if method in self.modes:
m = self.modes[method].check(i, clone, data, shared, fragments, clone, check_full)
if m == -1:
m = self.prepare_result(clone, part, shared)
if m != -1:
clone = clone[m:]
length += m
continue
ok = False
break
if ok:
ok = not check_full or not len(clone)
if ok:
break
return (ok, length)
def get_check_length(self:Self,
i:int,
string:str,
options:str|list[str],
shared:dict[str, Any|None] = {},
fragments:list[str] = [],
check_full:bool = True
) -> int:
has:bool
length:int
has, length = self.check(i, string, options, shared, fragments, check_full)
return length if has else -1
def check_select(self:Self,
i:int,
string:str,
options:tuple[tuple[int, int], str, list[str]],
shared:dict[str, Any|None] = {},
fragments:list[str] = []
) -> str|None:
length:int = 0
k:int = 0
check_last:bool = False
minimum:int
maximum:int
separator:str
items:list[str]
separator_length:int
(minimum, maximum), separator, items = options
separator_length = len(separator)
while k < maximum:
ok:bool = False
l:int = len(items)
j:int
item:str
if check_last or (k and k == l - 1):
if not string.startswith(" " + separator + " "):
return -1
length += separator_length + 2
string = string[0, separator_length + 2]
for j, item in enumerate(items):
has_variables:bool = RE.FRAGMENT_VARIABLES.match(
self.set_fragments_level(item, shared, fragments)
) is not None
item_length:int = (
self.get_check_length(i, string, [item], shared, fragments, False) if has_variables else
self.prepare_result(string, item, shared))
if item_length != -1:
string = string[:item_length]
items = items[:j] + items[j + 1:]
length += item_length
ok = True
break
if ok:
if "capitalized" not in shared or shared["capitalized"]:
shared["capitalized"] = False
elif check_last or not k:
return -1
else:
check_last = True
k -= 1
return -1 if k < minimum else length
def __get_list_items(self:Self, i:int, item:str) -> list[str]:
matches:REMatch|None = RE.LIST_ITEM.match(item)
if matches:
key:str = matches.group(1)
method:str
list_items:list[str]
method, *list_items = self.op.questions.get_value(key, i)
if method == "list":
return list_items
return [item]
def get_list(self:Self, i:int, items:list[str]) -> list[str]:
return [subitem for item in items for subitem in self.__get_list_items(i, item)]
@staticmethod
def check_range(string:str, inputs:str|list[str]) -> int:
number_matches:REMatch|None = RE.ABSOLUTE_INTEGER.match(string)
if number_matches:
number:int = int(string)
for range in (
[
int(value) for value in str(Utils.get_random(inputs.split("|"))).split("-")
] if Check.is_string(inputs) else
inputs if Check.is_array(inputs) else
[]):
if Check.is_number(range):
if number == range:
return len(string)
elif len(range) == 1:
if number == range[0]:
return len(string)
else:
if number >= range[0] and number <= range[1]:
return len(string)
return -1

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Utils.Patterns import RE from Utils.Patterns import RE
from typing import Any, Optional, Self from typing import Any, Optional, Self
@ -20,3 +21,23 @@ class Check:
@staticmethod @staticmethod
def is_array(item:Optional[Any]) -> bool: def is_array(item:Optional[Any]) -> bool:
return isinstance(item, (list, tuple)) return isinstance(item, (list, tuple))
@staticmethod
def is_integer(item:Optional[Any]) -> bool:
return isinstance(item, int)
@staticmethod
def is_float(item:Optional[Any]) -> bool:
return isinstance(item, float)
@staticmethod
def is_number(item:Optional[Any]) -> bool:
return isinstance(item, (int, float))
@staticmethod
def is_bytes(item:Optional[Any]) -> bool:
return isinstance(item, bytes)
@staticmethod
def is_json_object(item:Optional[Any]) -> bool:
return isinstance(item, (dict, list, tuple))

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from re import Pattern as REPattern from re import Pattern as REPattern
from re import compile as re_compile from re import compile as re_compile
@ -11,3 +12,21 @@ class RE:
SLASHES:REPattern = re_compile(r'[\\/]+') SLASHES:REPattern = re_compile(r'[\\/]+')
EXCEPTION:REPattern = re_compile(r'^\s*File "([^"]+)", line ([0-9]+), in ([^\n]+)(.*|[\r\n]*)*$') EXCEPTION:REPattern = re_compile(r'^\s*File "([^"]+)", line ([0-9]+), in ([^\n]+)(.*|[\r\n]*)*$')
BREAK_LINES:REPattern = re_compile(r'\r\n|[\r\n]') BREAK_LINES:REPattern = re_compile(r'\r\n|[\r\n]')
TO_SNAKE:REPattern = re_compile(r'[^a-zA-Z0-9]*([A-Z][A-Z0-9]*)|[^a-z0-9]+')
FRAGMENT_PATTERN:REPattern = re_compile(r'\${3}([0-9]+)\${3}')
FRAGMENT_VARIABLES:REPattern = re_compile(r'\{([^\{\}]+)\}')
FORMAT_SPLIT:REPattern = re_compile(r'^([^,:]+)[,:](.*)$')
FORMAT_PARTS:REPattern = re_compile(r'\{([^\{\}]+)\}|[^\{]+|\{')
LIST_ITEM:REPattern = re_compile(r'^list:([a-z0-9_]+)$', RE_IGNORE_CASE)
CAPITAL_CASE:REPattern = re_compile(r'^(.)')
BASIC_MODE_SPLIT:REPattern = re_compile(r'^([^,]+),(.*)$')
IS_SEPARATOR:REPattern = re_compile(r'^[a-z 0-9]+$', RE_IGNORE_CASE)
ABSOLUTE_INTEGER:REPattern = re_compile(r'^[0-9]+$')
SELECT_MODE_SPLIT:REPattern = re_compile(r'^([^,]+),([^,]+),(.*)$')
ROUTE_ITEM:REPattern = re_compile(r'^(?:([^:]+):)([^\s]+)\s+(?:([^\@\s]+)\@([^\s]+)|([^\s]+))(?:\s+([^\s]+))?$')
ROUTE_RE_FORMAT:REPattern = re_compile(r'(\(\[\^\\\/\]\+\))|([\/])')
HTTP_BLOCKS:REPattern = re_compile(r'((?:(?!(?:(?:\r\n){2}|\n{2}|\r{2}))(?:.|[\r\n]+))+)(?:(?:\r\n){2}|\n{2}|\r{2}((?:.+|[\r\n]+)*))?')
NEW_LINE:REPattern = re_compile(r'\r\n|[\n\r]')
HTTP_REQUEST:REPattern = re_compile(r'^([^\s]+)\s([^\s\?\#]+)(?:\?([^#]+))?(?:\#[^\s]+)?\s([^\/]+)\/([0-9\.]+)$')
URI_VARIABLES:REPattern = re_compile(r'&?([^=&]+)=([^&]*)')
HEADER_LINE:REPattern = re_compile(r'^([^\:]+)\:(.+)$')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Utils.Check import Check from Utils.Check import Check
from typing import Any, Self, Optional from typing import Any, Self, Optional
@ -6,6 +7,11 @@ from Utils.Patterns import RE
from re import Match as REMatch from re import Match as REMatch
from inspect import stack as get_stack from inspect import stack as get_stack
from inspect import FrameInfo from inspect import FrameInfo
from json import loads as json_decode
from json import dumps as json_encode
from random import random as math_random
from base64 import b64decode as base64_decode
from base64 import b64encode as base64_encode
class Utils: class Utils:
@ -81,3 +87,91 @@ class Utils:
cls.get_strings(*item) if Check.is_array(item) else (item,) cls.get_strings(*item) if Check.is_array(item) else (item,)
) if Check.is_string(string)] ) if Check.is_string(string)]
@staticmethod
def json_encode(data:dict[str, Any|None]|list[Any|None]|tuple[Any|None]) -> str|None:
try:
return json_encode(data, ensure_ascii=False)
except Exception as exception:
pass
return None
@staticmethod
def json_decode(data:str) -> dict[str, Any|None]|list[Any|None]|tuple[Any|None]|None:
try:
return json_decode(data)
except Exception as exception:
pass
return None
@staticmethod
def to_snake(string:str) -> str:
def callback(matches:REMatch) -> str:
upper:str|None = matches.group(1)
return "_" + upper.lower() if upper else "_"
return RE.TO_SNAKE.sub(callback, string).lower()
@staticmethod
def recursive(data:str, callback:Any) -> str:
cache:str = data
while True:
data = cache
cache = callback(cache)
if data == cache:
break
return cache
@staticmethod
def get_array(item:Any|None) -> list[Any|None]:
return item if Check.is_array(item) else [item]
@staticmethod
def get_random(_from:Optional[int] = None, _to:Optional[int] = None) -> Any|None:
return (
math_random() if _from is None else
_from[int(math_random() * len(_from))] if Check.is_array(_from) else
(
int(math_random() * _from) if _to is None else
int(math_random() * (_to - _from) + _from) if Check.is_integer(_to) else
math_random() * (_to - float(_from)) + float(_from) if Check.is_float(_to) else
None) if Check.is_integer(_from) else
(
math_random() * _from if _to is None else
math_random() * (float(_to) - _from) + _from if Check.is_number(_to) else
None) if Check.is_float(_from) else
None)
@classmethod
def randomize_array(cls:type[Self], items:list[Any|None]) -> None:
l:int = len(items)
for i in range(l):
j:int = cls.get_random(l)
if i != j:
items[i], items[j] = items[j], items[i]
@staticmethod
def base64_encode(data:str|bytes, encoding:str = "utf-8") -> str|None:
try:
return base64_encode(data.encode(encoding) if Check.is_string(data) else data).decode(encoding)
except Exception as exception:
pass
return None
@staticmethod
def base64_decode(data:str|bytes, encoding:str = "utf-8", is_string:bool = True) -> str|bytes|None:
try:
decoded:bytes = base64_decode(data.encode(encoding) if Check.is_string(data) else data)
return decoded.decode(encoding) if is_string else decoded
except Exception as exception:
pass
return None

View File

@ -1,5 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from Application.OpoTests import OpoTests from Application.OpoTests import OpoTests
from Controllers.TestController import TestController
opo_test:OpoTests = OpoTests() opo_test:OpoTests = OpoTests()
opo_test.controllers.add({
"test" : TestController(opo_test)
})