| [1356] | 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # Copyright (C) 2006 Ashwin Phatak |
|---|
| 3 | |
|---|
| [2771] | 4 | import re |
|---|
| [1356] | 5 | from trac.core import * |
|---|
| 6 | from trac.web.chrome import INavigationContributor, ITemplateProvider |
|---|
| 7 | from trac.web.main import IRequestHandler |
|---|
| 8 | from trac.perm import IPermissionRequestor |
|---|
| 9 | from trac.ticket.query import QueryModule |
|---|
| 10 | from trac.util.html import html |
|---|
| 11 | from trac.ticket import TicketSystem |
|---|
| 12 | from trac.ticket import Ticket |
|---|
| [1379] | 13 | from trac.mimeview.api import IContentConverter |
|---|
| 14 | from trac.wiki import IWikiSyntaxProvider |
|---|
| 15 | from trac.wiki.macros import WikiMacroBase |
|---|
| 16 | from trac.ticket.query import TicketQueryMacro as Macro |
|---|
| [1356] | 17 | |
|---|
| [1379] | 18 | __all__ = ['BatchModifyModule','TicketQueryMacro'] |
|---|
| [1356] | 19 | |
|---|
| 20 | class BatchModifyModule(Component): |
|---|
| 21 | '''Allows batch modification of tickets''' |
|---|
| 22 | |
|---|
| 23 | implements(INavigationContributor, IRequestHandler, ITemplateProvider, \ |
|---|
| [1379] | 24 | IPermissionRequestor, IContentConverter, IWikiSyntaxProvider) |
|---|
| [1356] | 25 | |
|---|
| 26 | # INavigationContributor methods |
|---|
| 27 | |
|---|
| 28 | def get_active_navigation_item(self, req): |
|---|
| [1379] | 29 | return QueryModule(self.env).get_active_navigation_item(req) |
|---|
| [1356] | 30 | |
|---|
| 31 | def get_navigation_items(self, req): |
|---|
| 32 | from trac.ticket.report import ReportModule |
|---|
| 33 | if req.perm.has_permission('TICKET_VIEW') and \ |
|---|
| 34 | not self.env.is_component_enabled(ReportModule): |
|---|
| 35 | yield ('mainnav', 'tickets', |
|---|
| 36 | html.A('View Tickets', href=req.href.query())) |
|---|
| [3254] | 37 | elif req.perm.has_permission('TICKET_BATCH_MODIFY'): |
|---|
| 38 | yield ('mainnav', 'query', |
|---|
| [1356] | 39 | html.A('Custom Query', href=req.href.query())) |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 42 | # IRequestHandler methods |
|---|
| 43 | |
|---|
| 44 | def match_request(self, req): |
|---|
| [2771] | 45 | return QueryModule(self.env).match_request(req) |
|---|
| [1356] | 46 | |
|---|
| 47 | def process_request(self, req): |
|---|
| 48 | if req.args.has_key('batchmod'): |
|---|
| 49 | req.perm.assert_permission('TICKET_BATCH_MODIFY') |
|---|
| 50 | self._batch_modify(req) |
|---|
| 51 | |
|---|
| 52 | QueryModule(self.env).process_request(req) |
|---|
| 53 | self._add_ticket_fields(req) |
|---|
| 54 | |
|---|
| 55 | return 'batchmod.cs', None |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | # ITemplateProvider methods |
|---|
| 59 | |
|---|
| 60 | def get_templates_dirs(self): |
|---|
| 61 | from pkg_resources import resource_filename |
|---|
| 62 | return [resource_filename(__name__, 'templates')] |
|---|
| [2771] | 63 | |
|---|
| 64 | def get_htdocs_dirs(self): |
|---|
| 65 | return [] |
|---|
| [1356] | 66 | |
|---|
| 67 | # IPermissionRequestor methods |
|---|
| 68 | def get_permission_actions(self): |
|---|
| 69 | yield 'TICKET_BATCH_MODIFY' |
|---|
| 70 | |
|---|
| 71 | |
|---|
| [1379] | 72 | # IContentConverter methods |
|---|
| 73 | def get_supported_conversions(self): |
|---|
| 74 | return QueryModule(self.env).get_supported_conversions() |
|---|
| 75 | |
|---|
| 76 | def convert_content(self, req, mimetype, query, key): |
|---|
| 77 | return QueryModule(self.env).convert_content(req, mimetype, query, key) |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | # IWikiSyntaxProvider methods |
|---|
| 81 | |
|---|
| 82 | def get_wiki_syntax(self): |
|---|
| 83 | return QueryModule(self.env).get_wiki_syntax() |
|---|
| 84 | |
|---|
| 85 | def get_link_resolvers(self): |
|---|
| 86 | return QueryModule(self.env).get_link_resolvers() |
|---|
| 87 | |
|---|
| 88 | |
|---|
| [1356] | 89 | # Internal methods |
|---|
| 90 | def _batch_modify(self, req): |
|---|
| 91 | tickets = req.session['query_tickets'].split(' ') |
|---|
| 92 | comment = req.args.get('comment', '') |
|---|
| 93 | values = {} |
|---|
| 94 | |
|---|
| 95 | for field in TicketSystem(self.env).get_ticket_fields(): |
|---|
| 96 | name = field['name'] |
|---|
| 97 | if name not in ('summary', 'reporter', \ |
|---|
| 98 | 'description', 'type', 'status', |
|---|
| 99 | 'resolution', 'owner'): |
|---|
| 100 | if req.args.has_key('bm_' + name): |
|---|
| 101 | values[name] = req.args.get(name) |
|---|
| 102 | |
|---|
| 103 | for id in tickets: |
|---|
| 104 | t = Ticket(self.env, id) |
|---|
| 105 | t.populate(values) |
|---|
| 106 | t.save_changes(req.authname, comment) |
|---|
| 107 | |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | def _add_ticket_fields(self, req): |
|---|
| 111 | for field in TicketSystem(self.env).get_ticket_fields(): |
|---|
| 112 | name = field['name'] |
|---|
| 113 | del field['name'] |
|---|
| 114 | if name in ('summary', 'reporter', 'description', 'type', 'status', |
|---|
| 115 | 'resolution', 'owner'): |
|---|
| 116 | field['skip'] = True |
|---|
| 117 | req.hdf['ticket.fields.' + name] = field |
|---|
| 118 | |
|---|
| 119 | |
|---|
| [1379] | 120 | class TicketQueryMacro(WikiMacroBase): |
|---|
| 121 | __doc__ = Macro.__doc__ |
|---|
| 122 | |
|---|
| 123 | def render_macro(self, req, name, content): |
|---|
| 124 | return Macro(self.env).render_macro(req, name, content) |
|---|