#!/usr/bin/env python3
"""
Paramecio2fm is a series of wrappers for Flask, mako and others and construct a simple headless cms.
Copyright (C) 2023 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 paramecio2.libraries.db import corefields
from paramecio2.libraries.db.coreforms import PasswordForm
from paramecio2.libraries.i18n import I18n
from paramecio2.libraries.keyutils import create_key_encrypt
from paramecio2.libraries.i18n import I18n, PGetText
# For tests outing the web framework
try:
from settings import config
except:
class config:
pass
framework='flask'
if hasattr(config, 'framework'):
framework=config.framework
if framework=='flask':
from flask import session, request, abort
elif framework=='fastapi':
from parameciofast.libraries.sessions import get_session
pass
# Need unittest
"""Functions and classes for process forms"""
def pass_values_to_form(post, arr_form, yes_error=True, pass_values=True):
"""Function for pass a dict with form values for check using forms dict
Values dict and Forms dict need have the same key. A forms dict is maked of a serie of paramecio2 forms elements, used for check the value.
Args:
post (dict): Dict composed by a series of values. The keys need to be equal to keys of arr_form dict.
arr_form (dict): Dict composed by a series or forms objects. The keys need to be equal to keys of post dict.
yes_error (bool): Show errors in txt_error form variables.
pass_values (bool): Pass default values or values from post dict to arr_form dict items
Returns:
arr_form (dict): Return arr_form dict with checked values from post dict.
"""
if pass_values:
def get_value(key):
return post[key]
else:
def get_value(key):
return arr_form[key].default_value
for key, value in arr_form.items():
post[key]=post.get(key, '')
#if arr_form[key].default_value=='':
arr_form[key].default_value=get_value(key)
if arr_form[key].field==None:
arr_form[key].field=corefields.CharField(key, 255, required=False)
# Recheck value if no set error field
if arr_form[key].field.error == None:
arr_form[key].field.check(post[key])
#arr_form[key].txt_error=""
if arr_form[key].required==True and arr_form[key].field.error==True and yes_error==True:
arr_form[key].txt_error=arr_form[key].field.txt_error
# Reset error on field.
arr_form[key].field.error=None
return arr_form
class CheckForm():
"""Simple class for make similar check to pass_values_to_form. More simple.
"""
def __init__(self):
self.error=0
def check(self, post, arr_form):
"""Simple method for pass a dict with form values for check using forms dict
Values dict and Forms dict need have the same key. A forms dict is maked of a serie of paramecio2 forms elements, used for check the value.
Args:
post (dict): Dict composed by a series of values. The keys need to be equal to keys of arr_form dict.
arr_form (dict): Dict composed by a series or forms objects. The keys need to be equal to keys of post dict.
Returns:
post (dict): Return post dict with values checked
arr_form (dict): Return arr_form with errors and values.
"""
for k in arr_form.keys():
post[k]=post.get(k, '')
if arr_form[k].field==None:
arr_form[k].field=corefields.CharField(k, 255, required=False)
post[k]=arr_form[k].field.check(post[k])
arr_form[k].txt_error=arr_form[k].field.txt_error
if arr_form[k].field.error==True and arr_form[k].required==True:
self.error+=1
return post, arr_form
def check_form(post, arr_form, sufix_form='_error'):
"""Function for make check form, passing errors to extra dict called error_form. Also returns an bool variable setting error.
Args:
post (dict): Dict composed by a series of values. The keys need to be equal to keys of arr_form dict.
arr_form (dict): Dict composed by a series or forms objects. The keys need to be equal to keys of post dict.
sufix_form (str): Define the sufix of error_form keys
Returns:
error (bool): Return False if not errors in checking, if errors return True
error_form (dict): A dict containing the errors in form fields.
post (dict): Sanitized values
arr_form (dict): arr_form with errors and values.
"""
error=0
error_form={}
for k in arr_form.keys():
post[k]=post.get(k, '')
if arr_form[k].field==None:
arr_form[k].field=corefields.CharField(k, 255, required=False)
post[k]=arr_form[k].field.check(post[k])
arr_form[k].txt_error=arr_form[k].field.txt_error
if arr_form[k].field.error==True and arr_form[k].required==True:
error_form['#'+k+sufix_form]=arr_form[k].txt_error
error+=1
return error, error_form, post, arr_form
def show_form(post, arr_form, t, yes_error=True, pass_values=True, modelform_tpl='forms/modelform.phtml'):
"""Function for generate a html form from a template
Args:
post (dict): Dict composed by a series of values. The keys need to be equal to keys of arr_form dict.
arr_form (dict): Dict composed by a series or forms objects. The keys need to be equal to keys of post dict.
t (PTemplate): Object used for load template for form
yes_error (bool): Show errors in txt_error form variables.
pass_values (bool): Pass default values or values from post dict to arr_form dict items
modelform_tpl (str): Path for the template that generate the html form. By default is paramecio2/libraries/templates/forms/modelform.phtml
Returns:
template (str): An html string with the generated form.
"""
# Create csrf_token in session
#generate_csrf()
if pass_values==True:
pass_values_to_form(post, arr_form, yes_error, pass_values)
return t.load_template(modelform_tpl, forms=arr_form)
def extract_post(post, fields):
"""Helper function for create a simple array from other using fields list for filter
Args:
post (dict): A dict with keys and values to filter.
fields (list): A list with keys to validate.
"""
return {k:v for k,v in post.items() if k in fields}
#Simple Function for add repeat_password form to user model
def set_extra_forms_user(user_admin):
"""Helper function for add extraforms to UserModel form, not for general use
Args:
user_admin (UserModel): Instance of UserModel object for modify forms and fields
"""
user_admin.fields['password'].required=True
user_admin.fields['email'].required=True
user_admin.create_forms(['username', 'email', 'password'])
user_admin.forms['repeat_password']=PasswordForm('repeat_password', '')
user_admin.forms['repeat_password'].required=True
user_admin.forms['repeat_password'].label=_('Repeat Password')
def csrf_token(token_id='csrf_token'):
"""Function for generate a csrf token html hide form using flask sessions
Args:
token_id (str): Name of the html hide form
Returns:
html (str): Return html input hidden with csrf token saved in session
"""
#s=get_session()
if not 'csrf_token' in session:
session['csrf_token']=create_key_encrypt()
return ''
def generate_csrf():
"""Function for generate a csrf token in a variable
Returns:
csrf_token (str): csrf token value
"""
if not 'csrf_token' in session:
session['csrf_token']=create_key_encrypt()
return session['csrf_token']
def check_csrf(name_csrf_token='csrf_token'):
csrf_token=session.get('csrf_token', '')
if csrf_token=='' or csrf_token!=request.form.get(name_csrf_token):
abort(403)