From 6dc5a616997e4a68bdc6cbcaf940c2f65c70ad07 Mon Sep 17 00:00:00 2001 From: Antonio de la Rosa Date: Tue, 6 Dec 2016 04:01:32 +0100 Subject: [PATCH] Many fixes for more performance --- paramecio/citoplasma/base_admin.py | 2 +- paramecio/citoplasma/generate_admin_class.py | 8 +- paramecio/citoplasma/i18n.py | 15 +- paramecio/citoplasma/lists.py | 2 +- paramecio/citoplasma/mtemplates.py | 17 +- paramecio/citoplasma/sessions.py | 101 ++++- paramecio/cromosoma/databases/mysqldb.py | 4 +- paramecio/cromosoma/formsutils.py | 2 +- paramecio/cromosoma/webmodel.py | 383 ++++++++++--------- paramecio/index.py | 16 +- paramecio/modules/admin/index.py | 29 +- paramecio/modules/admin/models/admin.py | 14 +- paramecio/modules/welcome/index.py | 4 +- 13 files changed, 340 insertions(+), 257 deletions(-) diff --git a/paramecio/citoplasma/base_admin.py b/paramecio/citoplasma/base_admin.py index 72e1073..06e9673 100644 --- a/paramecio/citoplasma/base_admin.py +++ b/paramecio/citoplasma/base_admin.py @@ -47,7 +47,7 @@ def base_admin(func_view, env, title, **args): content_index=func_view(connection, t, s, **args) - return t.load_template('admin/content.html', title=title, content_index=content_index, menu=menu, lang_selected=lang_selected, arr_i18n=I18n.dict_i18n) + return t.render_template('admin/content.html', title=title, content_index=content_index, menu=menu, lang_selected=lang_selected, arr_i18n=I18n.dict_i18n) else: redirect(make_url(config.admin_folder)) diff --git a/paramecio/citoplasma/generate_admin_class.py b/paramecio/citoplasma/generate_admin_class.py index 08e43b5..8d18869 100644 --- a/paramecio/citoplasma/generate_admin_class.py +++ b/paramecio/citoplasma/generate_admin_class.py @@ -85,7 +85,7 @@ class GenerateAdminClass: form=show_form(post, edit_forms, self.t, False) - return self.t.load_template(self.template_insert, admin=self, title_edit=title_edit, form=form, model=self.model, id=getpostfiles.get['id']) + return self.t.render_template(self.template_insert, admin=self, title_edit=title_edit, form=form, model=self.model, id=getpostfiles.get['id']) elif getpostfiles.get['op_admin']=='2': @@ -118,7 +118,7 @@ class GenerateAdminClass: redirect(self.url) else: form=show_form(getpostfiles.post, edit_forms, self.t, True) - return self.t.load_template(self.template_insert, admin=self, title_edit=title_edit, form=form, model=self.model, id=getpostfiles.get['id']) + return self.t.render_template(self.template_insert, admin=self, title_edit=title_edit, form=form, model=self.model, id=getpostfiles.get['id']) pass @@ -137,8 +137,8 @@ class GenerateAdminClass: else: - return self.t.load_template(self.template_verify_delete, url=self.url, item_id=getpostfiles.get['id'], op_admin=3, verified=1) + return self.t.render_template(self.template_verify_delete, url=self.url, item_id=getpostfiles.get['id'], op_admin=3, verified=1) else: - return self.t.load_template(self.template_admin, admin=self) + return self.t.render_template(self.template_admin, admin=self) diff --git a/paramecio/citoplasma/i18n.py b/paramecio/citoplasma/i18n.py index ed559e8..bf1b018 100644 --- a/paramecio/citoplasma/i18n.py +++ b/paramecio/citoplasma/i18n.py @@ -33,18 +33,19 @@ class I18n: l={} + #@staticmethod + #def set_lang(code_lang): + # if default_lang + + @staticmethod def get_default_lang(): lang=I18n.default_lang - s=get_session() - - if s==None: - - s={'lang': lang} - - lang=s.get('lang', lang) + #s=get_session() + + #lang=s.get('lang', lang) return lang diff --git a/paramecio/citoplasma/lists.py b/paramecio/citoplasma/lists.py index 1908b35..2af62b2 100644 --- a/paramecio/citoplasma/lists.py +++ b/paramecio/citoplasma/lists.py @@ -197,7 +197,7 @@ class SimpleList: self.model.yes_reset_conditions=True - listing=self.t.load_template('utils/list.phtml', simplelist=self, list=list_items, pages=pages) + listing=self.t.render_template('utils/list.phtml', simplelist=self, list=list_items, pages=pages) list_items.close() diff --git a/paramecio/citoplasma/mtemplates.py b/paramecio/citoplasma/mtemplates.py index 5085719..56785c0 100644 --- a/paramecio/citoplasma/mtemplates.py +++ b/paramecio/citoplasma/mtemplates.py @@ -62,9 +62,21 @@ def env_theme(module, cache_enabled=True, cache_impl='', cache_args={}, module_d #Standard templates #print(standard_templates) return TemplateLookup(directories=search_folders, default_filters=['h'], input_encoding='utf-8', encoding_errors='replace', cache_enabled=cache_enabled, cache_impl=cache_impl, cache_args=cache_args, module_directory=module_directory) + +def preload_templates(template_files, env): + + templates={} + + for template_file in template_files: + + templates[template_file]=env.get_template(template_file) + + return templates class PTemplate: + templates_loaded={} + def __init__(self, environment): # A simple method used in internal things of paramecio @@ -193,9 +205,12 @@ class PTemplate: def render_template(self, template_file, **arguments): + if not str(self.env.directories)+'/'+template_file in PTemplate.templates_loaded: + PTemplate.templates_loaded[str(self.env.directories)+'/'+template_file]=self.env.get_template(template_file) + arguments.update(self.filters) - return self.templates[template_file].render(**arguments) + return PTemplate.templates_loaded[str(self.env.directories)+'/'+template_file].render(**arguments) def add_filter(self, filter_name): diff --git a/paramecio/citoplasma/sessions.py b/paramecio/citoplasma/sessions.py index e14c6d0..754e9b8 100644 --- a/paramecio/citoplasma/sessions.py +++ b/paramecio/citoplasma/sessions.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 -from itsdangerous import JSONWebSignatureSerializer +from itsdangerous import URLSafeSerializer from paramecio.citoplasma.keyutils import create_key_encrypt, create_key_encrypt_256, create_key from bottle import request, response +import os +import json try: @@ -11,22 +13,22 @@ try: except: class config: - cookie_name='paramecio_session' + cookie_name='paramecio.session' key_encrypt=create_key_encrypt_256(30) - -""" + +# Cookie session +# This save the session in a cookie for maximum performance. In next version i can use memcached or something for session +# In next versions have two secret_keys for more security. + class ParamecioSession: - def __init__(self): - self.session=request.environ.get(config.cookie_name) - #self.token=request.get_cookie(config.cookie_name) + def __init__(self, session_dict): + self.session=session_dict def get(self, name, default_value): if not name in self.session: self.session[name]=default_value - request.environ[config.cookie_name]=self.session - request.environ[config.cookie_name]['save']=True return self.session[name] @@ -37,14 +39,11 @@ class ParamecioSession: def __setitem__(self, key, value): self.session[key]=value - request.environ[config.cookie_name]=self.session - request.environ[config.cookie_name]['save']=True def __delitem__(self, key): - del self.session[key] - request.environ[config.cookie_name]=self.session - request.environ[config.cookie_name]['save']=True + if key!='token': + del self.session[key] def __contains__(self, key): @@ -64,14 +63,74 @@ class ParamecioSession: def remove(self): response.delete_cookie(config.cookie_name, path="/") + + def delete(self): + self.remove() + + def save(self): + + path_cookie=config.session_opts['session.data_dir']+'/session_'+self.session['token'] + + with open(path_cookie, 'w') as f: + f.write(json.dumps(self.session)) + -def generate_session(): +def generate_session(session={}): - random_text=create_key_encrypt_256(30) - response.set_cookie(config.cookie_name, random_text, secret=config.key_encrypt, path="/") - request.environ[config.cookie_name]={'token': random_text} -""" + #secret=URLSafeSerializer(config.key_encrypt) + + #session=secret.dumps(session) + + token=create_key(30).replace('/', '#') + + response.set_cookie(config.cookie_name, token, path=config.session_opts['session.path']) + + s={'token': token} + + request.environ['session']=s + + return s +def get_session(): + + s={} + + if request.environ: + + if not 'session' in request.environ: + + cookie=None + + if request.cookies.get(config.cookie_name): + cookie=request.get_cookie(config.cookie_name) + + if not cookie: + + s=generate_session() + + else: + + path_cookie=config.session_opts['session.data_dir']+'/session_'+cookie + + if os.path.isfile(path_cookie): + + with open(path_cookie) as f: + s=json.loads(f.read()) + else: + s={'token': cookie} + + request.environ['session']=s + + + else: + + s=request.environ['session'] + + return ParamecioSession(s) + + + +""" def generate_session(): s=request.environ.get(config.cookie_name) s.invalidate() @@ -90,8 +149,8 @@ def get_session(): except: return None - - """ +""" +""" try: # Check if session was loaded, if loaded, get cache diff --git a/paramecio/cromosoma/databases/mysqldb.py b/paramecio/cromosoma/databases/mysqldb.py index 323dd77..a558ba4 100644 --- a/paramecio/cromosoma/databases/mysqldb.py +++ b/paramecio/cromosoma/databases/mysqldb.py @@ -11,8 +11,8 @@ class SqlClass: def __init__(self): - self.max_overflow=45 - self.pool_size=30 + self.max_overflow=65 + self.pool_size=45 self.error_connection="" self.connection={} self.connected=False diff --git a/paramecio/cromosoma/formsutils.py b/paramecio/cromosoma/formsutils.py index 01907d1..d21bd60 100644 --- a/paramecio/cromosoma/formsutils.py +++ b/paramecio/cromosoma/formsutils.py @@ -70,7 +70,7 @@ def show_form(post, arr_form, t, yes_error=True, pass_values=True, modelform_tpl if pass_values==True: pass_values_to_form(post, arr_form, yes_error) - return t.load_template(modelform_tpl, forms=arr_form) + return t.render_template(modelform_tpl, forms=arr_form) #Simple Function for add repeat_password form to user model diff --git a/paramecio/cromosoma/webmodel.py b/paramecio/cromosoma/webmodel.py index fe892ce..c5b4c94 100644 --- a/paramecio/cromosoma/webmodel.py +++ b/paramecio/cromosoma/webmodel.py @@ -5,10 +5,194 @@ import re import uuid from importlib import import_module, reload from collections import OrderedDict -from paramecio.cromosoma.databases.pymysql import SqlClass +from paramecio.cromosoma.databases.mysqldb import SqlClass from paramecio.cromosoma.coreforms import BaseForm, HiddenForm import traceback +class PhangoField: + + def __init__(self, name, size=255, required=False): + + # The name of the field in database table + + self.name=name + + # The label for the Field + + self.label=name.replace('_', ' ').title() + + # If field is required, self.required is True + + self.required=required + + # The size of field in database + + self.size=size + + # Protected, if this value != False, cannot use it in insert or update. + + self.protected=False + + # $quote_open is used if you need a more flexible sql sentence, + # @warning USE THIS FUNCTION IF YOU KNOW WHAT YOU ARE DOING + + self.quot_open='\'' + + # $quote_close is used if you need a more flexible sql sentence, + # @warning USE THIS PROPERTY IF YOU KNOW WHAT YOU ARE DOING + + self.quot_close='\'' + + # Variable where the basic text error is saved + + self.error=None + + self.txt_error="" + + # Themodel where this component or field live + + self.model=None + + # Property used for set this field how indexed in the database table. + + self.indexed=False + + # Property used for set this field how unique value in the database table. + + self.unique=False + + # Simple property for make more easy identify foreignkeyfields. + + self.foreignkey=False + + # Property that define the default value for this field + + self.default_value="" + + # Property that define if this field is in an update operation or insert operation + + self.update=False + + # Property used for check if this value cannot change if is in blank and is filled + + self.check_blank=False + + # Define the form, when is created forms with create_forms you can change the properties of this class + + self.name_form=BaseForm + + # Property that define if make escape in show_formatted. This property control the html transformation of <>" characters in html entities.If false, convert. + + self.escape=False + + # File related: if the field have a file related, delete the file + + self.file_related=False + + # Extra parameters for the form + + self.extra_parameters=[] + + # Template manager for the form if needed + + self.t=None + + # This method is used for describe the new field in a sql language format. + + + def get_type_sql(self): + + return 'VARCHAR('+str(self.size)+') NOT NULL DEFAULT "'+self.default_value+'"' + + def show_formatted(self, value): + + return value + + # This method for check the value + + + def check(self, value): + + self.error=False + self.txt_error='' + + value=str(value) + + if self.escape==False: + value=value.replace('<', '<') + + value=value.replace('>', '>') + + value=value.replace('"', '"') + + #value=WebModel.escape_sql(value) + + if value=="": + self.txt_error="The field is empty" + self.error=True + + + return value + + def set_relationships(self): + pass + + def create_form(self): + #self.name, self.default_value, + + self.extra_parameters.insert(0, self.name) + self.extra_parameters.insert(1, self.default_value) + form=self.name_form(*self.extra_parameters) + form.default_value=self.default_value + form.required=self.required + form.label=self.label + form.field=self + return form + + def change_form(self, new_form, parameters): + + self.name_form=new_form + + self.extra_parameters=parameters + + def post_register(self): + pass + +class PrimaryKeyField(PhangoField): + + def __init__(self, name, size=11, required=False): + super(PrimaryKeyField, self).__init__(name, size, required) + self.protected=True + self.name_form=HiddenForm + self.required=True + + def check(self, value): + + self.error=None + self.txt_error='' + + if value=='': + value='0' + + try: + + value=str(int(value)) + + except: + + value=0 + + if value==0: + self.txt_error="The value is zero" + self.error=True + + + return value + + def get_type_sql(self): + + return 'INT NOT NULL PRIMARY KEY AUTO_INCREMENT' + # The most important class for the framework # # Webmodel is a class for create objects that represent models. This models are a mirage of SQL tables. You can create fields, add indexes, foreign keys, and more. @@ -26,6 +210,7 @@ class WebModel: arr_sql_set_unique={} last_query="" connection_pool=[] + first_primary_key=PrimaryKeyField('id') #A dictionary for add models here @@ -103,13 +288,20 @@ class WebModel: self.required_save={} #Create id field + + primary_key=WebModel.first_primary_key + + primary_key.name=self.name_field_id + + self.register(primary_key) + self.register(PrimaryKeyField(self.name_field_id)) #self.model[name]=self self.yes_reset_conditions=True - self.create_fields() + #self.create_fields() self.updated=False @@ -955,190 +1147,3 @@ class WebModel: self.close() """ -class PhangoField: - - def __init__(self, name, size=255, required=False): - - # The name of the field in database table - - self.name=name - - # The label for the Field - - self.label=name.replace('_', ' ').title() - - # If field is required, self.required is True - - self.required=required - - # The size of field in database - - self.size=size - - # Protected, if this value != False, cannot use it in insert or update. - - self.protected=False - - # $quote_open is used if you need a more flexible sql sentence, - # @warning USE THIS FUNCTION IF YOU KNOW WHAT YOU ARE DOING - - self.quot_open='\'' - - # $quote_close is used if you need a more flexible sql sentence, - # @warning USE THIS PROPERTY IF YOU KNOW WHAT YOU ARE DOING - - self.quot_close='\'' - - # Variable where the basic text error is saved - - self.error=None - - self.txt_error="" - - # Themodel where this component or field live - - self.model=None - - # Property used for set this field how indexed in the database table. - - self.indexed=False - - # Property used for set this field how unique value in the database table. - - self.unique=False - - # Simple property for make more easy identify foreignkeyfields. - - self.foreignkey=False - - # Property that define the default value for this field - - self.default_value="" - - # Property that define if this field is in an update operation or insert operation - - self.update=False - - # Property used for check if this value cannot change if is in blank and is filled - - self.check_blank=False - - # Define the form, when is created forms with create_forms you can change the properties of this class - - self.name_form=BaseForm - - # Property that define if make escape in show_formatted. This property control the html transformation of <>" characters in html entities.If false, convert. - - self.escape=False - - # File related: if the field have a file related, delete the file - - self.file_related=False - - # Extra parameters for the form - - self.extra_parameters=[] - - # Template manager for the form if needed - - self.t=None - - # This method is used for describe the new field in a sql language format. - - - def get_type_sql(self): - - return 'VARCHAR('+str(self.size)+') NOT NULL DEFAULT "'+self.default_value+'"' - - def show_formatted(self, value): - - return value - - # This method for check the value - - - def check(self, value): - - self.error=False - self.txt_error='' - - value=str(value) - - if self.escape==False: - value=value.replace('<', '<') - - value=value.replace('>', '>') - - value=value.replace('"', '"') - - #value=WebModel.escape_sql(value) - - if value=="": - self.txt_error="The field is empty" - self.error=True - - - return value - - def set_relationships(self): - pass - - def create_form(self): - #self.name, self.default_value, - - self.extra_parameters.insert(0, self.name) - self.extra_parameters.insert(1, self.default_value) - form=self.name_form(*self.extra_parameters) - form.default_value=self.default_value - form.required=self.required - form.label=self.label - form.field=self - return form - - def change_form(self, new_form, parameters): - - self.name_form=new_form - - self.extra_parameters=parameters - - def post_register(self): - pass - -class PrimaryKeyField(PhangoField): - - def __init__(self, name, size=11, required=False): - super(PrimaryKeyField, self).__init__(name, size, required) - self.protected=True - self.name_form=HiddenForm - self.required=True - - def check(self, value): - - self.error=None - self.txt_error='' - - if value=='': - value='0' - - try: - - value=str(int(value)) - - except: - - value=0 - - if value==0: - self.txt_error="The value is zero" - self.error=True - - - return value - - def get_type_sql(self): - - return 'INT NOT NULL PRIMARY KEY AUTO_INCREMENT' - - - - diff --git a/paramecio/index.py b/paramecio/index.py index 13ad0eb..68e6218 100644 --- a/paramecio/index.py +++ b/paramecio/index.py @@ -59,21 +59,17 @@ routes={} module_loaded=None -#Import modules to load +#Getting paths for loaded modules for use in media load files for module in config.modules: - controller_path=load(module) - - controller_base=os.path.dirname(controller_path.__file__) + #controller_path=sys.modules[module] + + controller_base=sys.modules[module].__path__[0] base_module=module.split('.')[-1] arr_module_path[base_module]=controller_base - - dir_controllers=os.listdir(controller_base) - - #add_func_static_module(controller_base) #Prepare ssl @@ -166,7 +162,7 @@ if config.session_enabled==True: app.add_hook('after_request', save_session) #def """ - app = SessionMiddleware(app, config.session_opts, environ_key=config.cookie_name) + #app = SessionMiddleware(app, config.session_opts, environ_key=config.cookie_name) # Clean last slash @@ -185,7 +181,7 @@ set_timezone() def run_app(app): - run(app=app, host=config.host, server=config.server_used, port=config.port, debug=config.debug, reloader=config.reloader) + run(app=app, host=config.host, server=config.server_used, port=config.port, debug=config.debug, reloader=config.reloader, interval=0.5) """ if __name__ == "__main__": run(app=app, host=config.host, server=config.server_used, port=config.port, debug=config.debug, reloader=config.reloader) diff --git a/paramecio/modules/admin/index.py b/paramecio/modules/admin/index.py index f05cb49..f7c0620 100644 --- a/paramecio/modules/admin/index.py +++ b/paramecio/modules/admin/index.py @@ -98,10 +98,10 @@ def home(module='', submodule=''): c=user_admin.select_count() if c>0: - + if s['privileges']==2: #pass - + if module in menu: #Load module @@ -140,17 +140,22 @@ def home(module='', submodule=''): title_module=content_index[0] content_index=content_index[1] - return t.load_template('admin/content.html', title=title_module, content_index=content_index, menu=menu, lang_selected=lang_selected, arr_i18n=I18n.dict_i18n) + return t.render_template('admin/content.html', title=title_module, content_index=content_index, menu=menu, lang_selected=lang_selected, arr_i18n=I18n.dict_i18n) else: return content_index else: - return t.load_template('admin/index.html', title=I18n.lang('admin', 'welcome_to_paramecio', 'Welcome to Paramecio Admin!!!'), menu=menu, lang_selected=lang_selected, arr_i18n=I18n.dict_i18n) + return t.render_template('admin/index.html', title=I18n.lang('admin', 'welcome_to_paramecio', 'Welcome to Paramecio Admin!!!'), menu=menu, lang_selected=lang_selected, arr_i18n=I18n.dict_i18n) + + + return "" else: logout() + + return "" else: @@ -198,7 +203,7 @@ def home(module='', submodule=''): #connection.close() - return t.load_template('admin/login.phtml', forms=forms, yes_recovery_login=yes_recovery_login) + return t.render_template('admin/login.phtml', forms=forms, yes_recovery_login=yes_recovery_login) else: @@ -208,8 +213,10 @@ def home(module='', submodule=''): forms=show_form(post, user_admin.forms, t, yes_error=False) - return t.load_template('admin/register.phtml', forms=forms) - + return t.render_template('admin/register.phtml', forms=forms) + + return "" + @post('/'+config.admin_folder+'/login') def login(): @@ -413,7 +420,7 @@ def recovery_password(): #connection.close() - return t.load_template('admin/recovery.phtml', forms=forms) + return t.render_template('admin/recovery.phtml', forms=forms) @post('/'+config.admin_folder+'/recovery_password') def send_password(): @@ -462,7 +469,7 @@ def send_password(): send_mail=SendMail() - content_mail=t.load_template('admin/recovery_mail.phtml', token=token) + content_mail=t.render_template('admin/recovery_mail.phtml', token=token) if not send_mail.send(email_address, [email], I18n.lang('admin', 'send_email', 'Email for recovery your password'), content_mail): return {'email': 'Error: i cannot send mail', 'error': 1} @@ -475,7 +482,7 @@ def send_password(): def check_token(): t=PTemplate(env) - return t.load_template('admin/check_token.phtml') + return t.render_template('admin/check_token.phtml') @post('/'+config.admin_folder+'/check_token') def check_code_token(): @@ -518,7 +525,7 @@ def check_code_token(): send_mail=SendMail() - content_mail=t.load_template('admin/recovery_password.phtml', password=new_password) + content_mail=t.render_template('admin/recovery_password.phtml', password=new_password) if not send_mail.send(email_address, [arr_user['email']], I18n.lang('admin', 'send_password_email', 'Your new password'), content_mail): return {'token': 'Error: i cannot send mail', 'error': 1} diff --git a/paramecio/modules/admin/models/admin.py b/paramecio/modules/admin/models/admin.py index f2b6805..bd46130 100644 --- a/paramecio/modules/admin/models/admin.py +++ b/paramecio/modules/admin/models/admin.py @@ -29,23 +29,23 @@ class UserAdmin(UserModel): super().__init__(connection) # I can change other fields here, how the name. - + self.register(corefields.CharField('username')) - + self.fields['username'].required=True - + self.register(PasswordField('password')) self.fields['password'].required=True - + self.register(EmailField('email')) self.fields['email'].required=True - + self.register(corefields.CharField('token_recovery')) self.register(corefields.CharField('token_login')) - + self.register(PrivilegesField('privileges')) self.register(LangField('lang', 20)) @@ -53,7 +53,7 @@ class UserAdmin(UserModel): self.register(corefields.BooleanField('disabled')) self.register(corefields.IntegerField('num_tries', 1)) - + """ user_admin=WebModel('user_admin') diff --git a/paramecio/modules/welcome/index.py b/paramecio/modules/welcome/index.py index 21a00f1..5dcdaae 100644 --- a/paramecio/modules/welcome/index.py +++ b/paramecio/modules/welcome/index.py @@ -13,14 +13,14 @@ def home(): t=PTemplate(env) - return t.load_template('welcome.html', title="Welcome to Paramecio!!!", content="The simple web framework writed in Python3!!!") + return t.render_template('welcome.html', title="Welcome to Paramecio!!!", content="The simple web framework writed in Python3!!!") @route('/welcome/') def page(id): t=PTemplate(env) - return t.load_template('index.html', title="A simple example of a page", id=id, value=request.query.value) + return t.render_template('index.html', title="A simple example of a page", id=id, value=request.query.value) @route('/welcome/test/') def test(id):