| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright 2008 Optaros, Inc |
|---|
| 4 | |
|---|
| 5 | import re |
|---|
| 6 | import pkg_resources |
|---|
| 7 | import traceback |
|---|
| 8 | |
|---|
| 9 | from trac.core import Component, implements, ExtensionPoint |
|---|
| 10 | from trac.ticket.api import ITicketChangeListener, ITicketManipulator |
|---|
| 11 | from trac.web.api import IRequestFilter |
|---|
| 12 | from trac.web.chrome import ITemplateProvider |
|---|
| 13 | |
|---|
| 14 | from ticketsystem.api import IOperationsProvider, ITicketRelationshipProvider, ITicketUIWrapper, TypedTicketSystem, TypedTicket |
|---|
| 15 | |
|---|
| 16 | class TypedTicketModule(Component): |
|---|
| 17 | |
|---|
| 18 | implements(ITicketChangeListener, ITicketManipulator, |
|---|
| 19 | ITemplateProvider, IRequestFilter) |
|---|
| 20 | operations = ExtensionPoint(IOperationsProvider) |
|---|
| 21 | ticket_relationships = ExtensionPoint(ITicketRelationshipProvider) |
|---|
| 22 | action_listener_map = {'create': [], 'change': [], 'delete': []} |
|---|
| 23 | renderers = ExtensionPoint(ITicketUIWrapper) |
|---|
| 24 | |
|---|
| 25 | typed_ticket_re = re.compile(r'/ticket/(.*)') |
|---|
| 26 | typed_newticket_re = re.compile(r'/newticket(.*)') |
|---|
| 27 | |
|---|
| 28 | def __init__(self, *args, **kwargs): |
|---|
| 29 | # call the parent |
|---|
| 30 | super(TypedTicketModule, self).__init__(*args, **kwargs) |
|---|
| 31 | # make the operations map |
|---|
| 32 | for operation in self.operations : |
|---|
| 33 | for op_name in operation.register_for_events() : |
|---|
| 34 | if op_name in self.action_listener_map.keys() : |
|---|
| 35 | self.action_listener_map[op_name].append(operation) |
|---|
| 36 | |
|---|
| 37 | |
|---|
| 38 | # ITemplateProvider methods |
|---|
| 39 | def get_htdocs_dirs(self): |
|---|
| 40 | return [('ticketsystem', pkg_resources.resource_filename(__name__, 'htdocs'))] |
|---|
| 41 | |
|---|
| 42 | def get_templates_dirs(self): |
|---|
| 43 | return [pkg_resources.resource_filename(__name__, 'templates')] |
|---|
| 44 | |
|---|
| 45 | # ITicketChangeListener methods |
|---|
| 46 | def ticket_changed(self, ticket, comment, author, old_values) : |
|---|
| 47 | print 'ticket changed' |
|---|
| 48 | for ticket_renderer in [ r for r in self.renderers if r.match_for_render(ticket['type'])]: |
|---|
| 49 | ticket_renderer.process_changes(None, ticket) |
|---|
| 50 | |
|---|
| 51 | def ticket_created(self, ticket): |
|---|
| 52 | for ticket_renderer in [ r for r in self.renderers if r.match_for_render(ticket['type'])]: |
|---|
| 53 | ticket_renderer.process_changes(None, ticket) |
|---|
| 54 | |
|---|
| 55 | def ticket_deleted(self, ticket): |
|---|
| 56 | pass |
|---|
| 57 | |
|---|
| 58 | # ITicketManipulator methods |
|---|
| 59 | def validate_ticket(self, req, ticket): |
|---|
| 60 | for ticket_renderer in [ r for r in self.renderers if r.match_for_render(ticket['type'])]: |
|---|
| 61 | ticket_renderer.process_changes(req, ticket) |
|---|
| 62 | |
|---|
| 63 | return list() |
|---|
| 64 | |
|---|
| 65 | # IRequestFilter methods |
|---|
| 66 | def post_process_request(self, req, template, data, content_type): |
|---|
| 67 | if template in ["ticket.html" ]: |
|---|
| 68 | new_template = None |
|---|
| 69 | if not data.has_key('fields_key') : |
|---|
| 70 | data['fields_dict'] ={} |
|---|
| 71 | for field in data['fields'] : |
|---|
| 72 | data['fields_dict'][field['name']] = field |
|---|
| 73 | |
|---|
| 74 | for field in data['fields_dict']: |
|---|
| 75 | data['fields_dict'][field]['datefield'] = \ |
|---|
| 76 | self.config.getbool('ticket-custom',field+'.date') |
|---|
| 77 | |
|---|
| 78 | type = None |
|---|
| 79 | if data.has_key('ticket') : |
|---|
| 80 | data['ticket'] = TypedTicket(self.env, data['ticket']) |
|---|
| 81 | type = data['ticket']['type'] |
|---|
| 82 | if 'type' in req.args and req.args['type'] is not None: |
|---|
| 83 | type = req.args['type'] |
|---|
| 84 | for render_handle in [ rh for rh in self.renderers if rh.match_for_render(type)] : |
|---|
| 85 | data.update(render_handle.get_content_to_inject(req, data)) |
|---|
| 86 | |
|---|
| 87 | for render_handle in self.renderers : |
|---|
| 88 | if render_handle.match_for_render(type) and 'oldpage' not in req.args: |
|---|
| 89 | page = render_handle.handle_request(req, data, content_type) |
|---|
| 90 | if page : |
|---|
| 91 | new_template, new_data, new_content_type = page |
|---|
| 92 | if new_template and new_data and new_content_type : |
|---|
| 93 | return new_template, new_data, new_content_type |
|---|
| 94 | if new_data : |
|---|
| 95 | data = new_data |
|---|
| 96 | if new_content_type : |
|---|
| 97 | content_type = new_content_type |
|---|
| 98 | |
|---|
| 99 | # hook the new template |
|---|
| 100 | if new_template : |
|---|
| 101 | data['ticket_template'] = new_template |
|---|
| 102 | else : |
|---|
| 103 | data['ticket_template'] = self.env.config.get('ticket-system', |
|---|
| 104 | 'ticket.template', |
|---|
| 105 | 'ticket.html') |
|---|
| 106 | return "typedticket.html", data, content_type |
|---|
| 107 | |
|---|
| 108 | return template, data, content_type |
|---|
| 109 | |
|---|
| 110 | def pre_process_request(self, req, handler) : |
|---|
| 111 | match = self.typed_ticket_re.match( req.path_info ) |
|---|
| 112 | |
|---|
| 113 | if match and req.method=='POST': |
|---|
| 114 | type = None |
|---|
| 115 | if 'id' in req.args and req.args['id'] is not None: |
|---|
| 116 | type = TypedTicket(self.env, int(req.args['id']))['type'] |
|---|
| 117 | if 'field_type' in req.args and req.args['field_type'] is not None: |
|---|
| 118 | type = req.args['field_type'] |
|---|
| 119 | try : |
|---|
| 120 | for ticket_renderer in [ rh for rh in self.renderers if rh.match_for_render(type)] : |
|---|
| 121 | ticket_renderer.process_changes(req, None) |
|---|
| 122 | except Exception, e: |
|---|
| 123 | print e |
|---|
| 124 | self.log.error(e) |
|---|
| 125 | return handler |
|---|