diff --git a/paramecio/citoplasma/i18n.py b/paramecio/citoplasma/i18n.py
index a205934..18c10e5 100644
--- a/paramecio/citoplasma/i18n.py
+++ b/paramecio/citoplasma/i18n.py
@@ -1,15 +1,38 @@
#!/usr/bin/env python3
+"""
+Parameciofm is a series of wrappers for bottle.py, mako and others and construct a simple headless cms.
+
+Copyright (C) 2024 Antonio de la Rosa Caballero
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+"""
+
from importlib import import_module
from paramecio.citoplasma.sessions import get_session
import json
from bottle import request
+import gettext
+import os
yes_session=False
i18n_module={}
def load_lang(*args):
+ """A function for load the lang module dinamically
+ """
for module in args:
@@ -26,9 +49,57 @@ def load_lang(*args):
# here load the language
+class PGetText:
+
+ # Dict where all gettext domain are saved -> domain=name, example, admin, libraries, pastafari2, etc...
+
+ l={}
+
+ def __init__(self, module_file):
+
+ module_dir=os.path.dirname(os.path.realpath(module_file))
+
+ module_name=os.path.basename(module_dir)
+
+ if module_name not in PGetText.l:
+
+ PGetText.l[module_name]={}
+
+ for i in I18n.dict_i18n:
+
+ if i not in PGetText.l[module_name]:
+
+ PGetText.l[module_name][i]=gettext.translation(module_name, module_dir+'/languages/', languages=[i], fallback=True)
+ PGetText.l[module_name][i].install()
+
+ self.module=module_name
+
+ def gettext(self, text):
+
+ return PGetText.l[self.module][I18n.get_default_lang()].gettext(text)
+
+def pgettext(module_file):
+
+ module=os.path.dirname(os.path.realpath(module_file))
+
+ base_name=os.path.dirname(os.path.realpath(module))
+
+ l=gettext.translation(os.path.basename(base_name), module+'/languages/', languages=I18n.get_default_lang(), fallback=True)
+
+ return l.gettext
class I18n:
+ """Class for i18n tasks
+
+ Class for i18n tasks, how, strings for every language supported, for now are en-US and es-ES. You can add more languages adding
+
+ Attributes:
+ default_lang (str): The default string lang used when get someone
+ dict_i18n (list): The list with default languages. You can add more calling it static variable in settings/config.py
+
+ """
+
default_lang='en-US'
dict_i18n=['en-US', 'es-ES']
@@ -42,6 +113,7 @@ class I18n:
@staticmethod
def get_default_lang():
+ """Static method for get the default lang"""
lang=I18n.default_lang
@@ -53,6 +125,15 @@ class I18n:
@staticmethod
def lang(module, symbol, text_default, lang=None):
+ """Static method for get a string from selected language
+
+ Static method used to get the string of the selected language. If there is no string in the selected language, it returns text_default.
+
+ Args:
+ module (str): The module to which the translation string belongs
+ symbol (str): Simple symbol that is useful for identify the string
+ text_default (str): The text used by default when there are not translation in the selected language
+ """
if not lang:
lang=I18n.get_default_lang()
@@ -67,7 +148,12 @@ class I18n:
@staticmethod
def extract_value(value):
-
+ """Static method for get values from json lang array
+
+ Args:
+ value (json): Lang dict in json format
+ """
+
value=json.loads(value)
lang=I18n.get_default_lang()
@@ -93,3 +179,4 @@ class I18n:
return json.dumps(arr_final)
+common_pgettext=PGetText(__file__)
diff --git a/paramecio/citoplasma/sessions.py b/paramecio/citoplasma/sessions.py
index 3d41064..257ba14 100644
--- a/paramecio/citoplasma/sessions.py
+++ b/paramecio/citoplasma/sessions.py
@@ -15,7 +15,7 @@ except:
key_encrypt=create_key_encrypt_256(30)
session_opts={'session.data_dir': 'sessions', 'session.type': 'file', 'session.path': 'paramecio'}
-from itsdangerous import JSONWebSignatureSerializer
+#from itsdangerous import JSONWebSignatureSerializer
from bottle import request, response
import os
try:
diff --git a/paramecio/create_module.py b/paramecio/create_module.py
index 96e7c87..544402f 100644
--- a/paramecio/create_module.py
+++ b/paramecio/create_module.py
@@ -10,6 +10,8 @@ from settings import config
from importlib import import_module
def start():
+ """Module for create new modules for paramecio
+ """
parser=argparse.ArgumentParser(description='A tool for create new modules for paramecio')
@@ -99,11 +101,8 @@ def regenerate_modules_config():
print("-"*60)
exit(1)
- f=open('./settings/modules.py', 'w')
-
- f.write("".join(modules))
-
- f.close()
+ with open('./settings/modules.py', 'w') as f:
+ f.write("".join(modules))
if __name__=="__main__":
start()
diff --git a/paramecio/cromosoma/corefields.py b/paramecio/cromosoma/corefields.py
index 4c24ba3..5a48807 100644
--- a/paramecio/cromosoma/corefields.py
+++ b/paramecio/cromosoma/corefields.py
@@ -1,21 +1,46 @@
+"""
+Parameciofm is a series of wrappers for Bottle.py, mako and others and construct a simple headless cms.
+
+Copyright (C) 2024 Antonio de la Rosa Caballero
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+"""
+
from paramecio.cromosoma.webmodel import PhangoField
from paramecio.cromosoma import coreforms
from paramecio.citoplasma.i18n import I18n
+#from bs4 import BeautifulSoup
+import bleach
class IntegerField(PhangoField):
"""Class that figure an integer sql type field.
-
- Args:
- name (str): The name of new field
- size (int): The size of the new field in database. By default 11.
- required (bool): Boolean for define if
-
"""
def __init__(self, name, size=11, required=False):
+ """
+ Args:
+ name (str): The name of field
+ size (int): The size of the new field in database. By default 11.
+ required (bool): Boolean for define if field is required or not
+ """
+
super(IntegerField, self).__init__(name, size, required)
self.default_value=0
+
+
+ self.type_sql='int({})'.format(self.size)
def check(self, value):
@@ -60,6 +85,11 @@ class BigIntegerField(IntegerField):
"""
+ def __init__(self, name, size=11, required=False):
+
+ super().__init__(name, size, required)
+ self.type_sql='bigint({})'.format(self.size)
+
def get_type_sql(self):
"""Method for return the sql code for this type
@@ -85,6 +115,7 @@ class FloatField(PhangoField):
self.error_default="The value is zero"
self.default_value=0
+ self.type_sql='float'.format(self.size)
def check(self, value):
@@ -123,26 +154,55 @@ class FloatField(PhangoField):
return 'FLOAT NOT NULL DEFAULT "0"'
class DecimalField(FloatField):
+ """PhangoField field for Decimals fields."""
+
+ def __init__(self, name, size=11, required=False):
+
+ super().__init__(name, size, required)
+ self.type_sql='decimal(20,2)'
def get_type_sql(self):
return 'DECIMAL(20, 2) NOT NULL DEFAULT "0"'
class DoubleField(FloatField):
+ """PhangoField field for Double fields."""
+
+ def __init__(self, name, size=11, required=False):
+
+ super().__init__(name, size, required)
+ self.type_sql='double'
def get_type_sql(self):
return 'DOUBLE NOT NULL DEFAULT "0"'
class CharField(PhangoField):
+ """Simple alias for PhangoField"""
pass
class TextField(PhangoField):
+ """Class used for text fields
+
+ Class used for text fields, use TEXT sql type for the this field.
+ """
def __init__(self, name, required=False):
+ """Init TextField class different to standard PhangoField
+
+ Args:
+ name (str): The name of new field
+ required (bool): Boolean for define if field is required or not
+
+ Attributes:
+ set_default (str): Set if the value es NOT NULL or not
+ """
+
super().__init__(name, 11, required)
+ self.type_sql='text'
+
self.set_default='NOT NULL'
def get_type_sql(self):
@@ -153,19 +213,107 @@ class TextField(PhangoField):
return 'TEXT '+self.set_default
-class HTMLField(TextField):
+class LongTextField(TextField):
+ """Class used for long text fields (32 bits size, 4G)
+
+ Class used for text fields, use LONGTEXT sql type for the this field.
+ """
def __init__(self, name, required=False):
+ """Init TextField class different to standard PhangoField
+
+ Args:
+ name (str): The name of new field
+ required (bool): Boolean for define if field is required or not
+
+ Attributes:
+ set_default (str): Set if the value es NOT NULL or not
+ """
+
super().__init__(name, required)
+ self.type_sql='longtext'
+
+ def get_type_sql(self):
+
+ """Method for return the sql code for this type
+
+ """
+
+ return 'LONGTEXT '+self.set_default
+
+class HTMLField(TextField):
+ """Class used for html fields
+
+ Class used for html fields, use TEXT sql type for the this field because is children of TextField. In this method self.escape is used for convert " to "
+ """
+
+ def __init__(self, name, required=False):
+ """Init HTMLField class different to standard PhangoField
+
+ Args:
+ name (str): The name of new field
+ required (bool): Boolean for define if field is required or not
+
+ Attributes:
+ trusted_tags (list): A list with safe tags.
+ """
+
+ super().__init__(name, required)
+ self.trusted_tags=[]
def check(self, value):
+ """Check method for html values
- return re.sub('<.*?script?>', '', value)
+ This check method use beautifulsoap for clean and format html code
+ """
+
+ # leach.clean('
"trial"
', tags=('p'))
+ """
+ soup=BeautifulSoup(value, features='html.parser')
+ for tag in soup.findAll(True):
+
+ if tag.name not in self.trusted_tags:
+ tag.hidden=True
+ value=soup.renderContents().decode('utf-8')
+
+ if self.escape:
+
+ return value.replace('"', '"')
+ else:
+
+ return value
+
+ """
+
+ value=bleach.clean('
"trial"
', tags=self.trusted_tags)
+
+ if self.escape:
+
+ return value.replace('"', '"')
+ else:
+
+ return value
+
+
class ForeignKeyField(IntegerField):
+ """Subclass of IntegerField for create Foreign keys
+
+ A subclass of IntegerField used for create foreign keys in related tables.
+ """
def __init__(self, name, related_table, size=11, required=False, identifier_field='id', named_field="id", select_fields=[]):
+ """
+ Args:
+ name (str): Name of field
+ related_table (WebModel): The table-model related with this foreign key
+ size (int): The size of the new field in database. By default 11.
+ required (bool): Boolean for define if field is required or not
+ identifier_field (str): The Id field name from related table
+ named_field (str): The field from related table used for identify the row seleted from related table
+ select_fields (list): A series of fields names from related
+ """
super(ForeignKeyField, self).__init__(name, size, required)
@@ -192,7 +340,7 @@ class ForeignKeyField(IntegerField):
value=super().check(value)
if value=='0' or value==0:
- value='NULL'
+ value=None
return value
@@ -206,8 +354,15 @@ class ForeignKeyField(IntegerField):
class BooleanField(IntegerField):
+ """Field for boolean values
+ """
def __init__(self, name, size=1):
+ """
+ Args:
+ name (str): Name of field
+ size (int): The size of the new field in database. By default 11.
+ """
required=False
@@ -219,6 +374,8 @@ class BooleanField(IntegerField):
self.default_error="Need 0 or 1 value"
self.default_value=0
+ self.type_sql='tinyint(1)'
+
def check(self, value):
self.error=False
@@ -231,6 +388,7 @@ class BooleanField(IntegerField):
if value<0 or value>1:
self.txt_error=self.default_error
self.error=True
+ value=0
except:
diff --git a/paramecio/cromosoma/coreforms.py b/paramecio/cromosoma/coreforms.py
index 3247ddc..76d8a7a 100644
--- a/paramecio/cromosoma/coreforms.py
+++ b/paramecio/cromosoma/coreforms.py
@@ -1,13 +1,55 @@
#!/usr/bin/env python3
+"""
+Parameciofm is a series of wrappers for Bottle.py, mako and others and construct a simple headless cms.
+
+Copyright (C) 2024 Antonio de la Rosa Caballero
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+"""
+
+
from collections import OrderedDict
from html import escape
#Forms para python3
class BaseForm:
+ """The class used by all forms classes
+
+ BaseForm is the base class used for all form classes.
+
+ A form class is used for generate simple html forms, how input type, text type, hidden type, etc. PhangoField classes use this forms for generate automatically forms using GenerateAdminClass and others.
+ """
def __init__(self, name, value):
+ """
+ Args:
+ name (str): The html name for this form
+ value (str): The default value of this html form.
+
+ Attributes:
+ label (str): Label used in functions how show_form that generate a complete html form from a form class list
+ name (str): Name of the html form.
+ default_value (mixed): The default value of the form. Equal to value in typical html form.
+ css (str): Used for add css classes to the html form
+ type (str): Variable used for conventional html forms with html tag
+ field (PhangoField): Field related with this form. Used in PhangoField.
+ required (boolean): If form is required or not, used in functions that generate forms.
+ name_field_id (str): The html id for the html form. Used for html things.
+ help (str): A string with help text, used in functions that generate forms.
+ """
self.label=name
self.name=name
@@ -17,26 +59,45 @@ class BaseForm:
self.field=None
self.required=False
self.txt_error=''
+ self.error=False
self.name_field_id=self.name+'_form'
self.help=''
+ self.placeholder=''
def form(self):
+ """Method for returm the html code of the form
+ """
- return ''
+ return ''
def show_formatted(self, value):
+ """Method for show the value of form formatted
+
+ Args:
+ value (mixed): The value of field form
+ """
return value
#Method for escape value for html input. DON'T CHANGE IF YOU DON'T KNOWN WHAT ARE YOU DOING
def setform(self, value):
+ """A method for set the value in the form for escape and other things
+
+ Args:
+ value (mixed): The value of field form for set
+ """
value=str(value)
return value.replace('"', '"').replace("'", ''')
def change_name(self, new_name):
+ """A method for change the default form html name of the field form
+
+ Args:
+ new_name (str): The new name of the form. Always is finished with _form suffix
+ """
self.name=new_name
@@ -45,6 +106,8 @@ class BaseForm:
return ""
class SimpleTextForm(BaseForm):
+ """Form for simple text
+ """
def __init__(self, name, value):
super().__init__(name, value)
@@ -56,6 +119,8 @@ class SimpleTextForm(BaseForm):
return super().form()+' '+self.after_text
class TextForm(BaseForm):
+ """Form for simple text form
+ """
def __init__(self, name, value):
super(TextForm, self).__init__(name, value)
@@ -65,6 +130,8 @@ class TextForm(BaseForm):
return ''
class PasswordForm(BaseForm):
+ """Form for password forms
+ """
def __init__(self, name, value, show_password=False):
super(PasswordForm, self).__init__(name, value)
@@ -79,6 +146,8 @@ class PasswordForm(BaseForm):
return value
class HiddenForm(BaseForm):
+ """Form for hidden forms
+ """
def __init__(self, name, value):
super(HiddenForm, self).__init__(name, value)
@@ -86,8 +155,16 @@ class HiddenForm(BaseForm):
class SelectForm(BaseForm):
+ """Form for select html form
+ """
def __init__(self, name, value, elements=OrderedDict()):
+ """
+ Args:
+ name (str): The html name for this form
+ value (str): The default value of this html form
+ elements (OrderedDict): An ordered dict with the keys(the form value) and text label. Example, if you have a OrderedDict how {'0': 'Value selected'} in a html select form you have the next result: