plugin_event.py 6.05 KB
Newer Older
1 2
# -*- coding: utf-8 -*-
"""plugin_event controllers
3 4

"""
5
import urllib
6
import json
7
import re
8 9


10 11
from datetime import datetime
from plugin_dbui import get_id, INLINE_ALERT
12 13 14 15 16 17
from plugin_event import (do_title,
                          Graph,
                          List,
                          Metric1D,
                          Metric2D,
                          ReportException)
18
from plugin_event import EvtSelector, SelectorActiveItemsException
19 20


21 22 23 24 25 26
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.")


27 28
def graph_mpl():
    """Plot list or metric using the matplotlib library
LE GAC Renaud's avatar
LE GAC Renaud committed
29

30
    """
LE GAC Renaud's avatar
LE GAC Renaud committed
31
    # build the graph
LE GAC Renaud's avatar
LE GAC Renaud committed
32
    try:
33
        graph = Graph(db.graphs, request.vars.id_graphs)
LE GAC Renaud's avatar
LE GAC Renaud committed
34

LE GAC Renaud's avatar
LE GAC Renaud committed
35
    except (IndexError, TypeError, ValueError) as e:
36
        return INLINE_ALERT % ("GRAPH Error", e)
LE GAC Renaud's avatar
LE GAC Renaud committed
37 38

    # build the report title
39
    title = do_title(graph)
LE GAC Renaud's avatar
LE GAC Renaud committed
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54
    # 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()

LE GAC Renaud's avatar
LE GAC Renaud committed
55
    # delegate the rendering to the view
56
    return dict(data=data, title=title)
57 58


59
def grid():
60
    """Render the report through the C{Dbui.grid.Panel}.
61
    The report can be a list, a metrics 1d or 2d.
LE GAC Renaud's avatar
LE GAC Renaud committed
62

63
    The controller extracts the configuration of the report form the database.
LE GAC Renaud's avatar
LE GAC Renaud committed
64
    It builds the DataFrame, extracts the the configuration
65
    for the C{Ext.data.Store} as well as the C{Dbui.grid.Panel}.
66
    The former contains the data displayed in the grid.
LE GAC Renaud's avatar
LE GAC Renaud committed
67

68 69 70 71
    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.
LE GAC Renaud's avatar
LE GAC Renaud committed
72

73
    """
74
    # build the report
75 76
    try:
        if "id_lists" in request.vars:
77
            report = List(db.lists, request.vars.id_lists)
LE GAC Renaud's avatar
LE GAC Renaud committed
78

79
        elif "id_metrics1d" in request.vars:
80
            report = Metric1D(db.metrics1d, request.vars.id_metrics1d)
LE GAC Renaud's avatar
LE GAC Renaud committed
81

82
        elif "id_metrics2d" in request.vars:
83
            report = Metric2D(db.metrics2d, request.vars.id_metrics2d)
LE GAC Renaud's avatar
LE GAC Renaud committed
84

85 86 87
        else:
            return INLINE_ALERT % ("Error", "Report id is not defined.")

88
    except (IndexError, ReportException, TypeError, ValueError) as e:
89
        return INLINE_ALERT % ("REPORT Error...", e)
LE GAC Renaud's avatar
LE GAC Renaud committed
90

91
    # extract the configurations for the Ext.data.Store and Dbui.grid.Panel.
92 93
    store = report.to_store()
    grid = report.to_grid()
94

95
    # build the report title
96
    title = do_title(report)
LE GAC Renaud's avatar
LE GAC Renaud committed
97

98
    # delegate the grid rendering to the view
99
    return dict(cfg_store=store, grid=grid, title=title)
100 101


102 103 104 105 106 107 108
def lists2():
    """New approach to generate lists.

    """
    print "lists2 -- hello"


109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
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:

133
        if action != "update":
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
            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:
162 163
        value = model[key]["value"]
        type = model[key]["type"]
164 165 166 167 168

        if value:

            try:
                if type == "boolean":
169
                    value = value.lower() in ("true", "vrai", "y", "yes", "1")
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

                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

192
            model[key]["value"] = value
193 194 195 196 197 198 199 200 201 202 203 204

    # 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:
205
            data[key] = (rd[key] if key in rd else model[key]["value"])
206 207 208 209 210 211 212 213 214

        # 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)