source: dygraphsvisualizationplugin/trunk/dyviz/web_ui.py

Last change on this file was 14715, checked in by Jon Ashley, 8 years ago

Initial release of Dygraphs Visualization Plugin

File size: 4.6 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2015 Jon Ashley <trac@zelatrix.plus.com>
4# All rights reserved.
5#
6# Copyright (C) 2012 Rob Guttman <guttman@alum.mit.edu>
7# All rights reserved.
8#
9# This software is licensed as described in the file COPYING, which
10# you should have received as part of this distribution.
11
12import re
13
14from trac.config import ListOption
15from trac.core import *
16from trac.web.chrome import ITemplateProvider, add_script, add_stylesheet
17from trac.web.main import IRequestFilter, IRequestHandler
18
19class VisualizationModule(Component):
20    implements(IRequestHandler, ITemplateProvider, IRequestFilter)
21
22    SECTION = 'dyviz'
23    DEFAULTS = {
24        'source': 'table',
25        'query': '',
26        'selector': 'table.listing.tickets',
27        'options': 'width:600,height:400',
28    }
29
30    reports = ListOption(SECTION, 'reports', default=[],
31            doc="List of report numbers to treat as queues(?)")
32
33    # ITemplateProvider methods.
34    def get_htdocs_dirs(self):
35        from pkg_resources import resource_filename
36        return [('dyviz', resource_filename(__name__, 'htdocs'))]
37
38    def get_templates_dirs(self):
39        from pkg_resources import resource_filename
40        return [resource_filename(__name__, 'templates')]
41
42    # IRequestFilter methods.
43    def pre_process_request(self, req, handler):
44        return handler
45
46    def post_process_request(self, req, template, data, content_type):
47        if self._is_valid_request(req):
48            add_stylesheet(req, 'dyviz/dyviz.css')
49            add_script(req, 'dyviz/dygraph-combined-dev.js')
50            add_script(req, 'dyviz/dyviz.js')
51            add_script(req, '/dyviz/dyviz.html')
52        return template, data, content_type
53
54    # IRequestHandler methods.
55    def match_request(self, req):
56        return req.path_info.startswith('/dyviz/')
57
58    def process_request(self, req):
59        data = self._get_data(req)
60        return 'dyviz.html', data, 'text/javascript'
61
62    # Private methods.
63    def _is_valid_request(self, req):
64        """ Checks permissions and that page is visualizable. """
65        if req.perm.has_permission('TICKET_VIEW') and \
66                'action=' not in req.query_string and \
67                self._get_section(req):
68            return True
69        return False
70
71    def _get_section(self, req, check_referer=False):
72        """ Returns the trac.ini section that best matches the page url.
73            There's a default section [dyviz] plus regex defined sections.
74            The 'options' field is passed directly to dygraphs.
75
76              [dyviz]
77              reports = 11,12
78              options = width:400,height:300
79
80              [dyviz.report/12]
81              options = colors:['red','orange']
82
83              [dyviz.milestone]
84              options = plotter:barChartPlotter
85
86            In this example, here are results for different page urls:
87
88              /report/1      ->  None
89              /report/11     ->  'dyviz'
90              /report/12     ->  'dyviz.report/12'
91              /milestone/m1  ->  'dyviz.milestone'
92        """
93        if check_referer:
94            path = req.environ.get('HTTP_REFERER','')
95        else:
96            path = req.path_info
97
98        # check regex sections
99        for section in self.env.config.sections():
100            if not section.startswith('%s.' % self.SECTION):
101                continue
102            section_re = re.compile(section[len(self.SECTION)+1:])
103            if section_re.search(path):
104                return section
105
106        # check reports list
107        report_re = re.compile(r"/report/(?P<num>[1-9][0-9]*)")
108        match = report_re.search(req.path_info)
109        if match:
110            report = match.groupdict()['num']
111            if report in self.reports:
112                return self.SECTION
113
114        return None
115
116    def _get_data(self, req):
117        """Return the template data for the given request url."""
118        data = {}
119        section = self._get_section(req, check_referer=True)
120
121        # override [dyviz] with regex section
122        for key,default in self.DEFAULTS.items():
123            data[key] = self.env.config.get(self.SECTION,key,default) # [dyviz]
124            if section != self.SECTION:
125                data[key] = self.env.config.get(section,key,data[key])
126
127        # Redo options - make additive.
128        key,default = 'options',self.DEFAULTS['options']
129        data[key] = self.env.config.get(self.SECTION,key,default) # [dyviz]
130        if section != self.SECTION:
131            options = self.env.config.get(section,key,data[key])
132            if data[key] != options:
133                data[key] = (data[key] + ',' + options).strip(',')
134
135        return data
Note: See TracBrowser for help on using the repository browser.