439 lines
16 KiB
Python
439 lines
16 KiB
Python
"""
|
|
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 <https://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
#By default id is not showed
|
|
|
|
from paramecio2.libraries.pages import Pages
|
|
from paramecio2.libraries.urls import add_get_parameters
|
|
from paramecio2.libraries.i18n import I18n, PGetText
|
|
#from flask import request, session
|
|
from paramecio2.libraries.get_data import get_query_args
|
|
import sys
|
|
import re
|
|
|
|
pgettext=PGetText(__file__)
|
|
_=pgettext.gettext
|
|
|
|
class SimpleList:
|
|
"""Class for create item list from a model table
|
|
"""
|
|
|
|
def __init__(self, model, url, t):
|
|
"""Class for create item list from a model table
|
|
|
|
You can create lists using a WebModel. You can select the show fields, and you have features how order by field and simple searchs.
|
|
|
|
Args:
|
|
model (WebModel): A WebModel model (equivalent to database mysql table)
|
|
url (str): A string with the base url for the forms.
|
|
t (PTemplate): Template used for the class. Normally template subclassed from admin_t PTemplate
|
|
|
|
Attributes:
|
|
raw_query (boolean): If True then raw query is done, if False then query with all related fields is done
|
|
t (PTemplate): Template used for the class. Normally template subclassed from admin_t PTemplate
|
|
model (WebModel): The webmodel used for generate the admin model form
|
|
fields (list): A list with fields names of model getting of db query
|
|
fields_showed (list): A list with fields names of model showed in list
|
|
url (str): Base url used by SimpleList for generate edit, insert and other urls.
|
|
limit_pages (int): The number of items by page. By default, 20 items
|
|
order_defaults (list): Internal list used for define Ascendent and Descendent in sql queries
|
|
order_class (list): Internal list used for show icons for ascendent or descendent field selection
|
|
order (str): Default order used in order_defaults list
|
|
order_field (str): The default field used for order the list. By default is the model id field
|
|
order_by (str): The default order ASC or DESC defined in order_class list. By default is 0 or ASC
|
|
change_order (dict): Internal dict used for get all ordenable fields from model
|
|
yes_search (boolean): If True, a search form is showed, if False, the search form is hidden.
|
|
search_text (str): Used for save the search text sended via POST.
|
|
initial_num_pages (int): Initial number of pages showed in pagination.
|
|
table_div (boolean): If True, use div for create the table, if False, use standard html table for create the table.
|
|
begin_page (int): Number that is used for begin the elements to get from query
|
|
search_fields (list): The fields used for search data in form.
|
|
arr_extra_fields (list): List with the names of extra fields
|
|
arr_extra_options (list): List with a set of functions used how extra fields. This functions return lists with different options, joined with jln attribute.
|
|
jln (list): Jump line for join options by default.
|
|
ajax (boolean): If True, ajax is used for get items for the list and change page, if False, typical httpd request is used for change the items page.
|
|
|
|
|
|
"""
|
|
|
|
self.raw_query=True
|
|
|
|
self.t=t
|
|
|
|
self.model=model
|
|
|
|
#if len(self.model.forms)==0:
|
|
|
|
#self.model.create_forms()
|
|
|
|
self.fields=model.fields.keys()
|
|
|
|
self.fields_showed=self.fields
|
|
|
|
self.url=url
|
|
|
|
self.limit_pages=20
|
|
|
|
self.order_defaults=['ASC', 'DESC']
|
|
|
|
self.order_class=['down', 'up']
|
|
|
|
#self.s=get_session()
|
|
|
|
#clean session
|
|
|
|
self.order='0'
|
|
|
|
self.order_field=self.model.name_field_id
|
|
|
|
self.order_by=self.order_defaults[0]
|
|
|
|
self.change_order={}
|
|
|
|
self.yes_search=True
|
|
|
|
self.search_text=''
|
|
|
|
self.initial_num_pages=20
|
|
|
|
self.table_div=False
|
|
|
|
try:
|
|
|
|
#self.begin_page=int(request.args.get('begin_page', '0'))
|
|
self.begin_page=int(get_query_args('begin_page', '0'))
|
|
|
|
except ValueError:
|
|
self.begin_page=0
|
|
|
|
if self.begin_page<0:
|
|
self.begin_page=0
|
|
|
|
self.search_fields=self.fields
|
|
|
|
#self.yes_options=True
|
|
|
|
self.arr_extra_fields=[_('Options')]
|
|
|
|
self.arr_extra_options=[SimpleList.standard_options]
|
|
|
|
self.jln='<br />'
|
|
|
|
self.ajax=False
|
|
|
|
def restore_fields(self):
|
|
"""Simple method for restore default fields from model
|
|
"""
|
|
|
|
self.fields=self.model.fields.keys()
|
|
|
|
def obtain_order(self):
|
|
"""Function for set the order query defaults for list from http request query args.
|
|
"""
|
|
|
|
#self.order=request.args.get('order', self.order) #self.getpostfiles.get.get('order', self.order)
|
|
self.order=get_query_args('order', self.order)
|
|
|
|
order_k=int(self.order)
|
|
|
|
#Obtain from get
|
|
"""
|
|
if 'order' in request.query.keys():
|
|
"""
|
|
#order_k=int(request.query.get('order', 0))
|
|
|
|
if order_k>1 or order_k<0:
|
|
order_k=0
|
|
|
|
self.order_by=self.order_defaults[ order_k ]
|
|
|
|
self.order=order_k
|
|
|
|
def obtain_field_search(self):
|
|
"""Function for set the field search query defaults for list from http request query args.
|
|
"""
|
|
|
|
self.order_field=get_query_args('order_field', self.order_field)
|
|
|
|
field_k=self.order_field
|
|
|
|
"""
|
|
if 'order_field' in request.query.keys():
|
|
field_k=request.query.order_field
|
|
"""
|
|
|
|
if field_k in self.model.fields.keys():
|
|
|
|
self.order_field=field_k
|
|
|
|
for field in self.fields:
|
|
|
|
#Initialize foreignkeyfield fields too
|
|
|
|
if type(self.model.fields[field]).__name__=='ForeignKeyField':
|
|
name_related=self.model.fields[field].related_model.name
|
|
for k in self.model.fields[field].related_model.fields.keys():
|
|
self.change_order[field+'_'+k]=self.order
|
|
|
|
self.change_order[field]=self.order
|
|
|
|
if self.order==0:
|
|
self.change_order[field_k]=1
|
|
else:
|
|
self.change_order[field_k]=0
|
|
|
|
#self.order_field=self.order_field
|
|
|
|
def search(self):
|
|
"""Function for set the text order query defaults for list from http request query args.
|
|
"""
|
|
|
|
self.search_text=get_query_args('search_text', '')
|
|
|
|
self.search_text=self.search_text.replace('"', '"')
|
|
|
|
#self.model.conditions='AND
|
|
|
|
self.search_field=get_query_args('search_field', '')
|
|
|
|
if self.search_field not in self.model.fields.keys():
|
|
self.search_field=''
|
|
|
|
if self.search_field!='' and self.search_text!='':
|
|
self.model.conditions[0]+=' AND '+self.search_field+' LIKE %s'
|
|
self.model.conditions[1].append('%'+self.search_text+'%')
|
|
|
|
pass
|
|
|
|
def set_options(self, options_func, arr_row):
|
|
"""Method for join options list returns with jln attributte separator
|
|
|
|
Returns:
|
|
options (str): Return a string with joined options
|
|
"""
|
|
#SimpleList.standard_options(arr_row)
|
|
return self.jln.join(options_func(self.url, arr_row[self.model.name_field_id], arr_row))
|
|
|
|
@staticmethod
|
|
def standard_options(url, id, arr_row):
|
|
"""Static method for get standar options for make things with the items row.
|
|
|
|
Returns:
|
|
options (list): Return a list of basic options for items row
|
|
"""
|
|
options=[]
|
|
options.append('<a href="'+add_get_parameters(url, op_admin=1, id=id)+'">'+_('Edit')+'</a>')
|
|
options.append('<a href="'+add_get_parameters(url, op_admin=3, id=id)+'">'+_('Delete')+'</a>')
|
|
return options
|
|
|
|
def show(self):
|
|
"""Method for show the table
|
|
|
|
The principal method of the class. The list is showed with the selected fields, search form, pagination...
|
|
"""
|
|
|
|
self.model.yes_reset_conditions=False
|
|
|
|
self.obtain_order()
|
|
|
|
self.obtain_field_search()
|
|
|
|
self.search()
|
|
|
|
total_elements=self.model.select_count()
|
|
|
|
num_elements=self.limit_pages
|
|
|
|
link=add_get_parameters(self.url, search_text=self.search_text, search_field=self.search_field, order=self.order)
|
|
|
|
begin_page=self.begin_page
|
|
|
|
self.model.order_by='order by '+self.order_field+' '+self.order_by
|
|
|
|
if self.limit_pages>0:
|
|
|
|
self.model.limit='limit '+str(begin_page)+','+str(self.limit_pages)
|
|
|
|
list_items=self.model.select(self.fields, self.raw_query)
|
|
|
|
#print(self.model.fields.keys())
|
|
|
|
func_jscript=''
|
|
|
|
if self.ajax==True:
|
|
func_jscript='get_page()'
|
|
|
|
pages=''
|
|
|
|
if self.limit_pages>0:
|
|
pages=Pages.show( begin_page, total_elements, num_elements, link ,initial_num_pages=self.initial_num_pages, variable='begin_page', label='', func_jscript='')
|
|
|
|
self.begin_page=str(self.begin_page)
|
|
|
|
self.model.yes_reset_conditions=True
|
|
|
|
listing=self.t.load_template('utils/list.phtml', simplelist=self, list=list_items, pages=pages, ajax=self.ajax)
|
|
|
|
list_items.close()
|
|
|
|
return listing
|
|
|
|
"""
|
|
@staticmethod
|
|
def get_ajax_page(model):
|
|
|
|
|
|
|
|
pass
|
|
"""
|
|
|
|
|
|
class AjaxList(SimpleList):
|
|
"""Class for make a list from a table based in Ajax
|
|
"""
|
|
|
|
# Fields example: [['Hostname', True], ['IP', True], ['Options', False]]
|
|
|
|
# arr_order_fields=['server.hostname', 'server.ip']
|
|
|
|
# 'select count(servercloud.id) as num_elements from servercloud where servercloud.user_id=%s'
|
|
# params count_query [s['cu_id']]
|
|
|
|
# str_query no order, no limit -> select server.hostname, server.ip, servercloud.id from server, servercloud where server.id=servercloud.server_id and servercloud.user_id=%s
|
|
# str_query_params -> [s['cu_id'], begin_page, limit]
|
|
|
|
def __init__(self, db, fields, arr_order_fields, count_query, str_query):
|
|
"""Class for make a list from a table based in Ajax
|
|
|
|
A class that is useful for creating listings based on database models using Ajax
|
|
|
|
Args:
|
|
db (sql connection): A MySQL connection used for get the model.
|
|
fields (list): A list with the fields showed in table
|
|
arr_order_fields (list): A list with the sql names of selected fields for show.
|
|
count_query (str): sql segment for count query sentence. Example: select count(id) from table WHERE name=%s
|
|
str_query (str): sql segment for query sentence. Example: select id from table WHERE name=%s
|
|
|
|
Attributes:
|
|
fields (list): A list with the fields showed in table
|
|
arr_order_fields (list): A list with the sql names of selected fields for show.
|
|
limit (int): the number of items selected in query sentence.
|
|
count_query (str): sql segment for count query sentence. Example: select count(id) from table WHERE name=%s
|
|
count_query_params (list): A list with the params for parse a sql count query with %s symbols (View python help about sql sentences and connectors)
|
|
str_query (str): sql segment for query sentence. Example: select id from table WHERE name=%s
|
|
str_query_params (list): A list with the params for parse a sql query with %s symbols (View python help about sql sentences and connectors)
|
|
initial_num_pages (int): Initial number of pages showed in pagination.
|
|
db (sql connection): A MySQL connection used for get the model.
|
|
func_fields (dict): A series of functions used for a series of extra fields referring to each row of the table
|
|
initial_order_field (str): FIeld used for order the table in first execution
|
|
initial_order (int): If 0, the initial order is Ascendent, if 1, the initial order is Descendent.
|
|
|
|
"""
|
|
|
|
self.fields=fields
|
|
self.arr_order_fields=arr_order_fields
|
|
self.limit=20
|
|
self.count_query=count_query[0]
|
|
self.count_query_params=count_query[1]
|
|
self.str_query=str_query[0]
|
|
self.str_query_params=str_query[1]
|
|
self.initial_num_pages=20
|
|
self.db=db
|
|
self.func_fields={}
|
|
|
|
self.initial_order_field=''
|
|
self.initial_order=0
|
|
|
|
def show(self):
|
|
"""Method for show the table
|
|
|
|
The principal method of the class. The list is showed with the selected fields, search form, pagination...
|
|
"""
|
|
|
|
begin_page=int(get_query_args('position', 0))
|
|
order_field=get_query_args('order_field', self.initial_order_field)
|
|
order=get_query_args('order', self.initial_order)
|
|
limit=self.limit
|
|
|
|
arr_order=['ASC', 'DESC']
|
|
|
|
order_sql=''
|
|
order_params=[]
|
|
|
|
if order_field!='':
|
|
try:
|
|
order_field=int(order_field)
|
|
order=int(order)
|
|
|
|
if order_field>=0 and order_field<len(self.arr_order_fields):
|
|
order_sql='order by %s' % self.arr_order_fields[order_field]
|
|
if order>=0 and order<2:
|
|
order_sql+=' %s' % arr_order[order]
|
|
|
|
#order_params=[self.arr_order_fields[order_field]]
|
|
|
|
except:
|
|
order_field=0
|
|
order=0
|
|
|
|
|
|
rows=[]
|
|
|
|
with self.db.query(self.count_query, self.count_query_params) as cursor:
|
|
total_elements=cursor.fetchone()['num_elements']
|
|
|
|
str_query=self.str_query+' '+order_sql
|
|
|
|
params=self.str_query_params
|
|
|
|
html_pages=''
|
|
|
|
if self.limit>0:
|
|
str_query+=' limit %s, %s'
|
|
params.append(begin_page)
|
|
params.append(limit)
|
|
|
|
pages=Pages()
|
|
|
|
html_pages=_('Pages')+': '+pages.show( begin_page, total_elements, limit, '#' ,initial_num_pages=self.initial_num_pages, variable='begin_page', label='', func_jscript='')
|
|
|
|
with self.db.query(str_query, params) as cursor:
|
|
for row in cursor:
|
|
"""
|
|
c=len(self.arr_order_fields)
|
|
for x in range(c, len(row)):
|
|
key_field=list(row.keys())[x]
|
|
#print(key_field)
|
|
pass
|
|
"""
|
|
|
|
for func_field in self.func_fields:
|
|
if func_field in row:
|
|
row[func_field]=self.func_fields[func_field](row[func_field], row)
|
|
|
|
rows.append(row)
|
|
#{k:d[k] for in set(d).intersection(l)}
|
|
|
|
return {'fields': self.fields, 'rows': rows, 'html_pages': html_pages}
|
|
|
|
|
|
class SimpleAjaxList():
|
|
|
|
pass
|
|
|