Edgewall Software

Ticket #1198: trac-timeline-author-1198.patch

File trac-timeline-author-1198.patch, 16.1 KB (added by davidf@…, 6 months ago)

Patch to r7176 (0.11 branch) to enable filtering attachments by author name

  • trac/attachment.py

     
    451451            time = datetime.fromtimestamp(ts, utc) 
    452452            yield ('created', realm, id, filename, time, description, author) 
    453453 
    454     def get_timeline_events(self, req, resource_realm, start, stop): 
     454    def get_timeline_events(self, req, resource_realm, start, stop, filters): 
    455455        """Return an event generator suitable for ITimelineEventProvider. 
     456        This is called from the parent resource, it doesn't directly implement 
     457        ITimelineEventProvider. 
    456458 
    457459        Events are changes to attachments on resources of the given 
    458460        `resource_realm.realm`. 
    459461        """ 
     462        if filters.get('author', ''): 
     463            filter_author = lambda author: author == filters['author'] 
     464        else: 
     465            filter_author = lambda author: True 
    460466        for change, realm, id, filename, time, descr, author in \ 
    461467                self.get_history(start, stop, resource_realm.realm): 
    462468            attachment = resource_realm(id=id).child('attachment', filename) 
    463469            if 'ATTACHMENT_VIEW' in req.perm(attachment): 
     470                if not filter_author(author): 
     471                    continue 
    464472                yield ('attachment', time, author, (attachment, descr), self) 
    465473 
    466474    def render_timeline_event(self, context, field, event): 
  • trac/ticket/web_ui.py

     
    199199 
    200200    def get_timeline_filters(self, req): 
    201201        if 'TICKET_VIEW' in req.perm: 
    202             yield ('ticket', _('Ticket changes')) 
     202            yield ('ticket', ITimelineEventProvider.CHECKBOX, _('Ticket changes'), True) 
     203            yield ('author', ITimelineEventProvider.STRING, _('Author'), '') 
    203204            if self.timeline_details: 
    204                 yield ('ticket_details', _('Ticket details'), False) 
     205                yield ('ticket_details', ITimelineEventProvider.CHECKBOX, _('Ticket details'), False) 
    205206 
    206207    def get_timeline_events(self, req, start, stop, filters): 
    207208        ts_start = to_timestamp(start) 
     
    213214                      'edit': ('editedticket', 'updated')} 
    214215 
    215216        ticket_realm = Resource('ticket') 
     217        if filters.get('author', ''): 
     218            filter_author = lambda author: author == filters['author'] 
     219        else: 
     220            filter_author = lambda author: True 
    216221 
    217222        def produce_event((id, ts, author, type, summary, description), 
    218223                          status, fields, comment, cid): 
     
    221226                return None 
    222227            resolution = fields.get('resolution') 
    223228            info = '' 
     229            if not filter_author(author): 
     230                return None 
    224231            if status == 'edit': 
    225232                if 'ticket_details' in filters: 
    226233                    if len(fields) > 0: 
     
    290297            # Attachments 
    291298            if 'ticket_details' in filters: 
    292299                for event in AttachmentModule(self.env).get_timeline_events( 
    293                     req, ticket_realm, start, stop): 
     300                    req, ticket_realm, start, stop, filters): 
    294301                    yield event 
    295302 
    296303    def render_timeline_event(self, context, field, event): 
  • trac/ticket/roadmap.py

     
    501501 
    502502    def get_timeline_filters(self, req): 
    503503        if 'MILESTONE_VIEW' in req.perm: 
    504             yield ('milestone', _('Milestones')) 
     504            yield ('milestone', ITimelineEventProvider.CHECKBOX, _('Milestones'), True) 
    505505 
    506506    def get_timeline_events(self, req, start, stop, filters): 
    507507        if 'milestone' in filters: 
     
    520520 
    521521            # Attachments 
    522522            for event in AttachmentModule(self.env).get_timeline_events( 
    523                 req, milestone_realm, start, stop): 
     523                req, milestone_realm, start, stop, filters): 
    524524                yield event 
    525525                 
    526526    def render_timeline_event(self, context, field, event): 
  • trac/versioncontrol/web_ui/changeset.py

     
    764764 
    765765    def get_timeline_filters(self, req): 
    766766        if 'CHANGESET_VIEW' in req.perm: 
    767             yield ('changeset', _('Repository checkins')) 
     767            yield ('changeset', ITimelineEventProvider.CHECKBOX, _('Repository checkins'), True) 
     768            yield ('author', ITimelineEventProvider.STRING, _('Author'), '') 
    768769 
    769770    def get_timeline_events(self, req, start, stop, filters): 
     771        if filters.get('author', ''): 
     772            filter_author = lambda author: author == filters['author'] 
     773        else: 
     774            filter_author = lambda author: True 
    770775        if 'changeset' in filters: 
    771776            show_files = self.timeline_show_files 
    772777            show_location = show_files == 'location' 
     
    792797                        permitted_changesets.append(chgset) 
    793798                if permitted_changesets: 
    794799                    chgset = permitted_changesets[-1] 
     800                    if not filter_author(chgset.author): 
     801                        continue 
    795802                    yield ('changeset', chgset.date, chgset.author, 
    796803                           (permitted_changesets, chgset.message or '', 
    797804                            show_location, show_files)) 
  • trac/admin/console.py

     
    107107        except TracError, e: 
    108108            print>>sys.stderr, 'Command failed: %s' % e 
    109109            rv = 2 
     110            raise 
    110111        if not self.interactive: 
    111112            return rv 
    112113 
  • trac/wiki/web_ui.py

     
    549549 
    550550    def get_timeline_filters(self, req): 
    551551        if 'WIKI_VIEW' in req.perm: 
    552             yield ('wiki', _('Wiki changes')) 
     552            yield ('wiki', ITimelineEventProvider.CHECKBOX, _('Wiki changes'), True) 
     553            yield ('author', ITimelineEventProvider.STRING, _('Author'), '') 
    553554 
    554555    def get_timeline_events(self, req, start, stop, filters): 
    555556        db = self.env.get_db_cnx() 
     557        if filters.get('author', ''): 
     558            filter_author = lambda author: author == filters['author'] 
     559        else: 
     560            filter_author = lambda author: True 
    556561        if 'wiki' in filters: 
    557562            wiki_realm = Resource('wiki') 
    558563            cursor = db.cursor() 
     
    563568                wiki_page = wiki_realm(id=name, version=version) 
    564569                if 'WIKI_VIEW' not in req.perm(wiki_page): 
    565570                    continue 
     571                if not filter_author(author): 
     572                    continue 
    566573                yield ('wiki', datetime.fromtimestamp(ts, utc), author, 
    567574                       (wiki_page, comment)) 
    568575 
    569576            # Attachments 
    570577            for event in AttachmentModule(self.env).get_timeline_events( 
    571                 req, wiki_realm, start, stop): 
     578                req, wiki_realm, start, stop, filters): 
    572579                yield event 
    573580 
    574581    def render_timeline_event(self, context, field, event): 
  • trac/timeline/api.py

     
    3030    timeline. 
    3131    """ 
    3232 
     33    CHECKBOX = 'checkbox' 
     34    STRING = 'string' 
     35 
    3336    def get_timeline_filters(req): 
    3437        """Return a list of filters that this event provider supports. 
    3538         
    36         Each filter must be a (name, label) tuple, where `name` is the internal 
    37         name, and `label` is a human-readable name for display. 
    38  
    39         Optionally, the tuple can contain a third element, `checked`. 
    40         If `checked` is omitted or True, the filter is active by default, 
    41         otherwise it will be inactive. 
     39        Each filter must be a (name, type, label, default) tuple, where 
     40        `name` is the internal name, 
     41        `label` is a human-readable name for display, 
     42        `type` is either CHECKBOX or STRING 
     43        `default` is the default option for this filter 
    4244        """ 
    4345 
    4446    def get_timeline_events(req, start, stop, filters): 
    4547        """Return a list of events in the time range given by the `start` and 
    4648        `stop` parameters. 
    4749 
    48         The `filters` parameters is a list of the enabled filters, each item 
    49         being the name of the tuples returned by `get_timeline_filters`. 
     50        The `filters` parameters is a dictionary of the enabled filters, each 
     51        key being the name of the tuples returned by `get_timeline_filters`, 
     52        and each value being either `True` for a `CHECKBOX` filter or the string 
     53        passed to a `STRING` filter. `False` `CHECKBOX` filters are not included. 
    5054 
    5155        Since 0.11, the events are `(kind, date, author, data)` tuples, 
    5256        where `kind` is a string used for categorizing the event, `date` 
  • trac/timeline/web_ui.py

     
    128128 
    129129        available_filters = [] 
    130130        for event_provider in self.event_providers: 
    131             available_filters += event_provider.get_timeline_filters(req) 
     131            for timeline_filter in event_provider.get_timeline_filters(req): 
     132                # support for previous timeline filter format (Deprecated) 
     133                if len(timeline_filter) == 2: 
     134                    timeline_filter = (timeline_filter[0], ITimelineEventProvider.CHECKBOX, 
     135                                       timeline_filter[1], True) 
     136                elif len(timeline_filter) == 3: 
     137                    timeline_filter = (timeline_filter[0], ITimelineEventProvider.CHECKBOX, 
     138                                       timeline_filter[1], timeline_filter[2]) 
     139                available_filters.append(timeline_filter) 
    132140 
    133         filters = [] 
     141        filters = {} 
    134142        # check the request or session for enabled filters, or use default 
    135         for test in (lambda f: f[0] in req.args, 
    136                      lambda f: req.session.get('timeline.filter.%s' % f[0], 
    137                                                '') == '1', 
    138                      lambda f: len(f) == 2 or f[2]): 
    139             if filters: 
    140                 break 
    141             filters = [f[0] for f in available_filters if test(f)] 
     143        for f in available_filters: 
     144            filter_name = f[0] 
     145            if filter_name in filters: 
     146                continue 
     147            if f[1] == ITimelineEventProvider.CHECKBOX: 
     148                if filter_name in req.args: 
     149                    filters[filter_name] = True 
     150                elif req.session.get('timeline.filter.%s' % filter_name, '') == '1': 
     151                    filters[filter_name] = True 
     152                elif f[3]: 
     153                    filters[filter_name] = True 
     154            elif f[1] == ITimelineEventProvider.STRING: 
     155                if filter_name in req.args: 
     156                    filters[filter_name] = req.args[filter_name] 
     157                elif req.session.get('timeline.filter.%s' % filter_name, None) is not None: 
     158                    filters[filter_name] = req.session.get('timeline.filter.%s' % filter_name) 
     159                else: 
     160                    filters[filter_name] = f[3] 
    142161 
    143162        # save the results of submitting the timeline form to the session 
    144163        if 'update' in req.args: 
    145164            for filter in available_filters: 
    146165                key = 'timeline.filter.%s' % filter[0] 
    147166                if filter[0] in req.args: 
    148                     req.session[key] = '1' 
     167                    if filter[1] == ITimelineEventProvider.CHECKBOX: 
     168                        req.session[key] = '1' 
     169                    elif filter[1] == ITimelineEventProvider.STRING: 
     170                        req.session[key] = req.args[filter[0]] 
    149171                elif key in req.session: 
    150172                    del req.session[key] 
    151173 
     
    190212        add_link(req, 'alternate', rss_href, _('RSS Feed'), 
    191213                 'application/rss+xml', 'rss') 
    192214 
     215        filter_options_check = {} 
    193216        for filter_ in available_filters: 
    194             data['filters'].append({'name': filter_[0], 'label': filter_[1], 
    195                                     'enabled': filter_[0] in filters}) 
    196  
     217            if filter_[0] in filter_options_check: 
     218                continue 
     219            if filter_[1] == ITimelineEventProvider.CHECKBOX: 
     220                filter_options_check[filter_[0]] = True 
     221                data['filters'].append({'name': filter_[0], 'filter_type': filter_[1], 
     222                                        'label': filter_[2], 
     223                                        'enabled': filters.get(filter_[0], False)}) 
     224            elif filter_[1] == ITimelineEventProvider.STRING: 
     225                filter_options_check[filter_[0]] = True 
     226                data['filters'].append({'name': filter_[0], 'filter_type': filter_[1], 
     227                                        'label': filter_[2], 'enabled': True, 
     228                                        'value': filters.get(filter_[0], filter_[3])}) 
    197229        # Navigation to the previous/next period of 'daysback' days 
    198230        previous_start = format_date(fromdate - timedelta(days=daysback+1), 
    199231                                     format='%Y-%m-%d', tzinfo=req.tz) 
     
    305337        self.log.exception('Timeline event provider %s failed', ep_name) 
    306338 
    307339        guilty_filters = [f[0] for f in ep.get_timeline_filters(req)] 
    308         guilty_kinds = [f[1] for f in ep.get_timeline_filters(req)] 
     340        guilty_labels = [f[2] for f in ep.get_timeline_filters(req)] 
    309341        other_filters = [f for f in current_filters if not f in guilty_filters] 
    310342        if not other_filters: 
    311343            other_filters = [f for f in all_filters if not f in guilty_filters] 
     
    313345                                               'daysback')] 
    314346        href = req.href.timeline(args+[(f, 'on') for f in other_filters]) 
    315347        raise TracError(tag( 
    316             tag.p(', '.join(guilty_kinds), 
     348            tag.p(', '.join(guilty_labels), 
    317349                  ' event provider (', tag.tt(ep_name), ') failed:', tag.br(), 
    318350                  exc_name, ': ', to_unicode(exc), class_='message'), 
    319351            tag.p('You may want to see the other kind of events from the ', 
  • trac/timeline/templates/timeline.html

     
    2121        and <label><input type="text" size="3" name="daysback" value="$daysback" /> days back</label>. 
    2222       </div> 
    2323       <fieldset> 
    24         <label py:for="filter in filters"> 
     24        <label py:for="filter in filters" py:if="filter.filter_type == 'checkbox'"> 
    2525          <input type="checkbox" name="${filter.name}" 
    2626                 checked="${filter.enabled or None}"/> ${filter.label} 
    2727        </label> 
     28        <label py:for="filter in filters" py:if="filter.filter_type == 'string'"> 
     29          ${filter.label}  
     30          <input type="text" name="${filter.name}" value="${filter.value}"/> 
     31        </label> 
    2832       </fieldset> 
    2933       <div class="buttons"> 
    3034        <input type="submit" name="update" value="Update" /> 
  • contrib/workflow/graph-workflows

     
     1#!/bin/bash 
     2for f in *.ini ../../trac/ticket/workflows/*.ini 
     3  do 
     4    echo $f 
     5    dot=`basename "$f" .ini`.dot 
     6    python workflow_parser.py $f | grep -v rotate > $dot 
     7    dot $dot -Tpng -O 
     8  done 
     9