Commit d81542db authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Merge branch 'master' into 'production'

Release 0.7.0

See merge request !32
parents 1d2efd3a 8d155af3
...@@ -2,206 +2,104 @@ ...@@ -2,206 +2,104 @@
"""plugin_event controllers """plugin_event controllers
""" """
import traceback
import urllib import urllib
import json
import re
from datetime import datetime from plugin_event import (Graph,
from plugin_dbui import get_id, INLINE_ALERT
from plugin_event import (do_title,
Graph,
List, List,
Metric1D,
Metric2D, Metric2D,
ReportException) ReportException,
from plugin_event import EvtSelector, SelectorActiveItemsException Source)
MSG = T(" - %s entry(ies) modified in the history table. <br>"
" - DO NOT FORGET TO MODIFIED THE REPORT CONFIGURATION.")
MSG_CVT = T(" - Conversion error: %s.")
def graph_mpl():
"""Plot list or metric using the matplotlib library
"""
# build the graph
try:
graph = Graph(db.graphs, request.vars.id_graphs)
except (IndexError, TypeError, ValueError) as e:
return INLINE_ALERT % ("GRAPH Error", e)
# build the report title
title = do_title(graph)
# extract the image
# encode special character to be used in the image URI
extension = request.extension
if extension == "html":
data = graph.to_svg()
data = urllib.quote(data)
elif extension == "pdf":
data = graph.to_pdf()
elif extension == "png":
data = graph.to_png()
# delegate the rendering to the view
return dict(data=data, title=title)
def grid(): def grid():
"""Render the report through the C{Dbui.grid.Panel}. """The list is rendered such as an ``Ext.grid.Panel`` widget.
The report can be a list, a metrics 1d or 2d. Its context menu allows to export the content of the table as a CSV, LaTeX
or PDF format.
The controller extracts the configuration of the report form the database.
It builds the DataFrame, extracts the the configuration
for the C{Ext.data.Store} as well as the C{Dbui.grid.Panel}.
The former contains the data displayed in the grid.
The report identifier is defined in the viewport The controller extracts the configuration of the report from the database.
and send using the baseParams techniques. Possible identifiers It builds the DataFrame, extracts the configuration for the
are C{id_lists], C{id_metrics1d} and C{id_metrics2d}. ``Ext.data.Store`` as well as the ``Ext.grid.Panel``. The former contains
The identifier is used to instantiate the proper class. the data displayed in the grid.
""" """
# build the report
try: try:
if "id_lists" in request.vars: report = List(request.vars.id_list)
report = List(db.lists, request.vars.id_lists) store = report.get_store_configuration()
grid = report.get_grid_configuration()
elif "id_metrics1d" in request.vars: title = report.get_title()
report = Metric1D(db.metrics1d, request.vars.id_metrics1d)
elif "id_metrics2d" in request.vars:
report = Metric2D(db.metrics2d, request.vars.id_metrics2d)
else:
return INLINE_ALERT % ("Error", "Report id is not defined.")
except (IndexError, ReportException, TypeError, ValueError) as e: except (IndexError, ReportException, TypeError, ValueError):
return INLINE_ALERT % ("REPORT Error...", e) return CODE(traceback.format_exc()).xml()
# extract the configurations for the Ext.data.Store and Dbui.grid.Panel. response.view = "plugin_event/grid.html"
store = report.to_store()
grid = report.to_grid()
# build the report title
title = do_title(report)
# delegate the grid rendering to the view
return dict(cfg_store=store, grid=grid, title=title) return dict(cfg_store=store, grid=grid, title=title)
def userModelConsistency(): def metric2d():
""" A user data block is associated to each event. """The metric 2D is a 2D table rendered by an ``Ext.grid.Panel`` widget
It is configurable by the user and defined in the events table. and a graph rendered as an image. The context menu associated to the grid
allows to export the content of the table as a CSV, LaTeX or PDF format.
The context menu associated to the image allow to export in PNG or PDF
format.
The definition of the user data block (model) and the content The controller extracts the configuration of the report from the database.
of the history.data field have to be kept in synchronization. It builds the DataFrame, extracts the the configuration for the
This job is done by this controller. ``Ext.data.Store`` as well as the ``Ext.grid.Panel`` and generated
the graph.
""" """
# decode the request extension = request.extension
changes = json.loads(request.vars.changes)
event = request.vars.fieldEvent
model = json.loads(request.vars.fieldData)
# build a map of the modified keys.
# each operation is a list containing (action, old key, new key).
# the action is equal to: add, destroy, update
#
# NOTE: add and delete action are handle via dictionary copy.
#
#
update_keys = {}
for action, oldkey, newkey in changes:
if action != "update":
continue
# simplify the case where key1 > key2 > key3 to key1 > key3
# remove the case where key1 > key2 > ... > key1
if update_keys:
ok = False
for k, v in update_keys.iteritems():
if oldkey == v:
update_keys[k] = newkey
ok = True
if k == newkey:
del update_keys[k]
break
if ok:
continue
# basic case
update_keys[oldkey] = newkey
# get the event id
id_event = get_id(db.events, event=event)
if id_event == None:
return
# set-up the default values dealing with data conversion
for key in model:
value = model[key]["value"]
type = model[key]["type"]
if value:
try: try:
if type == "boolean": report = Metric2D(request.vars.id_metric2d)
value = value.lower() in ("true", "vrai", "y", "yes", "1")
elif type == "date": graph = Graph(report)
value = datetime.strptime(value, "%Y-%m-%d") title = report.get_title()
value = value.isoformat()
elif type == "float": if extension == "html":
value = float(value) store = report.get_store_configuration()
grid = report.get_grid_configuration()
elif type == "integer": if graph.ax is not None:
value = int(value) img = graph.to_svg()
img = urllib.quote(img)
if type == "string" and value[0] == "[" and value[-1] == "]": response.view = "plugin_event/grid_and_graph.html"
# reference to a set, pick the first value as default return dict(cfg_store=store, grid=grid, img=img, title=title)
li = json.loads(value)
value = (li[0] if li else None)
elif type == "reference": else:
value = None response.view = "plugin_event/grid.html"
return dict(cfg_store=store, grid=grid, title=title)
except ValueError as e: elif extension == "pdf":
return MSG_CVT % e data = graph.to_pdf()
response.view = "plugin_event/graph.pdf"
return dict(data=data, title=title)
model[key]["value"] = value elif extension == "png":
data = graph.to_png()
response.view = "plugin_event/graph.png"
return dict(data=data, title=title)
# scan and modify the history table except (IndexError, ReportException, TypeError, ValueError):
# the delete of old key is implicit since they are not copied return CODE(traceback.format_exc()).xml()
query = db.history.id_events == id_event
rows = db(query).select()
for row in rows:
data = {}
rd = (row.data if isinstance(row.data, dict) else dict())
# copy existing key or add new key def source():
for key in model: """Display the content of a source via an ``Ext.grid.Panel``.
data[key] = (rd[key] if key in rd else model[key]["value"]) Values send by the selector are used to filter the content of the source.
# modify key name """
for oldkey, newkey in update_keys.iteritems(): try:
if oldkey in rd: report = Source(request.vars.source)
data[newkey] = rd[oldkey] store = report.get_store_configuration()
grid = report.get_grid_configuration()
title = report.get_title()
db(db.history.id == row.id).update(data=data) except (IndexError, ReportException, TypeError, ValueError):
return CODE(traceback.format_exc()).xml()
return MSG % len(rows) response.view = "plugin_event/grid.html"
return dict(cfg_store=store, grid=grid, title=title)
...@@ -13,3 +13,5 @@ Functions ...@@ -13,3 +13,5 @@ Functions
:toctree: generated/ :toctree: generated/
INHIBIT_CASCADE_DELETE INHIBIT_CASCADE_DELETE
ON_CREATE_LISTS2
ON_UPDATE_LISTS2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# track_event api documentation build configuration file, created by # plugin_event api documentation build configuration file, created by
# sphinx-quickstart on Sat Apr 11 11:17:03 2015. # sphinx-quickstart on Sat Apr 11 11:17:03 2015.
# #
# This file is execfile()d with the current directory set to its containing dir. # This file is execfile()d with the current directory set to its containing dir.
...@@ -78,9 +78,9 @@ source_suffix = '.rst' ...@@ -78,9 +78,9 @@ source_suffix = '.rst'
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
app = 'track_events' app = 'plugin_event'
now = datetime.now() now = datetime.now()
project = u'track_events API' project = u'plugin_event API'
copyright = u'2012-%s, R. Le Gac, licensed under CeCILL' % now.year copyright = u'2012-%s, R. Le Gac, licensed under CeCILL' % now.year
author = u'R. Le Gac' author = u'R. Le Gac'
......
Dataframes
-----------
A collection of classes and functions to build and to manipulate the sources.
.. currentmodule:: plugin_event
.. autosummary::
:toctree: generated/
active_period
coverage
db2df
debug_df
expand_per_year
full_name
get_column_names
get_items
get_items_per_year
get_items_small
get_items_small_per_year
get_objectlike_items
get_objectlike_items_per_year
get_peoplelike_items
get_peoplelike_items_per_year
get_people_per_year
is_end
is_start
normalize_history_data
query_history
Timer
to_extjs_gridcolumns
to_items_per_year
\ No newline at end of file
plugin_event.BaseReport.to_df plugin_event.Event.get_source
============================= =============================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: BaseReport.to_df .. automethod:: Event.get_source
\ No newline at end of file \ No newline at end of file
plugin_event.Selector.selector plugin_event.Event.get_sources
============================== ==============================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: Selector.selector .. automethod:: Event.get_sources
\ No newline at end of file \ No newline at end of file
plugin_event.ViewportUi.graph_node plugin_event.Event.register_source
================================== ==================================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: ViewportUi.graph_node .. automethod:: Event.register_source
\ No newline at end of file \ No newline at end of file
plugin_event.SelectorUi.selector plugin_event.Event.register_sources
=================================== ===================================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: SelectorUi.selector .. automethod:: Event.register_sources
\ No newline at end of file \ No newline at end of file
plugin_event.Report.lists
=========================
.. currentmodule:: plugin_event
.. automethod:: Report.lists
\ No newline at end of file
plugin_event.Report.graphs plugin_event.Report.lists2
========================== ==========================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: Report.graphs .. automethod:: Report.lists2
\ No newline at end of file \ No newline at end of file
plugin_event.Metric1D.to_store plugin_event.Report.metrics2d2
============================== ==============================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: Metric1D.to_store .. automethod:: Report.metrics2d2
\ No newline at end of file \ No newline at end of file
plugin_event.ViewportUi.object_node plugin_event.Selector.selector_list
=================================== ===================================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: ViewportUi.object_node .. automethod:: Selector.selector_list
\ No newline at end of file \ No newline at end of file
plugin_event.Selector.selector_metric2d
=======================================
.. currentmodule:: plugin_event
.. automethod:: Selector.selector_metric2d
\ No newline at end of file
plugin_event.ViewportUi.metric1d_node plugin_event.Selector.selector_source
===================================== =====================================
.. currentmodule:: plugin_event .. currentmodule:: plugin_event
.. automethod:: ViewportUi.metric1d_node .. automethod:: Selector.selector_source
\ No newline at end of file \ No newline at end of file
...@@ -12,8 +12,9 @@ plugin_event.BaseReport ...@@ -12,8 +12,9 @@ plugin_event.BaseReport
.. autosummary:: .. autosummary::
:toctree: report/ :toctree: report/
~BaseReport.to_df ~BaseReport.get_grid_configuration
~BaseReport.get_store_configuration
~BaseReport.get_title
......
...@@ -12,6 +12,11 @@ plugin_event.Event ...@@ -12,6 +12,11 @@ plugin_event.Event
:toctree: model/ :toctree: model/
~Event.define_paths ~Event.define_paths
~Event.get_source
~Event.get_sources
~Event.register_source
~Event.register_sources
......
plugin_event.EvtSelector
========================
.. currentmodule:: plugin_event
.. autoclass:: EvtSelector
:show-inheritance:
.. rubric:: Methods
.. autosummary::
:toctree: selector/
~EvtSelector.query
~EvtSelector.reset_extra_queries
...@@ -11,7 +11,8 @@ plugin_event.Graph ...@@ -11,7 +11,8 @@ plugin_event.Graph
.. autosummary:: .. autosummary::
:toctree: report/ :toctree: report/
~Graph.to_df ~Graph.bar_like
~Graph.line_like
~Graph.to_pdf ~Graph.to_pdf
~Graph.to_png ~Graph.to_png
~Graph.to_svg ~Graph.to_svg
......
...@@ -11,10 +11,6 @@ plugin_event.List ...@@ -11,10 +11,6 @@ plugin_event.List
.. autosummary:: .. autosummary::
:toctree: report/ :toctree: report/
~List.to_df
~List.to_grid
~List.to_store
......
...@@ -11,9 +11,7 @@ plugin_event.Metric2D ...@@ -11,9 +11,7 @@ plugin_event.Metric2D
.. autosummary:: .. autosummary::
:toctree: report/ :toctree: report/
~Metric2D.to_df ~Metric2D.summaries
~Metric2D.to_grid
~Metric2D.to_store
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment