source: contextchromeplugin/0.12/contextchrome/linkdeco.py

Last change on this file was 17546, checked in by matobaa, 4 years ago

ContextChromePlugin: cosmetic changes

File size: 7.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2012-2013,2017,2019 MATOBA Akihiro <matobaa+trac-hacks@gmail.com>
5# All rights reserved.
6#
7# This software is licensed as described in the file COPYING, which
8# you should have received as part of this distribution.
9
10from trac.core import Component, implements
11from trac.ticket.model import Ticket
12from trac.web.api import IRequestHandler, IRequestFilter
13from trac.config import ListOption, IntOption
14from trac.wiki.model import WikiPage
15from datetime import datetime
16from trac.web.chrome import ITemplateProvider, add_stylesheet, add_script,\
17    add_script_data
18from pkg_resources import resource_filename
19import json
20
21
22class TicketLinkDecorator(Component):
23    """ set css-class to ticket link as ticket field value. field name can
24    set in [ticket]-decorate_fields in trac.ini
25    """
26    implements(IRequestHandler, IRequestFilter, ITemplateProvider)
27
28    decorate_fields = ListOption('ticket', 'decorate_fields', default='type',
29        doc=""" comma separated List of field names to add css class of ticket link.
30            (Provided by !ContextChrome.!TicketLinkDecorator) """)
31
32    # IRequestHandler Methods
33    def match_request(self, req):
34        return req.path_info == '/contextchrome/ticketlink.jsonrpc'
35
36    def process_request(self, req):
37        payload = json.load(req)
38        if not 'method' in payload or not payload['method'] == 'ticket.get':
39            req.send_response(501)  # Method Not Implemented
40            req.end_headers()
41            return
42        params = payload['params']
43        content = json.dumps(dict(map(lambda id: (id, self.get(req, id)), params)), indent=4)
44        req.send_response(200)
45        req.send_header('Content-Type', 'application/json')
46        req.send_header('Content-Length', len(content))
47        req.end_headers()
48        req.write(content)
49
50    def format(self, param):
51        if isinstance(param, datetime):
52            return {"__jsonclass__": ["datetime", param.isoformat()]}
53        return param
54
55    # if TicketSystem(self.env).resource_exists(resource):
56    def get(self, req, id):
57        ticket = Ticket(self.env, id)
58        req.perm(ticket.resource).require('TICKET_VIEW')  # FIXME: skip instead fail
59        return {  # like XmlRpcPlugin
60            'id': id,
61            'error': None,
62            'result': [
63                id,
64                self.format(ticket.values['time']),
65                self.format(ticket.values['changetime']),
66                dict([(key, self.format(ticket.values[key])) for key in ticket.values
67                    if key in self.config.getlist('ticket', 'decorate_fields')])
68            ]
69        }
70
71    # IRequestFilter methods
72    def pre_process_request(self, req, handler):
73        return handler
74
75    def post_process_request(self, req, template, data, content_type):
76        if True:  # any template
77            add_script(req, "contextchrome/js/ticketlinkdecorator.js")
78        return template, data, content_type
79
80    # ITemplateProvider methods
81    def get_htdocs_dirs(self):
82        return [('contextchrome', resource_filename(__name__, 'htdocs'))]
83
84    def get_templates_dirs(self):
85        return []
86
87
88class WikiLinkNewDecolator(Component):
89    """ set \"new\" css-class to wiki link if the page is young. age can set in [wiki]-wiki_new_info_second in trac.ini"""
90    implements(IRequestHandler, IRequestFilter, ITemplateProvider)
91
92    wiki_new_info_day = IntOption('wiki', 'wiki_new_info_second', '432000',
93        doc=u"""age in seconds to add new icon. (Provided by !ContextChrome.!WikiLinkNewDecolator) """)
94
95    # IRequestHandler Methods
96    def match_request(self, req):
97        return req.path_info == '/contextchrome/wikilinknew.jsonrpc'
98
99    def process_request(self, req):
100        payload = json.load(req)
101        if 'method' not in payload or not payload['method'] == 'wiki.getPageInfo':
102            req.send_response(501)  # Method Not Implemented
103            req.end_headers()
104            return
105        params = payload['params']
106        content = json.dumps(dict(map(lambda id: (id, self.get(req, id)), params)), indent=4)
107        req.send_response(200)
108        req.send_header('Content-Type', 'application/json')
109        req.send_header('Content-Length', len(content))
110        req.end_headers()
111        req.write(content)
112
113    # IRequestFilter methods
114    def pre_process_request(self, req, handler):
115        return handler
116
117    def post_process_request(self, req, template, data, content_type):
118        if True:  # any template
119            add_script(req, "contextchrome/js/wikilinknewdecorator.js")
120            add_script_data(req, {'config__wiki__wiki_new_info_second': 
121                self.config.getint('wiki', 'wiki_new_info_second')})
122        return template, data, content_type
123
124    def get(self, req, id):
125        wikipage = WikiPage(self.env, id)
126        req.perm(wikipage.resource).require('WIKI_VIEW')  # FIXME: skip instead fail
127        now = datetime.now(req.tz)
128        limit = self.config.getint('wiki', 'wiki_new_info_second')
129        delta = now - wikipage.time or 0
130        return {  # like XmlRpcPlugin
131            'id': id,
132            'error': None,
133            'result': [
134                id,
135                wikipage.time.isoformat(),
136                delta.total_seconds(),
137                limit > delta.days * 86400 + delta.seconds,  # True if page is new
138            ]
139        }
140
141    # ITemplateProvider methods
142    def get_htdocs_dirs(self):
143        return [('contextchrome', resource_filename(__name__, 'htdocs'))]
144
145    def get_templates_dirs(self):
146        return []
147
148
149class InternalStylesheet(Component):
150    """ Use internal stylesheet. Off to use your own site.css for \".new\" css-class."""
151    implements(IRequestFilter, ITemplateProvider)
152
153    # IRequestFilter methods
154    def pre_process_request(self, req, handler):
155        add_stylesheet(req, "contextchrome/css/contextchrome.css")
156        return handler
157
158    def post_process_request(self, req, template, data, content_type):
159        return template, data, content_type
160
161    # ITemplateProvider methods
162    def get_htdocs_dirs(self):
163        return [('contextchrome', resource_filename(__name__, 'htdocs'))]
164
165    def get_templates_dirs(self):
166        return []
167
168
169class InterTracTicketLinkDecorator(Component):
170    """ set css-class to type on external ticket. """
171    implements(IRequestFilter, ITemplateProvider)
172
173    # IRequestFilter methods
174    def pre_process_request(self, req, handler):
175        add_script(req, "contextchrome/js/xdr.js")
176        add_script(req, "contextchrome/js/intertracticketlinkdecorator.js")
177        add_script_data(req, {'config__ticket__decolate_fields': self.config.getlist('ticket', 'decorate_fields')})
178        return handler
179
180    def post_process_request(self, req, template, data, content_type):
181        return template, data, content_type
182
183    # ITemplateProvider methods
184    def get_htdocs_dirs(self):
185        return [('contextchrome', resource_filename(__name__, 'htdocs'))]
186
187    def get_templates_dirs(self):
188        return []
Note: See TracBrowser for help on using the repository browser.