Commit 680376bd authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Add a new concept allowing users to design and customize lists.

parent b9997764
""" List controllers
"""
from reporting_tools import (MySelector,
from reporting_tools import (MyList,
MySelector,
Base,
Person)
BASE_VIEW = 'report.%s'
def index():
""" Generate list(s) according to list definition and selector requirement
(experimental).
Handle the following URLs:
application/list/index
application/list/index?id_sqltable_configuration=2
"""
report = MyList(virtdb.my_list_selector)
iframe = report.download()
if iframe:
return iframe
if request.vars.id_sqltable_configurations:
report.id_sqltable_configurations = request.vars.id_sqltable_configurations
# response.view = "list/build_list.%s" % request.extension
return dict(report=report())
def hardware():
""" Active hardware for a given period of time, given team, ...
......
......@@ -37,6 +37,8 @@
'Client IP': 'Client IP',
'Code': 'Code',
'Collections': 'Collections',
'Columns': 'Colonnes',
'Configuration': 'Configuration',
'contains': 'contiens',
'Contract': 'Contrat',
'Controller': 'Controller',
......@@ -66,7 +68,9 @@
'Event': 'Evènement',
'Event category': 'Event category',
'events': 'évènements',
'Evènement': 'Evènement',
'Executed': 'Executé',
'Field': 'Champ',
'Filter agencies': 'Filtrer les agences',
'Filter budgets': 'Filtrer les budgets',
'Filter careers': 'Filtrer les carrières',
......@@ -83,8 +87,10 @@
'First Name': 'Prénom',
'Forgot username?': 'Forgot username?',
'Format': 'Format',
'Formats': 'Formats',
'Forms': 'Formulaire',
'FTE': 'FTE',
'Function': 'Fonction',
'Funding': 'Financement',
'fundings': 'financements',
'Fundings': 'Financements',
......@@ -102,15 +108,18 @@
'Hdr': 'Hdr',
'Hdr Date': 'Hdr Date',
'Hdr defense date': "Date de soutenace de l'hdr",
'Headers': 'En têtes',
'Help': 'Aide',
'history': 'historique',
'History': 'Historique',
'Id': 'Id',
'Id My Lists': 'Id My Lists',
'Initials': 'Initiales',
'Invalid email': 'Invalid email',
'Invalid login': 'Invalid login',
'Is Active': 'Is Active',
'is equal to': 'égal à',
'Labels': 'Etiquettes',
'Last name': 'Last name',
'Last Name': 'Nom de famille',
'less or equal to': 'inférieur ou égal à',
......@@ -125,7 +134,7 @@
'List of responsibilities': 'Liste des responsabilités',
'List of trainee': 'Liste des stagiaires',
'Liste': 'Liste',
'Lists': 'Lists',
'Lists': 'Listes',
'Logged in': 'Logged in',
'Login': 'Login',
'Logout': 'Logout',
......@@ -139,11 +148,15 @@
'Modified By': 'Modified By',
'Modified On': 'Modified On',
'Modèle': 'Modèle',
'My lists': 'Mes listes',
'my_lists': 'mes listes',
'Name': 'Nom',
'Niveau': 'Niveau',
'Note': 'Note',
'Notified': 'Notifié',
'Object or table name': 'Object or table name',
'Order by': 'Trié par',
'Orderby': 'Trié par',
'Organization': 'Organisation',
'organization_levels': "niveau de l'organisation",
'organizations': 'organisations',
......@@ -174,6 +187,7 @@
'project leader,...': 'project leader,...',
'projects': 'projets',
'Projet': 'Projet',
'Python Code': 'Python Code',
'Quality': 'Qualité',
'Qualité': 'Qualité',
'Ratio': 'Ratio',
......@@ -190,6 +204,10 @@
'Select': 'Selectionnez',
'Select a teams and/or a project !!!': 'Select a teams and/or a project !!!',
'select...': 'selectionner...',
'Sqltable': 'Sqltable',
'sqltable_configurations': 'sqltable_configurations',
'sqltable_functions': 'sqltable_functions',
'sqltable_virtualfields': 'sqltable_virtualfields',
'Stage': 'Stage',
'Start': 'Début',
'start': 'début',
......
# -*- coding: utf-8 -*-
""" db
Defined the database tables for the applications.
Defined the database core tables for the applications.
"""
import locale
......@@ -94,6 +94,31 @@ db.history.id_events.requires = IS_IN_DB(db, 'events.event')
db.history.id_people.requires = IS_IN_DB(db, 'people.last_name')
db.history.trainee_category.requires = IS_IN_USET((undef, 'PHY', 'IR'))
tp_list = "Name of the list."
tp_columns = "List of column names separated by a comma. " \
"The column name is encoded as 'tablename.columnname."
tp_headers = "Dictionary associating the column name and the column header. " \
"The dictionary is encoded as {tablename.columnname: header, ...}"
tp_formats = "Dictionary associating the column name and the format fucntion. " \
"The dictionary is encoded as {tablename.columnname: function, ...}"
tp_orderby = "List of columns defining the order by directive: " \
"tablename.columnname, ~tablename.columnname, ..."
db.define_table("my_lists",
Field("list", "string", notnull=True, unique=True, comment=tp_list),
Field("id_events", "reference events", default=undef_id, label='Event'),
Field("columns", "text", notnull=True, comment=tp_columns),
Field("headers", "text", comment=tp_headers),
Field("formats", "text", comment=tp_formats),
Field("orderby", "text", comment=tp_orderby),
Field("note", "text"),
migrate="my_lists.table")
db.define_table("organizations",
Field("organization", "string", notnull=True, unique=True),
Field("definition", "text"),
......
# -*- coding: utf-8 -*-
""" db
Defined the database tables for the sqltables (reports)
"""
tp_name = "Name of the sqltable."
tp_columns = "List of column names separated by a comma. " \
"The column name is encoded as 'tablename.columnname."
tp_formats = "Dictionary associating the column name and the format fucntion. " \
"The dictionary is encoded as {tablename.columnname: function, ...}"
tp_labels = "Dictionary associating the column name and the column header. " \
"The dictionary is encoded as {tablename.columnname: header, ...}"
tp_orderby = "List of columns defining the order by directive: " \
"tablename.columnname, ~tablename.columnname, ..."
db.define_table("sqltable_configurations",
Field("sqltable", "string", notnull=True, unique=True, comment=tp_list),
Field("id_events", "reference events", default=undef_id, label='Event'),
Field("columns", "text", notnull=True, comment=tp_columns),
Field("labels", "text", comment=tp_labels),
Field("formats", "text", comment=tp_formats),
Field("orderby", "text", comment=tp_orderby),
Field("note", "text"),
migrate="sqltable_configurations.table")
func_code = "def repr_xxx(value, row):\n"\
" return value\n"
db.define_table("sqltable_functions",
Field("function", "string", default= "repr_xxx", notnull=True, unique=True),
Field("python_code", "text", default=func_code),
migrate="sqltable_functions.table")
virtualfield_code = "def xxx(row):\n"\
" return None\n"
db.define_table("sqltable_virtualfields",
Field("field", "string", notnull=True, unique=True),
Field("python_code", "text", default=virtualfield_code),
migrate="sqltable_virtualfields.table")
......@@ -46,7 +46,7 @@ virtdb.define_table('list_selector',
Field('id_projects', 'reference projects', label=T('Project')),
Field('category', 'string'),
Field('id_people_categories', 'reference people_categories', label= T("Quality")),
Field('id_events', 'reference events', label=T('List')),
Field('id_events', 'reference events', label=T('Event')),
Field('format', 'string', default='html'))
virtdb.list_selector.category.requires = IS_IN_SET((el.category for el in categories))
......@@ -59,6 +59,33 @@ virtdb.list_selector.id_teams.requires = IS_IN_DB(db, 'teams.team')
virtdb.list_selector.format.requires = IS_IN_SET(FORMATS)
#
# my list selector (experimental)
#
virtdb.define_table('my_list_selector',
Field('year', 'integer', default=year),
Field('period_start', 'date'),
Field('period_end', 'date'),
Field('id_people', 'reference people', label=T('Person')),
Field('id_teams', 'reference teams', label=T('Team')),
Field('id_projects', 'reference projects', label=T('Project')),
Field('category', 'string'),
Field('id_people_categories', 'reference people_categories', label= T("Quality")),
Field('id_sqltable_configurations', 'reference sqltable_configurations', label=T('List')),
Field('format', 'string', default='html'))
virtdb.my_list_selector.category.requires = IS_IN_SET((el.category for el in categories))
virtdb.my_list_selector.id_people_categories.requires = IS_IN_DB(db, 'people_categories.code')
virtdb.my_list_selector.id_people.requires = IS_IN_DB(db, 'people.last_name')
virtdb.my_list_selector.id_projects.requires = IS_IN_DB(db, 'projects.project')
virtdb.my_list_selector.id_teams.requires = IS_IN_DB(db, 'teams.team')
virtdb.my_list_selector.id_sqltable_configurations.requires = \
IS_IN_DB(db, 'sqltable_configurations.sqltable')
virtdb.my_list_selector.format.requires = IS_IN_SET(FORMATS)
#
# people selector
#
......@@ -70,7 +97,7 @@ virtdb.define_table('people_selector',
Field('id_projects', 'reference projects', label=T('Project')),
Field('category', 'string'),
Field('id_people_categories', 'reference people_categories', label= T("Quality")),
Field('id_events', 'reference events', label=T('List')),
Field('id_events', 'reference events', label=T('Event')),
Field('format', 'string', default='html'))
virtdb.people_selector.category.requires = IS_IN_SET((el.category for el in categories))
......
......@@ -37,6 +37,26 @@ fieldsModifier.configure_field('period_start', flex=1)
fieldsModifier.configure_field('period_end', flex=1)
fieldsModifier.merge_fields('period_start', 'period_end', fieldLabel=T('Period'))
#
# my lists
#
fieldsModifier = dbui.FieldsModifier('my_lists')
fieldsModifier.configure_field('columns', height=140)
fieldsModifier.configure_field('headers', height=190, hideLabel=True)
fieldsModifier.configure_field('formats', height=190, hideLabel=True)
fieldsModifier.configure_field('orderby', height=190, hideLabel=True)
fieldsModifier.configure_field('note', height=190, hideLabel=True)
#
# my list selector
#
fieldsModifier = dbui.FieldsModifier('my_list_selector')
fieldsModifier.configure_field('id_sqltable_configurations', hidden=True)
fieldsModifier.configure_field('id_people', editable='false', mode='local')
fieldsModifier.configure_field('period_start', flex=1)
fieldsModifier.configure_field('period_end', flex=1)
fieldsModifier.merge_fields('period_start', 'period_end', fieldLabel=T('Period'))
#
# people selector
#
......@@ -54,6 +74,28 @@ fieldsModifier.configure_field('period_start', flex=1)
fieldsModifier.configure_field('period_end', flex=1)
fieldsModifier.merge_fields('period_start', 'period_end', fieldLabel=T('Period'))
#
# sqltable_configurations
#
fieldsModifier = dbui.FieldsModifier('sqltable_configurations')
fieldsModifier.configure_field('columns', height=140)
fieldsModifier.configure_field('labels', height=190, hideLabel=True)
fieldsModifier.configure_field('formats', height=190, hideLabel=True)
fieldsModifier.configure_field('orderby', height=190, hideLabel=True)
fieldsModifier.configure_field('note', height=190, hideLabel=True)
#
# sqltable_functions
#
fieldsModifier = dbui.FieldsModifier('sqltable_functions')
fieldsModifier.configure_field('python_code', height=215, hideLabel=True)
#
# sqltable_virtualfields
#
fieldsModifier = dbui.FieldsModifier('sqltable_virtualfields')
fieldsModifier.configure_field('python_code', height=215, hideLabel=True)
#
# trainee selector
#
......
......@@ -64,3 +64,102 @@ formModifier.configure(buttonAlign='right',
height=270,
defaults={'height': 200})
#
# My lists
#
formModifier = dbui.FormModifier('my_lists')
formModifier.merge_fields('list',
'id_events',
'columns',
dbui.Spacer(height=75),
title=T('General'),
flex=1)
formModifier.merge_fields('headers',
dbui.Spacer(height=128),
title=T('Headers'),
flex=1)
formModifier.merge_fields('formats',
dbui.Spacer(height=128),
title=T('Formats'),
flex=1)
formModifier.merge_fields('orderby',
dbui.Spacer(height=128),
title=T('Order by'),
flex=1)
formModifier.merge_fields('note',
dbui.Spacer(height=128),
title=T('Note'),
flex=1)
formModifier.set_mapper(dbui.map_tabpanel)
formModifier.configure(buttonAlign='right',
labelWidth=70,
labelAlign='left',
width=400,
height=300,
defaults={'height': 240})
#
# sqltable_configurations
#
formModifier = dbui.FormModifier('sqltable_configurations')
formModifier.merge_fields('sqltable',
'id_events',
'columns',
dbui.Spacer(height=75),
title=T('General'),
flex=1)
formModifier.merge_fields('labels',
dbui.Spacer(height=128),
title=T('Labels'),
flex=1)
formModifier.merge_fields('formats',
dbui.Spacer(height=128),
title=T('Formats'),
flex=1)
formModifier.merge_fields('orderby',
dbui.Spacer(height=128),
title=T('Order by'),
flex=1)
formModifier.merge_fields('note',
dbui.Spacer(height=128),
title=T('Note'),
flex=1)
formModifier.set_mapper(dbui.map_tabpanel)
formModifier.configure(buttonAlign='right',
labelWidth=70,
labelAlign='left',
width=400,
height=300,
defaults={'height': 240})
#
# sqltable_functions
#
formModifier = dbui.FormModifier('sqltable_functions')
formModifier.configure(buttonAlign='right',
labelWidth=70,
labelAlign='left',
width=400,
height=300)
#
# sqltable_virtualfields
#
formModifier = dbui.FormModifier('sqltable_virtualfields')
formModifier.configure(buttonAlign='right',
labelWidth=70,
labelAlign='left',
width=400,
height=300)
......@@ -100,6 +100,26 @@ gridModifier = dbui.GridModifier('projects')
gridModifier.configure_column('project', width=20)
gridModifier.set_rownumbering()
#
# sqltable_configuration
#
gridModifier = dbui.GridModifier('sqltable_configurations')
gridModifier.set_rownumbering()
#
# sqltable_functions
#
gridModifier = dbui.GridModifier('sqltable_functions')
gridModifier.configure_column('function', width=20)
gridModifier.set_rownumbering()
#
# sqltable_virtualfields
#
gridModifier = dbui.GridModifier('sqltable_virtualfields')
gridModifier.configure_column('field', width=20)
gridModifier.set_rownumbering()
#
# teams
#
......
......@@ -14,6 +14,12 @@ AUTH_TABLES = ['auth_cas',
'auth_permission',
'auth_user']
CONF_TABLES = ['sqltable_configurations',
'sqltable_functions',
'sqltable_virtualfields']
CONFIGURATOR = lambda tablename: dbui.to_gridPanel(db[tablename])
#
# CAS node -- when the identification procedure is activated
#
......@@ -24,8 +30,7 @@ if session.auth:
hidden_tables.remove(el)
casNode = dbui.Node(T('CAS'))
configurator = lambda tablename: dbui.to_gridPanel(db[tablename])
casNode.add_children(db.tables, func=configurator, hidden=hidden_tables)
casNode.add_children(db.tables, func=CONFIGURATOR, hidden=hidden_tables)
#
# Help node
......@@ -40,15 +45,33 @@ helpNode.add_child(T('documentations'), documentationsLeaf)
helpNode.add_child(T('versions'), versionLeaf)
helpNode.sort_children()
#
# configuration node
#
confNode = dbui.Node(T('Configuration'))
confNode.add_children(CONF_TABLES, func=CONFIGURATOR)
#
# grid node
#
hidden_tables = list(AUTH_TABLES)
hidden_tables.extend(CONF_TABLES)
gridNode = dbui.Node(T('Tables'))
configurator = lambda tablename: dbui.to_gridPanel(db[tablename])
gridNode.add_children(db.tables, func=configurator, hidden=hidden_tables)
gridNode.add_children(db.tables, func=CONFIGURATOR, hidden=hidden_tables)
#
# lists node
#
listNode = dbui.Node(T('Lists'))
for row in db(db.sqltable_configurations.id > 0).select():
url = URL('list', 'index', vars=dict(id_sqltable_configurations=row.id))
leaf = dbui.to_panelWithUrlSelector(virtdb.my_list_selector, baseUrl=url)
listNode.add_child(row.sqltable, leaf)
listNode.sort_children()
#
# report node
#
......@@ -109,5 +132,5 @@ if session.auth:
viewportModifier.append_plugins('pViewportLogin')
viewportModifier.configure(logged=True)
viewportModifier.add_node(helpNode, casNode, wizardNode, gridNode, reportNode)
viewportModifier.add_node(helpNode, casNode, wizardNode, confNode, gridNode, listNode, reportNode)
viewportModifier.default_node(T('Tables'), T('history'))
......@@ -2,6 +2,7 @@
"""
from datetime import date, datetime, timedelta
from virtualfield import VirtualFieldTool
from gluon import current
from gluon.dal import Field
from plugin_dbui import (UNDEF_ID,
......@@ -11,6 +12,27 @@ from plugin_dbui import (UNDEF_ID,
Selector)
MSG_NO_FORMAT = "The function %s is not defined in sqtable_functions table."
MSG_NO_VITUALFIELD_TOOL = "The VirtaulField Tool %s is not defined."
class ExtractAndFormat(object):
"""Tool to get the content of a row for a given field when the field
is defined as 'tablename.fieldname'. In addition the content can be
formatted using the represent function.
This class is useful to build extracolumn in SQLTable.
"""
def __init__(self, fname, represent=lambda val: val):
self.tablename, self.fieldname = fname.split('.')
self.represent = represent
def __call__(self, row, rc):
return self.represent(row[self.tablename][self.fieldname])
class Base(object):
"""Base class for reporting tool.
......@@ -106,6 +128,383 @@ class CountPeople(object):
return rows
class SelectorActiveItems(Selector):
"""Custom version of the selector.
It contains additional tools to selected active records
during the period range which can be defined in several different ways.
"""
def __init__(self,
table,
exclude_fields=('category',
'period_end',
'period_start',
'year'),
extfield='format'):
"""
@type table: gluon.dal.Table
@param table: the virtual table defining the selector.
@type exclude_fields: list of string
@param exclude_fields: name of the selector fields which are
excluded in the query.
@type extfield: string
@param extfield: name of the selector field which define
the format of the report.
"""
self.periode_end = None
self.period_start = None
self.year = None
Selector.__init__(self,
table,
exclude_fields=exclude_fields,
extfield=extfield)
if self.year:
self.period_start = date(self.year, 1, 1)
self.period_end = date(self.year, 12, 31)
def query_active_items(self, table):
"""Build the database query for the database table
including inner join for foreign keys, selector constraints and
extra queries.
@type table: gluon.dal.Table
@param table: the database table in which records are selected.
@rtype: gluon.dal.Query
@return: The query selects active items during the given period of
time. It only works for table having the database fields
C{start_date} and C{end_date}.