diff --git a/paramecio2/libraries/db/corefields.py b/paramecio2/libraries/db/corefields.py new file mode 100644 index 0000000..88c4378 --- /dev/null +++ b/paramecio2/libraries/db/corefields.py @@ -0,0 +1,256 @@ +from paramecio2.libraries.db.webmodel import PhangoField +from paramecio2.libraries.db import coreforms +from paramecio2.libraries.i18n import I18n + +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): + super(IntegerField, self).__init__(name, size, required) + self.default_value=0 + + def check(self, value): + + """Method for check if value is integer + + Args: + value (int): The value to check + + """ + + self.error=False + self.txt_error='' + + try: + + value=str(int(value)) + + if value=="0" and self.required==True: + self.txt_error="The value is zero" + self.error=True + except: + + value="0" + self.txt_error="The value is zero" + self.error=True + + return value + + def get_type_sql(self): + + """Method for return the sql code for this type + + """ + + return 'INT('+str(self.size)+') NOT NULL DEFAULT "0"' + +class BigIntegerField(IntegerField): + + """Class that figure an big integer sql type field. + + Only change the sql type with respect to IntegerField + + """ + + def get_type_sql(self): + + """Method for return the sql code for this type + + """ + + return 'BIGINT('+str(self.size)+') NOT NULL DEFAULT "0"' + + +class FloatField(PhangoField): + + """Class that figure an float 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): + super(FloatField, self).__init__(name, size, required) + + self.error_default="The value is zero" + self.default_value=0 + + def check(self, value): + + """Method for check if value is integer + + Args: + value (float): The value to check + + """ + + self.error=False + self.txt_error='' + + try: + + value=str(value) + + if value.find(',')!=-1: + value=value.replace(',', '.') + + value=str(float(value)) + + if value==0 and self.required==True: + self.txt_error=self.error_default + self.error=True + except: + + value="0" + self.txt_error=self.error_default + self.error=True + + return value + + def get_type_sql(self): + + return 'FLOAT NOT NULL DEFAULT "0"' + +class DoubleField(FloatField): + + def get_type_sql(self): + + return 'DOUBLE NOT NULL DEFAULT "0"' + +class CharField(PhangoField): + + pass + +class TextField(PhangoField): + + def __init__(self, name, required=False): + super().__init__(name, 11, required) + + self.set_default='NOT NULL' + + def get_type_sql(self): + + """Method for return the sql code for this type + + """ + + return 'TEXT '+self.set_default + +class HTMLField(TextField): + + def __init__(self, name, required=False): + super().__init__(name, required) + + def check(self, value): + + return re.sub('<.*?script?>', '', value) + + +class ForeignKeyField(IntegerField): + + def __init__(self, name, related_table, size=11, required=False, identifier_field='id', named_field="id", select_fields=[]): + + super(ForeignKeyField, self).__init__(name, size, required) + + self.table_id=related_table.name_field_id + + self.table_name=related_table.name + + self.related_model=related_table + + self.identifier_field=identifier_field + + self.named_field=named_field + + self.select_fields=select_fields + + self.foreignkey=True + + self.change_form(coreforms.SelectModelForm, [related_table, self.named_field, self.identifier_field]) + + self.default_value=None + + def check(self, value): + + value=super().check(value) + + if value=='0' or value==0: + value='NULL' + + return value + + def get_type_sql(self): + + """Method for return the sql code for this type + + """ + + return 'INT NULL' + + +class BooleanField(IntegerField): + + def __init__(self, name, size=1): + + required=False + + self.yes_text=I18n.lang('common', 'yes', 'Yes') + self.no_text=I18n.lang('common', 'no', 'No') + + super(IntegerField, self).__init__(name, size, required) + + self.default_error="Need 0 or 1 value" + self.default_value=0 + + def check(self, value): + + self.error=False + self.txt_error='' + + try: + + value=int(value) + + if value<0 or value>1: + self.txt_error=self.default_error + self.error=True + + except: + + self.error=True + self.txt_error=self.default_error + value=0 + + value=str(value) + + return value + + def get_type_sql(self): + + """Method for return the sql code for this type + + """ + + return 'BOOLEAN NOT NULL DEFAULT "0"' + + def show_formatted(self, value): + + value=int(value) + + if value==0: + value=self.no_text + else: + value=self.yes_text + + return str(value) diff --git a/paramecio2/libraries/db/coreforms.py b/paramecio2/libraries/db/coreforms.py new file mode 100644 index 0000000..bbf360c --- /dev/null +++ b/paramecio2/libraries/db/coreforms.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 + +from collections import OrderedDict +from html import escape + +#Forms para python3 + +class BaseForm: + + def __init__(self, name, value): + + self.label=name + self.name=name + self.default_value=value + self.css='' + self.type='text' + self.field=None + self.required=False + self.txt_error='' + self.name_field_id=self.name+'_form' + self.help='' + + def form(self): + + return '' + + def show_formatted(self, value): + + 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): + + value=str(value) + + return value.replace('"', '"').replace("'", ''') + + def change_name(self, new_name): + + self.name=new_name + + self.name_field_id=self.name+'_form' + + return "" + +class SimpleTextForm(BaseForm): + + def __init__(self, name, value): + super().__init__(name, value) + + self.after_text='' + + def form(self): + + return super().form()+' '+self.after_text + +class TextForm(BaseForm): + + def __init__(self, name, value): + super(TextForm, self).__init__(name, value) + + def form(self): + + return '' + +class PasswordForm(BaseForm): + + def __init__(self, name, value): + super(PasswordForm, self).__init__(name, value) + self.type='password' + + def setform(self, value): + return "" + +class HiddenForm(BaseForm): + + def __init__(self, name, value): + super(HiddenForm, self).__init__(name, value) + self.type='hidden' + + +class SelectForm(BaseForm): + + def __init__(self, name, value, elements=OrderedDict()): + super(SelectForm, self).__init__(name, value) + self.arr_select=elements + + def form(self): + + the_form='\n' + + return the_form + +class SelectModelForm(SelectForm): + + def __init__(self, name, value, model, field_name, field_value, field_parent=None): + super(SelectModelForm, self).__init__(name, value) + + try: + self.default_value=int(self.default_value) + except: + self.default_value=0 + + self.arr_select=OrderedDict() + self.model=model + self.field_name=field_name + self.field_value=field_value + self.field_parent=field_parent + + self.form=self.normal_form + + if self.field_parent!=None: + self.form=self.parent_form + + + def normal_form(self): + + self.arr_select['']='' + + with self.model.select([self.field_name, self.field_value], True) as cur: + for arr_value in cur: + + self.arr_select[arr_value[self.field_value]]=self.model.fields[self.field_name].show_formatted(arr_value[self.field_name]) + + try: + + self.default_value=int(self.default_value) + + except: + self.default_value=0 + + return super().form() + + def parent_form(self): + + self.arr_select['']='' + + arr_son={} + + old_conditions=self.model.conditions + old_limit=self.model.limit + + self.model.limit='' + + self.model.set_conditions('WHERE 1=1', []) + + + with self.model.select([self.field_name, self.field_value, self.field_parent], True) as cur: + + for arr_value in cur: + + if not arr_value[self.field_parent] in arr_son: + + arr_son[arr_value[self.field_parent]]=[] + + arr_son[arr_value[self.field_parent]].append([arr_value[self.field_value], arr_value[self.field_name]]) + + self.create_son(0, arr_son) + + self.model.conditions=old_conditions + self.model.limit=old_limit + + try: + + self.default_value=int(self.default_value) + + except: + self.default_value=0 + + return super().form() + + + def create_son(self, parent_id, arr_son, separator=''): + + if parent_id in arr_son: + for son in arr_son[parent_id]: + self.arr_select[son[0]]=separator+son[1] + + son_separator=separator + + if son[0] in arr_son: + son_separator+='--' + self.create_son(son[0],arr_son, son_separator) diff --git a/paramecio2/libraries/db/dbadmin.py b/paramecio2/libraries/db/dbadmin.py new file mode 100644 index 0000000..58d2c6a --- /dev/null +++ b/paramecio2/libraries/db/dbadmin.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python3 + +import argparse +import os,traceback +import sys, inspect +import shutil +import re +from datetime import date +from pathlib import Path +from colorama import init, Fore, Back, Style +from importlib import import_module, reload +from paramecio2.libraries.db.webmodel import WebModel +from settings import config + +#from models import books + +def start(): + + connection=WebModel.connection() + + #connection.connect_to_db(WebModel.connections['default']) + + parser = argparse.ArgumentParser(description='A tool for create tables in databases using models from Cromosoma') + + parser.add_argument('--model', help='Model python path', required=True) + + parser.add_argument('--config', help='The config file', required=False) + + args = parser.parse_args() + + init() + + #Import config + + config_file='config' + + if args.config!=None: + config_file=args.config + + try: + + config=import_module('settings.'+config_file) + + except: + e = sys.exc_info()[0] + v = sys.exc_info()[1] + + print(Fore.WHITE+Back.RED+Style.BRIGHT+"Config file not found: %s %s" % (e, v)) + + exit(1) + + #print(WebModel.connections) + + if '/' in args.model: + + args.model=args.model.replace('/', '.')[:-3] #.replace('.py', '') + + try: + + model=import_module(args.model) + + for name, obj in inspect.getmembers(sys.modules[model.__name__]): + if inspect.isclass(obj): + if obj.__module__==args.model and hasattr(obj, 'webmodel'): + + WebModel.model[name.lower()]=obj(connection) + + + #WebModel.modelobj + + except: + """ + e = sys.exc_info()[0] + v = sys.exc_info()[1] + + print(Fore.WHITE+Back.RED+Style.BRIGHT +"Error, file with model not found: %s %s" % (e, v)) + """ + print("Exception in user code:") + print("-"*60) + traceback.print_exc(file=sys.stdout) + print("-"*60) + + exit(1) + + #load the table of databases + + cursor=connection.query("show tables") + + table_exists=[] + + for row in cursor: + table=list(row.values())[0] + + if table in WebModel.model: + table_exists.append(table) + + #If don't want order + #set([1,2,3,4]) - set([2,5]) + + tables=list(WebModel.model.keys()) + + #Array diff ordered + + new_tables=[x for x in tables if x not in table_exists] + + #If don't want order + #new_tables=set(tables)-set(table_exists) + + #Need order new_tables + + changes=0 + + #Create new tables + + if len(new_tables)>0: + print(Style.BRIGHT+"Creating new tables...") + + changes+=1 + + for table in new_tables: + print(Style.NORMAL+"--Creating table "+table+"...") + connection.query(WebModel.model[table].create_table()) + + for table in new_tables: + + print("--Adding indexes and constraints for the new table "+table) + + for k_field, index in WebModel.arr_sql_index[table].items(): + print("---Added index to "+k_field) + connection.query(index) + + for k_set, index_set in WebModel.arr_sql_set_index[table].items(): + + if index_set!="": + connection.query(index_set) + print("---Added constraint to "+k_set) + + print("--Adding uniques elements for the new table") + + #See if changes exists + + #Check if created tables are modified. + + try: + + model_old=import_module('backups.'+args.model) + + for name, obj in inspect.getmembers(sys.modules[model_old.__name__]): + if inspect.isclass(obj): + if obj.__module__=='backups.'+args.model and hasattr(obj, 'webmodel'): + + WebModel.model['old_'+name.lower()]=obj(connection) + + print(Style.BRIGHT+"Checking old versions of model for find changes...") + + for table in tables: + #connection.query("") + #Check if new table + + #fields_to_add, fields_to_modify, fields_to_add_index, fields_to_add_constraint, fields_to_add_unique, fields_to_delete_index, fields_to_delete_unique, fields_to_delete_constraint, fields_to_delete + + fields_to_add=[] + fields_to_modify=[] + fields_to_add_index=[] + fields_to_add_constraint=[] + fields_to_add_unique=[] + fields_to_delete_index=[] + fields_to_delete_unique=[] + fields_to_delete_constraint=[] + fields_to_delete=[] + + old_table='old_'+table + + if not old_table in WebModel.model: + WebModel.model[old_table]=WebModel.model[table] + + for f, v in WebModel.model[table].fields.items(): + + if not f in WebModel.model[old_table].fields: + + fields_to_add.append(f) + + #Add index + + if v.indexed==True: + + fields_to_add_index.append(f) + + changes+=1 + + #Add unique + + if v.unique==True: + + fields_to_add_unique.append(f) + + changes+=1 + + #Add constraint + + if v.foreignkey==True: + + fields_to_add_constraint.append(f) + + changes+=1 + + changes+=1 + + #If exists field in old webmodel and new + + else: + + v_old=WebModel.model[old_table].fields[f] + + if v.get_type_sql()!=v_old.get_type_sql(): + + fields_to_modify.append(f) + + changes+=1 + + #Add index + + if v.indexed==True and v_old.indexed==False: + + fields_to_add_index.append(f) + + changes+=1 + + if v.indexed==False and v_old.indexed==True: + + fields_to_delete_index.append(f) + + changes+=1 + + #Add unique + + if v.unique==True and v_old.unique==False: + + fields_to_add_unique.append(f) + + changes+=1 + + if v.unique==False and v_old.unique==True: + + fields_to_delete_unique.append(f) + + changes+=1 + + #Add constraint + + if v.foreignkey==True and v_old.foreignkey==False: + + fields_to_add_constraint.append(f) + + changes+=1 + + if v.foreignkey==False and v_old.foreignkey==True: + + fields_to_delete_constraint.append(f) + + changes+=1 + + for f, v in WebModel.model[old_table].fields.items(): + + if not f in WebModel.model[table].fields: + + #Add constraint + + if v.foreignkey==True: + + fields_to_delete_constraint.append(f) + + changes+=1 + + fields_to_delete.append(f) + + changes+=1 + + WebModel.model[table].update_table(fields_to_add, fields_to_modify, fields_to_add_index, fields_to_add_constraint, fields_to_add_unique, fields_to_delete_index, fields_to_delete_unique, fields_to_delete_constraint, fields_to_delete) + + #for field_update in arr_update: + + + #Make a for in fields, if the field not exist in old model, create, if is not same type, recreate. If no have index now, delete index, if is a new index, create, same thing with uniques + + #for field in WebModel.model + + except ImportError: + + pass + + except: + + print("Exception in user code:") + print("-"*60) + traceback.print_exc(file=sys.stdout) + print("-"*60) + + exit(1) + + original_file_path=args.model.replace('.', '/')+'.py' + + backup_path='backups/'+original_file_path + + if changes>0: + print(Style.BRIGHT+"Creating backup of the model. WARNING: DON'T DELETE BACKUPS DIRECTORY IF YOU WANT MAKE CHANGES IN THE FUTURE WITHOUT MODIFY DIRECTLY THE DATABASE") + + create_backup(original_file_path, backup_path) + + else: + if not os.path.isfile(backup_path): + create_backup(original_file_path, backup_path) + + # Execute script + + arr_script_model=args.model.split('.') + + arr_script_model.pop() + + script_model='.'.join(arr_script_model)+'.scripts.install' + + script_py=script_model.replace('.', '/')+'.py' + + if os.path.isfile(script_py): + + locked_file='/'.join(arr_script_model)+'/scripts/locked' + + if not os.path.isfile(locked_file): + + script_install=import_module(script_model) + + script_install.run() + + f=open(locked_file, 'w') + + f.write('OK') + + f.close() + + + connection.close() + + #script_model=args.model+'' + + print(Style.BRIGHT+"All tasks finished") + +def create_backup(original_file_path, file_path): + + #Create copy + + path=os.path.dirname(file_path) + + p=Path(path) + + if not p.is_dir(): + p.mkdir(0o755, True) + with open(path+'/__init__.py', 'w') as f: + f.write("#!/usr/bin/env python3\n") + + #Create path + + if os.path.isfile(file_path): + today = date.today() + shutil.copy(file_path, file_path+'.'+today.strftime("%Y%M%d%H%M%S")) + + new_file="" + + f=open(original_file_path) + + for line in f: + """ + new_line=line.replace("model[\"", "model[\"old_") + new_line=new_line.replace("model['", "model['old_") + + new_line=new_line.replace("WebModel(\"", "WebModel(\"old_") + new_line=new_line.replace("WebModel('", "WebModel('old_") + """ + new_file+=line + + f.close() + + f=open(file_path, 'w') + + f.write(new_file) + + f.close() diff --git a/paramecio2/libraries/db/extrafields/__init__.py b/paramecio2/libraries/db/extrafields/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/paramecio2/libraries/db/extrafields/arrayfield.py b/paramecio2/libraries/db/extrafields/arrayfield.py new file mode 100644 index 0000000..854ebb4 --- /dev/null +++ b/paramecio2/libraries/db/extrafields/arrayfield.py @@ -0,0 +1,59 @@ +from paramecio2.libraries.db.webmodel import PhangoField,WebModel +import json + +class ArrayField(PhangoField): + + def __init__(self, name, field_type, required=False): + + super().__init__(name, required) + + self.field_type=field_type + + self.error_default='Sorry, the json array is invalid' + + self.set_default='NOT NULL' + + def check(self, value): + + if type(value).__name__=='str': + try: + value=json.loads(value) + except json.JSONDecodeError: + + value=[] + self.error=True + self.txt_error=self.error_default + + elif type(value).__name__!='list': + + value=[] + self.error=True + self.txt_error='Sorry, the json array is invalid' + + if type(self.field_type).__name__!='ArrayField': + for k,v in enumerate(value): + + value[k]=self.field_type.check(v) + + final_value=json.dumps(value) + + final_value=WebModel.escape_sql(final_value) + + return final_value + + def get_type_sql(self): + + return 'TEXT '+self.set_default + + def show_formatted(self, value): + + return ", ".join(value) + + def loads(self, value): + + try: + + return json.loads(value) + except: + + return False diff --git a/paramecio2/libraries/db/extrafields/colorfield.py b/paramecio2/libraries/db/extrafields/colorfield.py new file mode 100644 index 0000000..9ebaeef --- /dev/null +++ b/paramecio2/libraries/db/extrafields/colorfield.py @@ -0,0 +1,47 @@ +from paramecio2.libraries.db.corefields import IntegerField +from paramecio2.libraries.db.extraforms.colorform import ColorForm + +class ColorField(IntegerField): + + def __init__(self, name, size=11, required=False): + super().__init__(name, size, required) + + self.name_form=ColorForm + + def check(self, value): + + value=str(value).replace('#', '0x') + + value=int(value, 16) + + if value<0 or value>0xffffff: + value=0 + + return value + def get_hex_color(self, value): + + value=str(hex(int(value))).replace('0x', '') + + c=len(value) + + if(c<6): + repeat=6-c + value=('0'*repeat)+value + + value='#'+value + + return value + + def show_formatted(self, value): + + value=str(hex(int(value))).replace('0x', '') + + c=len(value) + + if(c<6): + repeat=6-c + value=('0'*repeat)+value + + value='#'+value + + return '
' % value; diff --git a/paramecio2/libraries/db/extrafields/datefield.py b/paramecio2/libraries/db/extrafields/datefield.py new file mode 100644 index 0000000..40803ad --- /dev/null +++ b/paramecio2/libraries/db/extrafields/datefield.py @@ -0,0 +1,39 @@ +from paramecio2.libraries.db.corefields import PhangoField +from paramecio.citoplasma import datetime +from paramecio2.libraries.db.extraforms.dateform import DateForm + +class DateField(PhangoField): + + def __init__(self, name, size=255, required=False): + + super().__init__(name, size, required) + + self.name_form=DateForm + + self.utc=True + + self.error_default='Error: Date format invalid' + + def check(self, value): + + if self.utc: + + value=datetime.local_to_gmt(value) + + elif not datetime.obtain_timestamp(value, False): + + self.error=True + self.txt_error=self.error_default + return '' + + if value==False: + + self.error=True + self.txt_error=self.error_default + return '' + + return value + + def show_formatted(self, value): + + return datetime.format_date(value) diff --git a/paramecio2/libraries/db/extrafields/datetimefield.py b/paramecio2/libraries/db/extrafields/datetimefield.py new file mode 100644 index 0000000..9e5050d --- /dev/null +++ b/paramecio2/libraries/db/extrafields/datetimefield.py @@ -0,0 +1,60 @@ +from paramecio2.libraries.db.corefields import PhangoField +from paramecio.citoplasma import datetime +from paramecio2.libraries.db.extraforms.dateform import DateForm + +class DateTimeField(PhangoField): + + def __init__(self, name, size=255, required=False): + + super().__init__(name, size, required) + + self.name_form=DateForm + + self.utc=False + + self.error_default='Error: Date format invalid' + + def check(self, value): + + if self.utc: + + value=datetime.local_to_gmt(value) + + elif not datetime.obtain_timestamp(value, False): + + self.error=True + self.txt_error=self.error_default + return '' + + if value==False: + + self.error=True + self.txt_error=self.error_default + return '' + else: + + """ + format_date_txt="YYYY/MM/DD" + + format_time_txt="HH:mm:ss" + """ + + value=datetime.format_local_strtime('YYYY-MM-DD HH:mm:ss', value) + + return value + + def show_formatted(self, value): + + # Convert to paramecio value + value=str(value) + value=value.replace('-', '').replace(':', '').replace(' ', '') + + return datetime.format_date(value) + + def get_type_sql(self): + + """Method for return the sql code for this type + + """ + + return 'DATETIME NOT NULL' diff --git a/paramecio2/libraries/db/extrafields/dictfield.py b/paramecio2/libraries/db/extrafields/dictfield.py new file mode 100644 index 0000000..3132f7f --- /dev/null +++ b/paramecio2/libraries/db/extrafields/dictfield.py @@ -0,0 +1,50 @@ +from paramecio2.libraries.db.webmodel import WebModel, PhangoField +import json + +class DictField(PhangoField): + + def __init__(self, name, field_type, required=False): + + super().__init__(name, required) + + self.field_type=field_type + + self.error_default='Sorry, the json dict is invalid' + + self.set_default='NOT NULL' + + def check(self, value): + + if type(value).__name__=='str': + try: + value=json.loads(value) + except json.JSONDecodeError: + + value={} + self.error=True + self.txt_error=self.error_default + + elif type(value).__name__!='dict': + + value={} + self.error=True + self.txt_error=self.error_default + + for k,v in value.items(): + + value[k]=self.field_type.check(v) + + final_value=json.dumps(value) + + #final_value=WebModel.escape_sql(final_value) + + return final_value + + def get_type_sql(self): + + return 'TEXT '+self.set_default + + def show_formatted(self, value): + + return ", ".join(value) + diff --git a/paramecio2/libraries/db/extrafields/emailfield.py b/paramecio2/libraries/db/extrafields/emailfield.py new file mode 100644 index 0000000..cf47b3b --- /dev/null +++ b/paramecio2/libraries/db/extrafields/emailfield.py @@ -0,0 +1,27 @@ +from paramecio2.libraries.db.corefields import CharField +import re + +mail_pattern=re.compile("\w[\w\.-]*@\w[\w\.-]+\.\w+") + +class EmailField(CharField): + + def __init__(self, name, size=1024, required=False): + + super().__init__(name, size, required) + + self.error_default='Error: No valid format' + + def check(self, value): + + value=super().check(value) + + self.error=False + self.txt_error='' + + if not mail_pattern.match(value): + + self.error=True + value="" + self.txt_error=self.error_default + + return value diff --git a/paramecio2/libraries/db/extrafields/filefield.py b/paramecio2/libraries/db/extrafields/filefield.py new file mode 100644 index 0000000..60ec02f --- /dev/null +++ b/paramecio2/libraries/db/extrafields/filefield.py @@ -0,0 +1,176 @@ +import os +import sys +from pathlib import Path +from paramecio2.libraries.db.corefields import CharField +from paramecio2.libraries.db.extraforms.fileform import FileForm +from paramecio.citoplasma import httputils +from paramecio.citoplasma.keyutils import create_key +import traceback + +from bottle import request + + +from uuid import uuid4 +#from paramecio2.libraries.db.extraforms.fileform import FileForm + +class FileField(CharField): + + def __init__(self, name, save_folder='media/upload/files', sizes=None, module=None, size=255, required=False): + + super().__init__(name, size, required) + + self.yes_prefix=True + + self.suffix='' + + # Is relative to media folder of paramecio + + #if module!=None: + + self.save_folder=save_folder + + self.file_related=True + + self.sizes=sizes + + self.name_form=FileForm + self.extra_parameters=[self.save_folder] + + + def change_folder(self, folder): + + pass + + def check(self, value): + + files_uploaded=request.files + + field_file=self.name+'_file' + + #if not change + + if not field_file in files_uploaded: + + if value=='': + + if self.model: + + if self.model.updated: + + old_reset=self.model.yes_reset_conditions + + self.model.yes_reset_conditions=False + + with self.model.select([self.name]) as cur: + + for arr_image in cur: + + if arr_image[self.name]!='': + try: + os.remove(arr_image[self.name]) + except: + pass + + #if arr_image[self.name]!=save_file and arr_image[self.name]!='': + + #value=arr_image[self.name] + + self.model.yes_reset_conditions=old_reset + self.txt_error='Field is empty' + self.error=True + + return '' + + else: + + value=os.path.basename(value) + + return self.save_folder+'/'+value + + + # Load image file + + file_bytecode=files_uploaded[field_file].file + + filename=files_uploaded[field_file].filename + + realfilename, ext = os.path.splitext(filename) + + prefix='' + + if self.yes_prefix==True: + #prefix=uuid4().hex+'_' + prefix=create_key(5).replace('/', '-').replace('#', '-')+self.suffix+'_' + + filename=prefix+filename + + save_file=self.save_folder+'/'+filename + + # Save file + + try: + + #Check if directory exists + + if not os.path.isdir(self.save_folder): + + # Try create if not + + try: + + p=Path(self.save_folder) + + p.mkdir(mode=0o755, parents=True) + + except: + self.error=True + + self.txt_error='Error: cannot create the directory where save the image.Check permissions,' + return "" + + #files_uploaded[field_file].save(self.save_folder, overwrite=True) + + if os.path.isfile(save_file): + + os.remove(save_file) + + # Delete old files + + if self.model!=None: + + if self.model.updated: + + #old_conditions=self.model.conditions + + old_reset=self.model.yes_reset_conditions + + self.model.yes_reset_conditions=False + + with self.model.select([self.name]) as cur: + + for arr_file in cur: + + if arr_file[self.name]!=save_file and arr_file[self.name]!='': + + if os.path.isfile(arr_file[self.name]): + + os.remove(arr_file[self.name]) + + self.model.yes_reset_conditions=old_reset + + + #self.model.conditions=old_conditions + + return save_file + + except: + + self.error=True + self.txt_error='Error: cannot save the image file, Exists directory for save the file? '+traceback.format_exc() + print(traceback.format_exc()) + return "" + + def show_formatted(self, value): + + return os.path.basename(value) + diff --git a/paramecio2/libraries/db/extrafields/i18nfield.py b/paramecio2/libraries/db/extrafields/i18nfield.py new file mode 100644 index 0000000..bf7b96a --- /dev/null +++ b/paramecio2/libraries/db/extrafields/i18nfield.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +import json +from paramecio2.libraries.db.webmodel import PhangoField +from paramecio2.libraries.db.coreforms import BaseForm +from paramecio2.libraries.db.extraforms.i18nform import I18nForm +from paramecio.citoplasma.i18n import I18n +from paramecio.citoplasma.httputils import GetPostFiles +import json +import re + +class I18nField(PhangoField): + + def __init__(self, name, form=None): + + super().__init__(name) + + if form==None: + form=BaseForm(name, '') + + self.name_form=I18nForm + self.extra_parameters=[form] + self.show_formatted_value=True + self.show_blank=False + + arr_i18n={i:'' for i in I18n.dict_i18n} + self.default_value=json.dumps(arr_i18n) + + def change_form(self, form): + self.extra_parameters=[form] + + def check_value(self, value): + + return super().check(value) + + def check(self, value): + + self.error=False + self.txt_error='' + + arr_values={} + + try: + arr_values=json.loads(value) + + if not arr_values: + arr_values={} + + except: + arr_values={} + + arr_real_values={} + + error_values=0 + + for lang in I18n.dict_i18n: + arr_real_values[lang]=arr_values.get(lang, '') + arr_real_values[lang]=self.check_value(arr_real_values[lang]) + + + if not arr_real_values[lang] or arr_real_values[lang]=='None': + arr_real_values[lang]='' + error_values+=1 + + self.error=False + + arr_values=arr_real_values + + if error_values: + if error_values==len(arr_values): + self.error=True + self.txt_error='Sorry, You field language is empty' + return json.dumps(arr_values) + + + """ + if arr_values[I18n.default_lang]=='': + self.error=True + self.txt_error='Sorry, You need default language '+I18n.default_lang + return json.dumps(arr_values) + """ + + return json.dumps(arr_values) + + def get_type_sql(self): + + return 'TEXT NOT NULL' + + def obtain_lang_value(self, lang, value): + + return value.get(self.name+'_'+lang, '') + + def obtain_lang_from_post(self, lang, value): + + #getpost=GetPostFiles() + + #getpost.obtain_post() + + return "" #GetPostFiles.post.get(self.name+'_'+lang, '') + + def show_formatted(self, value): + + if value=='': + value='{"en-US": "", "es-ES": ""}' + + value=json.loads(value) + + lang=I18n.get_default_lang() + + if value[lang]!='' or self.show_blank: + + return value[lang] + + lang_value=value[I18n.default_lang] + + if value[I18n.default_lang]=='': + for l in value: + + if value[l]!='': + lang_value=value[l] + break + + return lang_value + + + @staticmethod + def get_value(value): + + value=json.loads(value) + + lang=I18n.get_default_lang() + + if value[lang]!='': + + return value[lang] + + return value[I18n.default_lang] + +class I18nHTMLField(I18nField): + + def check_value(self, value): + + return re.sub('<.*?script?>', '', value) + +class I18nPhangoField(I18nField): + + def __init__(self, name, field_class, form=None): + + super().__init__(name, form) + + self.field_class=field_class + + def check_value(self, value): + + f=self.field_class + + return f.check(value) diff --git a/paramecio2/libraries/db/extrafields/imagefield.py b/paramecio2/libraries/db/extrafields/imagefield.py new file mode 100644 index 0000000..fa1f7df --- /dev/null +++ b/paramecio2/libraries/db/extrafields/imagefield.py @@ -0,0 +1,276 @@ +import os +import sys +from pathlib import Path +from paramecio2.libraries.db.corefields import CharField +from paramecio2.libraries.db.extraforms.fileform import FileForm +from paramecio.citoplasma import httputils +from paramecio.citoplasma.keyutils import create_key +import traceback + +from bottle import request +try: + from PIL import Image +except: + print("Unexpected error:", sys.exc_info()[0]) + raise + + +from uuid import uuid4 +#from paramecio2.libraries.db.extraforms.fileform import FileForm + +class ImageField(CharField): + + def __init__(self, name, save_folder='media/upload/images', sizes=None, module=None, size=255, required=False): + + super().__init__(name, size, required) + + self.yes_prefix=True + + #self.name_form=FileForm + + self.thumbnail={'mini_': 150} + + self.yes_thumbnail=False + + self.default_quality_thumb=95 + + self.suffix='' + + # Is relative to media folder of paramecio + + #if module!=None: + + self.save_folder=save_folder + + self.file_related=True + + self.sizes=sizes + + self.name_form=FileForm + self.extra_parameters=[self.save_folder] + + + def change_folder(self, folder): + + pass + + def check(self, value): + + files_uploaded=request.files + + field_file=self.name+'_file' + + #if not change + + if not field_file in files_uploaded: + + if value=='': + + if self.model: + + if self.model.updated: + + old_reset=self.model.yes_reset_conditions + + self.model.yes_reset_conditions=False + + with self.model.select([self.name]) as cur: + + for arr_image in cur: + + if arr_image[self.name]!='': + try: + os.remove(arr_image[self.name]) + except: + pass + + #if arr_image[self.name]!=save_file and arr_image[self.name]!='': + + #value=arr_image[self.name] + + self.model.yes_reset_conditions=old_reset + self.txt_error='Field is empty' + self.error=True + + return '' + + else: + + value=os.path.basename(value) + + return self.save_folder+'/'+value + + + # Load image file + + file_bytecode=files_uploaded[field_file].file + + filename=files_uploaded[field_file].filename + + try: + + im=Image.open(file_bytecode) + + except IOError: + + self.error=True + + self.txt_error='Error, file not have a valid format' + return "" + + real_width=im.size[0] + real_height=im.size[1] + + if self.sizes: + + if 'maximum' in self.sizes: + if self.sizes['maximum'][0]
+ % endfor
+% endif
+{{form.form()}}
+ {% endfor %} +${form.form()|n} ${form.txt_error}
+ % else: + ${form.form()|n} + % endif + % endfor + ${csrf_token()|n} ++ +
+ +${add_js_home_local('tinymce/tinymce.min.js', 'admin')} diff --git a/paramecio2/libraries/templates/utils/accept.phtml b/paramecio2/libraries/templates/utils/accept.phtml new file mode 100644 index 0000000..d41419a --- /dev/null +++ b/paramecio2/libraries/templates/utils/accept.phtml @@ -0,0 +1,12 @@ +${question_text}: + +<%block name="form"> +%block> diff --git a/paramecio2/libraries/templates/utils/admin.phtml b/paramecio2/libraries/templates/utils/admin.phtml new file mode 100644 index 0000000..f5d2666 --- /dev/null +++ b/paramecio2/libraries/templates/utils/admin.phtml @@ -0,0 +1,4 @@ +${show_flash_message()|n} + +${lang('common', 'add_item', 'Add new item')}
+${admin.list.show()|n} diff --git a/paramecio2/libraries/templates/utils/insertform.phtml b/paramecio2/libraries/templates/utils/insertform.phtml new file mode 100644 index 0000000..b753fc7 --- /dev/null +++ b/paramecio2/libraries/templates/utils/insertform.phtml @@ -0,0 +1,21 @@ +${admin.text_home|n} >> \ +% if id!='0': + ${title_edit} \ +%else: + ${title_edit} \ +%endif +<% + + enctype_txt='' + + if enctype: + enctype_txt='enctype="multipart/form-data"' + +%> +
+ diff --git a/paramecio2/libraries/templates/utils/list.phtml b/paramecio2/libraries/templates/utils/list.phtml new file mode 100644 index 0000000..b843cbc --- /dev/null +++ b/paramecio2/libraries/templates/utils/list.phtml @@ -0,0 +1,135 @@ +<%def name="select_field(field)"> + % if simplelist.search_field==field: + selected \ + % endif +%def> +<%def name="set_css_arrow(simplelist, field)"> + % if simplelist.order_field==field: + + % endif +%def> +% if simplelist.yes_search: +| ${set_css_arrow(simplelist, field)}${simplelist.model.fields[field].label} | + % endfor + % for extra_field in simplelist.arr_extra_fields: +${ extra_field } | + % endfor +|||
| ${simplelist.model.fields[field].show_formatted(row[field])} | + % else: +${simplelist.model.fields[field].show_formatted(row[field])}${str(simplelist.model.fields[field].related_model.fields[simplelist.model.fields[field].named_field].show_formatted(row[field]))} | + % endif + % else: + %if type(simplelist.model.fields[field]).__name__!='ForeignKeyField': +${str(simplelist.model.fields[field].show_formatted(row[field]))|n} | + % else: +${str(simplelist.model.fields[field].related_model.fields[simplelist.model.fields[field].named_field].show_formatted(row[field]))|n} | + % endif + % endif + % endfor + + % for extra_field_func in simplelist.arr_extra_options: +${ simplelist.set_options(extra_field_func, row)|n } | + % endfor +
+% if pages!='': +${lang('common', 'pages', 'Pages')}: ${pages|n} +% endif +
diff --git a/paramecio2/libraries/templates/utils/translations.phtml b/paramecio2/libraries/templates/utils/translations.phtml new file mode 100644 index 0000000..e1f6294 --- /dev/null +++ b/paramecio2/libraries/templates/utils/translations.phtml @@ -0,0 +1,85 @@ +