Compare commits

...

10 commits

16 changed files with 179 additions and 118 deletions

View file

@ -1,4 +1,4 @@
from flask import Flask, session, url_for, escape, request, send_file, abort
from flask import Flask, session, url_for, request, send_file, abort
from settings import config
from importlib import import_module
import os
@ -24,11 +24,15 @@ def start_app():
application_root='/'
if hasattr(config, 'application_root'):
#print(config.application_root)
application_root=config.application_root
app.config.update(
APPLICATION_ROOT=application_root
)
#app.config['APPLICATION_ROOT']=application_root
if hasattr(config, 'json_sort_keys'):
app.config.update(

View file

@ -8,7 +8,7 @@ import re
from pathlib import Path
from base64 import b64encode
from paramecio2.libraries.db.webmodel import WebModel
from paramecio2.modules.admin.models.admin import UserAdmin
from paramecio2.modules.admin.models.admin import UserAdmin, LoginTries
from subprocess import call
from urllib.parse import urlparse
@ -80,49 +80,7 @@ def start():
print('Error: cannot copy the file index.py to app.py. Check if exists and if you have permissions for this task')
"""
try:
shutil.copy(workdir+'/frontend/padmin.py', args.path+'/padmin.py')
except:
print('Error: cannot copy the file padmin.py. Check if exists and if you have permissions for this task')
try:
shutil.copy(workdir+'/frontend/i18nadmin.py', args.path+'/i18nadmin.py')
except:
print('Error: cannot copy the file i18nadmin.py. Check if exists and if you have permissions for this task')
try:
shutil.copy(workdir+'/frontend/regenerate.py', args.path+'/regenerate.py')
except:
print('Error: cannot copy the file regenerate.py. Check if exists and if you have permissions for this task')
try:
shutil.copy(workdir+'/frontend/create_module.py', args.path+'/create_module.py')
except:
print('Error: cannot copy the file create_module.py. Check if exists and if you have permissions for this task')
try:
shutil.copy(workdir+'/settings/modules.py', path_settings+'/modules.py')
except:
print('Error: cannot copy the file modules.py. Check if exists and if you have permissions for this task')
"""
if args.symlink==True:
try:
os.symlink(workdir, args.path+'/paramecio2', True)
@ -178,6 +136,15 @@ def start():
conf=conf.replace("domain_url='http://localhost:5000'", "domain_url='"+domain_url+"'")
# Question about email
e_q=input('Email for site: ')
conf=conf.replace("no-reply@example.com", e_q)
#if e_q=='':
#domain_url='http://localhost:8080'
with open(path_settings+'/config.py', 'w') as f:
@ -225,6 +192,7 @@ def start():
conn=WebModel.connection()
useradmin=UserAdmin(conn)
logintries=LoginTries(conn)
# Check if db exists
@ -261,6 +229,9 @@ def start():
print('Error: cannot create table admin, you can create this table with padmin.py')
else:
sql_login=logintries.create_table()
logintries.query(sql_login)
# Add admin module to config
with open(path_settings+'/config.py', 'r') as f:

View file

@ -664,6 +664,15 @@ class TimeClass:
"""
return self.t.format(self.format_date_full)
def format_datetime(self):
"""Method for get datetime formatted using format_time attribute
Returns:
Datetime formatted with format_time attribute
"""
return self.t.format(self.format_time)
def local_to_utc(self):
"""Method for convert datetime from actual timezone to UTC"""

View file

@ -172,6 +172,20 @@ class TextField(PhangoField):
return 'TEXT '+self.set_default
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 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

View file

@ -42,12 +42,13 @@ class BaseForm:
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 '<input type="'+self.type+'" class="'+self.css+'" name="'+self.name+'" id="'+self.name_field_id+'" value="'+self.setform(self.default_value)+'" />'
return '<input type="'+self.type+'" class="'+self.css+'" name="'+self.name+'" id="'+self.name_field_id+'" value="'+self.setform(self.default_value)+'" placeholder="'+self.placeholder+'" />'
def show_formatted(self, value):
"""Method for show the value of form formatted

View file

@ -26,16 +26,17 @@ class DateTimeField(PhangoField):
value=datetime.local_to_gmt(value)
elif not datetime.obtain_timestamp(value):
self.error=True
self.txt_error=self.error_default
return ''
return '0000-00-00 00:00:00'
if value==False:
self.error=True
self.txt_error=self.error_default
return ''
return '0000-00-00 00:00:00'
else:
"""

View file

@ -5,8 +5,10 @@ from paramecio2.libraries.db.corefields import CharField
from paramecio2.libraries.db.extraforms.fileform import FileForm
from paramecio2.libraries.keyutils import create_key
import traceback
from flask import request
from werkzeug.utils import secure_filename
from bottle import request
# from bottle import request
try:
from PIL import Image
except:
@ -63,61 +65,67 @@ class ImageField(CharField):
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 field_file in files_uploaded:
if files_uploaded[field_file].filename=='':
if self.model:
if value=='':
if self.model.updated:
if self.model:
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 ''
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
else:
value=os.path.basename(value)
return self.save_folder+'/'+value
else:
value=os.path.basename(value)
return self.save_folder+'/'+value
# Load image file
file_bytecode=files_uploaded[field_file].file
#file_bytecode=files_uploaded[field_file].file
filename=files_uploaded[field_file].filename
filename=secure_filename(files_uploaded[field_file].filename)
try:
im=Image.open(file_bytecode)
im=Image.open(files_uploaded[field_file])
except IOError:

View file

@ -72,6 +72,7 @@ class JsonValueField(PhangoField):
super().__init__(name, required)
self.error_default='Sorry, the json dict is invalid'
self.default_value={}
#self.set_default='NOT NULL'
@ -86,7 +87,7 @@ class JsonValueField(PhangoField):
except json.JSONDecodeError:
final_value={}
final_value='{}'
self.error=True
self.txt_error=self.error_default

View file

@ -72,6 +72,8 @@ class GenerateAdminClass:
self.url_redirect=self.url
self.pre_update=None
self.post_update=None
self.text_home=I18n.lang('common', 'home', 'Home')
@ -131,6 +133,13 @@ class GenerateAdminClass:
insert_row=self.model.insert
pre_update_ret=False
if not self.pre_update:
pre_update_ret=True
else:
pre_update_ret=self.pre_update(self)
try:
item_id=str(int(request.args.get('id', '0')))
@ -149,21 +158,36 @@ class GenerateAdminClass:
post=dict(request.form)
if insert_row(post):
flash(I18n.lang('common', 'task_successful', 'Task successful'))
if self.post_update:
if item_id=='0':
item_id=self.model.insert_id()
self.post_update(self, item_id)
return redirect(self.url_redirect)
if pre_update_ret:
if insert_row(post):
flash(I18n.lang('common', 'task_successful', 'Task successful'))
if self.post_update:
if item_id=='0':
item_id=self.model.insert_id()
self.post_update(self, item_id)
return redirect(self.url_redirect)
else:
url_action=add_get_parameters(self.url, op_admin=2, id=item_id)
post=dict(request.form)
form=show_form(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=item_id, url_action=url_action, enctype=self.model.enctype)
else:
url_action=add_get_parameters(self.url, op_admin=2, id=item_id)
post=dict(request.form)
form=show_form(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=item_id, url_action=url_action, enctype=self.model.enctype)

View file

@ -1,4 +1,4 @@
from flask import g
from flask import g, session, redirect, url_for
from functools import wraps
from paramecio2.libraries.db.webmodel import WebModel

View file

@ -4,6 +4,7 @@ from paramecio2.modules.admin.models.admin import UserAdmin
from paramecio2.libraries.generate_admin_class import GenerateAdminClass
from paramecio2.libraries.i18n import I18n
from paramecio2.libraries.db.coreforms import SelectForm
from paramecio2.libraries.db.coreforms import HiddenForm
import copy
from paramecio2.modules.admin import admin_app, t as admin_t
@ -22,7 +23,9 @@ def ausers():
user_admin.fields['double_auth'].name_form=SelectForm
user_admin.create_forms(['username', 'password', 'email', 'privileges', 'lang', 'disabled', 'double_auth'])
user_admin.fields['last_login'].name_form=HiddenForm
user_admin.create_forms(['username', 'password', 'email', 'privileges', 'lang', 'disabled', 'double_auth', 'last_login'])
user_admin.forms['privileges'].arr_select={0: I18n.lang('admin', 'without_privileges', 'Without privileges'), 1: I18n.lang('admin', 'selected_privileges', 'Selected privileges'), 2: I18n.lang('admin', 'administrator', 'Administrator')}
@ -43,7 +46,7 @@ def ausers():
admin.list.search_fields=['username']
admin.arr_fields_edit=['username', 'password', 'repeat_password', 'email', 'lang', 'double_auth', 'disabled']
admin.arr_fields_edit=['username', 'password', 'repeat_password', 'email', 'lang', 'double_auth', 'disabled', 'last_login']
form_admin=admin.show()

View file

@ -239,6 +239,8 @@ def login():
#user_admin.set_conditions('WHERE id=%s', [arr_user['id']]).update({'token_auth': token_auth})
user_admin.fields['token_auth'].protected=False
arr_update['token_auth']=token_auth
# Send email
@ -303,7 +305,9 @@ def signup():
forms['privileges']=2
user_admin.valid_fields=['username', 'email', 'password', 'privileges']
forms['last_login']=now()
user_admin.valid_fields=['username', 'email', 'password', 'privileges', 'last_login']
user_admin.create_forms()
@ -357,6 +361,8 @@ def auth_check():
check_csrf()
you_cannot_login=0
if 'login_admin' in session:
code=request.form.get('code', '')
@ -365,23 +371,35 @@ def auth_check():
user_admin.check_user=False
c=user_admin.set_conditions('WHERE id=%s AND token_auth=%s', [session['user_id'], code]).select_count()
arr_user=user_admin.set_conditions('WHERE id=%s', [session.get('user_id', 0)]).select_a_row_where()
if c==1:
if arr_user:
user_admin.safe_query()
if user_admin.fields['token_auth'].verify(code, arr_user['token_auth']):
user_admin.set_conditions('WHERE id=%s', [session['user_id']]).update({'token_auth': ''})
user_admin.safe_query()
user_admin.set_conditions('WHERE id=%s', [session['user_id']]).update({'token_auth': ''})
session['verify_auth']=True
error=0
else:
session['verify_auth']=True
error=0
you_cannot_login=check_login_tries()
else:
you_cannot_login=check_login_tries()
return {'error': error}
return {'error': error, 'you_cannot_login': you_cannot_login}
"""
@admin_app.route('/admin/recovery_password/')
def recovery_password():
return ""
"""
def check_login_tries():

View file

@ -84,7 +84,7 @@ class UserAdmin(UserModel):
self.register(corefields.CharField('token_login'))
self.register(corefields.CharField('token_auth'))
self.register(PasswordField('token_auth'))
self.register(PrivilegesField('privileges'))

View file

@ -38,7 +38,8 @@ ${load_js()|n}
portal_admin_name_set=('Paramecio', 'Framework!')
#if hasattr(config, 'portal_admin_name_set'):
if hasattr(config, 'portal_admin_name_set'):
portal_admin_name_set=('Paramecio', 'Framework!')
%>
<span id="title_phango">${portal_admin_name_set[0]}</span> <span id="title_framework">${portal_admin_name_set[1]}</span>

View file

@ -50,7 +50,7 @@
}
else
{
$('#code_submit').prop('disabled', true);
$('#code_submit').prop('disabled', false);
// Firefox have a horrible and stupid bug and you need attr for set de new csrf_token
@ -68,6 +68,12 @@
}
if(data.you_cannot_login) {
$('#code_error').html("${lang('common', 'error_tries_disabled', 'Error, excessive tries, wait some minutes for login again')}");
}
}
});

View file

@ -5,15 +5,15 @@ import os
from setuptools import setup, find_packages
if sys.version_info < (3, 6):
raise NotImplementedError("Sorry, you need at least Python 3.6 for use paramecio2.")
if sys.version_info < (3, 8):
raise NotImplementedError("Sorry, you need at least Python 3.8 for use paramecio2.")
#import paramecio
# Pillow should be installed after if you need ImageField
# If you install passlib and bcrypt, the password system will use bcrypt by default, if not, will use native crypt libc
setup(name='paramecio2',
version='2.0.21',
version='2.0.27',
description='Simple Web Framework based in flask and Mako.',
long_description='This framework is a simple framework used for create web apps. Paramecio is modular and fast. By default have a module called admin that can be used for create admin sites',
author='Antonio de la Rosa Caballero',
@ -38,9 +38,9 @@ setup(name='paramecio2',
'Topic :: Internet :: WWW/HTTP :: WSGI :: Server',
'Topic :: Software Development :: Libraries :: Application Frameworks',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.6'
'Programming Language :: Python :: 3.8'
'Programming Language :: Python :: 3.9'
'Programming Language :: Python :: 3.10'
'Programming Language :: Python :: 3.11'
],
)