PKw¼_5¼ì÷#ÕÕprivatetickets/api.pyfrom trac.core import * from trac.perm import IPermissionRequestor from trac.ticket.model import Ticket __all__ = ['PrivateTicketsSystem'] class PrivateTicketsSystem(Component): """Central tasks for the PrivateTickets plugin.""" implements(IPermissionRequestor) # IPermissionRequestor methods def get_permission_actions(self): actions = ['TICKET_VIEW_REPORTER', 'TICKET_VIEW_OWNER', 'TICKET_VIEW_CC'] return actions + [('TICKET_VIEW_SELF', actions)] # Public methods def check_ticket_access(self, req, id): """Return if this req is permitted access to the given ticket ID.""" try: tkt = Ticket(self.env, id) except TracError: return False # Ticket doesn't exist if req.perm.has_permission('TICKET_VIEW_REPORTER') and \ tkt['reporter'] == req.authname: return True if req.perm.has_permission('TICKET_VIEW_CC') and \ req.authname in [x.strip() for x in tkt['cc'].split(',')]: return True if req.perm.has_permission('TICKET_VIEW_OWNER') and \ req.authname == tkt['owner']: return True return False PK ¾_5ÊxYYprivatetickets/view.pyfrom trac.core import * from trac.web.chrome import INavigationContributor from trac.ticket.web_ui import TicketModule from trac.ticket.query import QueryModule from trac.Search import SearchModule from trac.ticket.report import ReportModule from api import PrivateTicketsSystem __all__ = ['PrivateTicketsViewModule'] class PrivateTicketsViewModule(Component): """Allow users to see tickets they are involved in.""" implements(INavigationContributor) # INavigationContributor methods def get_active_navigation_item(self, req): return '' def get_navigation_items(self, req): # Don't allow this to be exposed if 'DO_PRIVATETICKETS_FILTER' in req.args.keys(): del req.args['DO_PRIVATETICKETS_FILTER'] # Various ways to allow access if not req.perm.has_permission('TICKET_VIEW'): if TicketModule(self.env).match_request(req): if PrivateTicketsSystem(self.env).check_ticket_access(req, req.args['id']): self._grant_view(req) elif QueryModule(self.env).match_request(req): req.args['DO_PRIVATETICKETS_FILTER'] = 'query' self._grant_view(req) # Further filtering in query.py elif SearchModule(self.env).match_request(req): if 'ticket' in req.args.keys(): req.args['pticket'] = req.args['ticket'] del req.args['ticket'] elif ReportModule(self.env).match_request(req): self._grant_view(req) # So they can see the query page link if req.args.get('id'): req.args['DO_PRIVATETICKETS_FILTER'] = 'report' return [] # Internal methods def _grant_view(self, req): req.perm.perms['TICKET_VIEW'] = True req.hdf['trac.acl.TICKET_VIEW'] = 1 PK(»_5privatetickets/__init__.pyPK3½_5"bÔΜœprivatetickets/query.pyfrom trac.core import * from trac.web.api import IRequestFilter from trac.ticket.query import QueryModule from api import PrivateTicketsSystem __all__ = ['PrivateTicketsQueryFilter'] class PrivateTicketsQueryFilter(Component): """Remove entires from queries if this user shouldn't see them.""" implements(IRequestFilter) # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, content_type): if req.args.get('DO_PRIVATETICKETS_FILTER') == 'query': # Extract the data results = [] node = req.hdf.getObj('query.results') if not node: return template, content_type node = node.child() while node: data = {} sub_node = node.child() while sub_node: data[sub_node.name()] = sub_node.value() sub_node = sub_node.next() results.append(data) node = node.next() self.log.debug('PrivateTickets: results = %r', results) # Nuke the old data req.hdf.removeTree('query.results') # Filter down the data fn = PrivateTicketsSystem(self.env).check_ticket_access new_results = [d for d in results if fn(req, d['id'])] self.log.debug('PrivateTickets: new_results = %r', new_results) # Reinsert the data req.hdf['query.results'] = new_results return template, content_type PK(»_5ij8Ü;;privatetickets/search.pyfrom trac.core import * from trac.Search import ISearchSource from trac.ticket.api import TicketSystem from trac.web.api import IRequestFilter from api import PrivateTicketsSystem __all__ = ['PrivateTicketsSearchModule'] class PrivateTicketsSearchModule(Component): """Search restricted to tickets you are involved with.""" implements(ISearchSource, IRequestFilter) # ISearchSource methods def get_search_filters(self, req): if not req.perm.has_permission('TICKET_VIEW') and \ ( req.perm.has_permission('TICKET_VIEW_REPORTER') or \ req.perm.has_permission('TICKET_VIEW_CC') or \ req.perm.has_permission('TICKET_VIEW_ASSIGNED') ): yield ('pticket', 'Tickets') def get_search_results(self, req, terms, filters): if req.perm.has_permission('TICKET_VIEW'): return if 'pticket' not in filters: return req._MUNGE_FILTER = True fn = PrivateTicketsSystem(self.env).check_ticket_access for result in TicketSystem(self.env).get_search_results(req, terms, ['ticket']): id = int(result[0].split('/')[-1]) self.log.debug('PrivateTicketsSearchModule: Check id %r', id) if fn(req, id): yield result # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, content_type): if hasattr(req, '_MUNGE_FILTER'): node = req.hdf.getObj('search.filters').child() while node: if req.hdf['search.filters.%s.name'%node.name()] == 'pticket': req.hdf['search.filters.%s.name'%node.name()] = 'ticket' node = node.next() return template, content_type PKKa5wžêA¶¶privatetickets/report.pyfrom trac.core import * from trac.web.api import IRequestFilter from api import PrivateTicketsSystem __all__ = ['PrivateTicketsReportFilter'] class PrivateTicketsReportFilter(Component): """Show only ticket the user is involved in in the reports.""" implements(IRequestFilter) # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, content_type): if req.args.get('DO_PRIVATETICKETS_FILTER') == 'report': # Walk the HDF fn = PrivateTicketsSystem(self.env).check_ticket_access deleted = [] left = [] node = req.hdf.getObj('report.items').child() while node: i = node.name() id = req.hdf['report.items.%s.ticket'%i] if not fn(req, id): deleted.append(i) else: left.append(i) node = node.next() # Delete the needed subtrees for n in deleted: req.hdf.removeTree('report.items.%s'%n) # Recalculate this req.hdf['report.numrows'] = len(left) # Move the remaining items into their normal places for src, dest in zip(left, xrange(len(left)+len(deleted))): if src == dest: continue req.hdf.getObj('report.items').copy(str(dest), req.hdf.getObj('report.items.%s'%src)) for n in xrange(len(left), len(left)+len(deleted)): req.hdf.removeTree('report.items.%s'%n) return template, content_type PKma5( =ï——privatetickets/api.pyc;ò #$HEc@sDdkTdklZdklZdgZdefd„ƒYZdS((s*(sIPermissionRequestor(sTicketsPrivateTicketsSystemcBs*tZdZeeƒd„Zd„ZRS(s,Central tasks for the PrivateTickets plugin.cCs$dddg}|d|fgSdS(NsTICKET_VIEW_REPORTERsTICKET_VIEW_OWNERsTICKET_VIEW_CCsTICKET_VIEW_SELF(sactions(sselfsactions((s0build/bdist.linux-i686/egg/privatetickets/api.pysget_permission_actions scCsõyt|i|ƒ}Wntj o tSnX|ii dƒo|d|i jot Sn|ii dƒoA|i gi }|didƒD]}||iƒƒq“~jot Sn|ii dƒo|i |djot SntSdS( s>Return if this req is permitted access to the given ticket ID.sTICKET_VIEW_REPORTERsreportersTICKET_VIEW_CCsccs,sTICKET_VIEW_OWNERsownerN(sTicketsselfsenvsidstkts TracErrorsFalsesreqspermshas_permissionsauthnamesTruesappends_[1]ssplitsxsstrip(sselfsreqsids_[1]stktsx((s0build/bdist.linux-i686/egg/privatetickets/api.pyscheck_ticket_accesss 'W'(s__name__s __module__s__doc__s implementssIPermissionRequestorsget_permission_actionsscheck_ticket_access(((s0build/bdist.linux-i686/egg/privatetickets/api.pysPrivateTicketsSystems   N(s trac.cores trac.permsIPermissionRequestorstrac.ticket.modelsTickets__all__s ComponentsPrivateTicketsSystem(sIPermissionRequestorsTickets__all__sPrivateTicketsSystem((s0build/bdist.linux-i686/egg/privatetickets/api.pys?s   PKma5` ïNS S privatetickets/view.pyc;ò <'HEc@sxdkTdklZdklZdklZdklZdk l Z dk l Z dgZ defd„ƒYZd S( (s*(sINavigationContributor(s TicketModule(s QueryModule(s SearchModule(s ReportModule(sPrivateTicketsSystemsPrivateTicketsViewModulecBs3tZdZeeƒd„Zd„Zd„ZRS(s0Allow users to see tickets they are involved in.cCsdSdS(Ns((sselfsreq((s1build/bdist.linux-i686/egg/privatetickets/view.pysget_active_navigation_itemscCsod|iiƒjo|id=n|iidƒ o/t|iƒi|ƒo8t |iƒi ||idƒo|i |ƒqcqgt |iƒi|ƒod|id<|i |ƒqgt |iƒi|ƒo<d|iiƒjo"|id|id<|id=qcqgt|iƒi|ƒo5|i |ƒ|iidƒod|idprivatetickets/search.pycPKma5ðnP7ëë¤_Jprivatetickets/report.pycPKma5³ˆe‡‡¤SEGG-INFO/PKG-INFOPKma5‚@cpp¤7UEGG-INFO/SOURCES.txtPKma5“×2¤ÙVEGG-INFO/dependency_links.txtPKma5wVBßêê¤WEGG-INFO/entry_points.txtPKma5’[â ¤6XEGG-INFO/top_level.txtPKma5“×2¤yXEGG-INFO/zip-safePKÜ©X