# -*- coding: utf-8 -*- """plugin_event controllers """ import urllib import json import re from datetime import datetime from plugin_dbui import get_id, INLINE_ALERT from plugin_event import (do_title, Graph, List, Metric1D, Metric2D, ReportException) from plugin_event import EvtSelector, SelectorActiveItemsException MSG = T(" - %s entry(ies) modified in the history table.
" " - 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(): """Render the report through the C{Dbui.grid.Panel}. The report can be a list, a metrics 1d or 2d. 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 and send using the baseParams techniques. Possible identifiers are C{id_lists], C{id_metrics1d} and C{id_metrics2d}. The identifier is used to instantiate the proper class. """ # build the report try: if "id_lists" in request.vars: report = List(db.lists, request.vars.id_lists) elif "id_metrics1d" in request.vars: 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: return INLINE_ALERT % ("REPORT Error...", e) # extract the configurations for the Ext.data.Store and Dbui.grid.Panel. 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) def userModelConsistency(): """ A user data block is associated to each event. It is configurable by the user and defined in the events table. The definition of the user data block (model) and the content of the history.data field have to be kept in synchronization. This job is done by this controller. """ # decode the request 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: if type == "boolean": value = value.lower() in ("true", "vrai", "y", "yes", "1") elif type == "date": value = datetime.strptime(value, "%Y-%m-%d") value = value.isoformat() elif type == "float": value = float(value) elif type == "integer": value = int(value) if type == "string" and value[0] == "[" and value[-1] == "]": # reference to a set, pick the first value as default li = json.loads(value) value = (li[0] if li else None) elif type == "reference": value = None except ValueError as e: return MSG_CVT % e model[key]["value"] = value # scan and modify the history table # the delete of old key is implicit since they are not copied 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 for key in model: data[key] = (rd[key] if key in rd else model[key]["value"]) # modify key name for oldkey, newkey in update_keys.iteritems(): if oldkey in rd: data[newkey] = rd[oldkey] db(db.history.id == row.id).update(data=data) return MSG % len(rows)