Exemplo n.º 1
0
 def _prepare_links(self, tkt, db):
     links = TicketLinks(self.env, tkt, db)
     links.blocking = set(
         int(n) for n in self.NUMBERS_RE.findall(tkt['blocking'] or ''))
     links.blocked_by = set(
         int(n) for n in self.NUMBERS_RE.findall(tkt['blockedby'] or ''))
     return links
Exemplo n.º 2
0
    def _get_stats_config(self):
        all_statuses = set(TicketSystem(self.env).get_all_status())
        remaining_statuses = set(all_statuses)
        groups =  DefaultTicketGroupStatsProvider(self.env)._get_ticket_groups()
        catch_all_group = None

        for group in groups:
            status_str = group['status'].strip()
            if status_str == '*':
                if catch_all_group:
                    raise TracError(_(
                        "'%(group1)s' and '%(group2)s' milestone groups "
                        "both are declared to be \"catch-all\" groups. "
                        "Please check your configuration.",
                        group1=group['name'], group2=catch_all_group['name']))
                catch_all_group = group
            else:
                group_statuses = set([s.strip()
                                      for s in status_str.split(',')]) \
                                      & all_statuses
                if group_statuses - remaining_statuses:
                    raise TracError(_(
                        "'%(groupname)s' milestone group reused status "
                        "'%(status)s' already taken by other groups. "
                        "Please check your configuration.",
                        groupname=group['name'],
                        status=', '.join(group_statuses - remaining_statuses)))
                else:
                    remaining_statuses -= group_statuses
                group['statuses'] = group_statuses
        if catch_all_group:
            catch_all_group['statuses'] = remaining_statuses
        
        return groups
Exemplo n.º 3
0
 def sort(self):
     """Do an in-place topological sort of this prototype."""
     from api import TracForgeAdminSystem
     steps = TracForgeAdminSystem(self.env).get_project_setup_participants()
     
     all_provides = set()
     for action, args in self:
         all_provides |= set(steps[action].get('provides', ()))
     
     effective_depends = {}
     for action, args in self:
         # All real deps are always used
         effective_depends.setdefault(action, []).extend(steps[action].get('depends', ()))
         for tag in steps[action].get('optional_depends', ()):
             # Any optional dep that is provided by something else is used
             if tag in all_provides:
                 effective_depends[action].append(tag)
     
     old = set([action for action, args in self])
     new = []
     tags = set()
     for i in xrange(len(self)):
         for action in old:
             self.env.log.debug('TracForge: %s %s %s %s %s', i, action, old, new, tags)
             if all([tag in tags for tag in effective_depends[action]]):
                 new.append(action)
                 tags |= set(steps[action].get('provides', []))
                 old.remove(action)
                 break
         if not old:
             break
     if old:
         raise ValueError('Cant solve')
     action_map = dict(self)
     self[:] = [(action, action_map[action]) for action in new]
Exemplo n.º 4
0
    def __init__(self, env, tkt, db=None, ticket_cache=None):
        '''Initialize ticket links
        Use `ticket_cache` (if is not None) to store fetched tickets.
        '''
        self.env = env
        if not isinstance(tkt, Ticket):
            if ticket_cache is not None:
                tid = int(tkt)
                if tid not in ticket_cache:
                    ticket_cache[tid] = Ticket(self.env, tid)
                tkt = ticket_cache[tid]
            else:
                tkt = Ticket(self.env, tkt)
        self.tkt = tkt

        db = db or self.env.get_db_cnx()
        cursor = db.cursor()

        cursor.execute('SELECT dest FROM mastertickets WHERE source=%s ORDER BY dest', (self.tkt.id,))
        self.blocking = set([int(num) for num, in cursor])
        self._old_blocking = copy.copy(self.blocking)

        cursor.execute('SELECT source FROM mastertickets WHERE dest=%s ORDER BY source', (self.tkt.id,))
        self.blocked_by = set([int(num) for num, in cursor])
        self._old_blocked_by = copy.copy(self.blocked_by)
Exemplo n.º 5
0
 def _update_pages(self):
     all_pages = WikiSystem(self.env).get_pages()
     self.pages = set([p for p in all_pages if len(p) >= self.minimum_length])
     exclude = set([p.strip() for p in (self.exclude or '') if p.strip()])
     self.pages.difference_update(exclude)
     explicitly_wikified = set([p.strip() for p in (self.explicitly_wikify or '') if p.strip()])
     self.pages.update(explicitly_wikified)
Exemplo n.º 6
0
    def get_user_permissions(self, username):
        """Retrieve the permissions for the given user and return them in a
        dictionary.
        
        The permissions are stored in the database as (username, action)
        records. There's simple support for groups by using lowercase names for
        the action column: such a record represents a group and not an actual
        permission, and declares that the user is part of that group.
        """
        subjects = set([username])
        for provider in self.group_providers:
            subjects.update(provider.get_permission_groups(username))

        actions = set([])
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("SELECT username,action FROM permission")
        rows = cursor.fetchall()
        while True:
            num_users = len(subjects)
            num_actions = len(actions)
            for user, action in rows:
                if user in subjects:
                    if action.isupper() and action not in actions:
                        actions.add(action)
                    if not action.isupper() and action not in subjects:
                        # action is actually the name of the permission group
                        # here
                        subjects.add(action)
            if num_users == len(subjects) and num_actions == len(actions):
                break
        return list(actions)
Exemplo n.º 7
0
    def post_process_request(self, req, template, data, content_type):
        if req.path_info.startswith('/ticket/'):
            # In case of an invalid ticket, the data is invalid
            if not data:
                return template, data, content_type
            tkt = data['ticket']
            links = TicketLinks(self.env, tkt)

            for i in links.blocked_by:
                if Ticket(self.env, i)['status'] != 'closed':
                    add_script(req, 'mastertickets/disable_resolve.js')
                    break

            # Add link to depgraph if needed
            if links:
                add_ctxtnav(req, 'Depgraph',
                            req.href.depgraph('ticket', tkt.id))

            for change in data.get('changes', {}):
                if not change.has_key('fields'):
                    continue
                for field, field_data in change['fields'].iteritems():
                    if field in self.fields:
                        if field_data['new'].strip():
                            new = set(
                                [int(n) for n in field_data['new'].split(',')])
                        else:
                            new = set()
                        if field_data['old'].strip():
                            old = set(
                                [int(n) for n in field_data['old'].split(',')])
                        else:
                            old = set()
                        add = new - old
                        sub = old - new
                        elms = tag()
                        if add:
                            elms.append(
                                tag.em(u', '.join(
                                    [unicode(n) for n in sorted(add)])))
                            elms.append(u' added')
                        if add and sub:
                            elms.append(u'; ')
                        if sub:
                            elms.append(
                                tag.em(u', '.join(
                                    [unicode(n) for n in sorted(sub)])))
                            elms.append(u' removed')
                        field_data['rendered'] = elms

        #add a link to generate a dependency graph for all the tickets in the milestone
        if req.path_info.startswith('/milestone/'):
            if not data:
                return template, data, content_type
            milestone = data['milestone']
            add_ctxtnav(req, 'Depgraph',
                        req.href.depgraph('milestone', milestone.name))

        return template, data, content_type
Exemplo n.º 8
0
    def ticket_deleted(self, tkt):
        db = self.env.get_db_cnx()

        links = TicketLinks(self.env, tkt, db)
        links.blocking = set()
        links.blocked_by = set()
        links.save('trac', 'Ticket #%s deleted' % tkt.id, when=None, db=db)

        db.commit()
Exemplo n.º 9
0
 def ticket_changed(self, tkt, comment, author, old_values):
     db = self.env.get_db_cnx()
     
     links = TicketLinks(self.env, tkt, db)
     links.blocking = set(self.NUMBERS_RE.findall(tkt['blocking'] or ''))
     links.blocked_by = set(self.NUMBERS_RE.findall(tkt['blockedby'] or ''))
     links.save(author, comment, tkt.time_changed, db)
     
     db.commit()
Exemplo n.º 10
0
    def testSprintTicketStatsChartUsesAliases(self):
        self.env.compmgr.enabled[SprintTicketStatsChartGenerator] = True
        self.teh.create_ticket(Type.USER_STORY, {Key.SPRINT: self.sprint.name})

        get_widget = ChartGenerator(self.env).get_chartwidget
        widget = get_widget(ChartType.SPRINT_TICKET_STATS, sprint_name=self.sprint.name)

        chart_labels = set([item[1] for item in widget.data["labels"]])
        self.assert_equals(set(["User Story", "Task"]), chart_labels)
Exemplo n.º 11
0
    def ticket_changed(self, tkt, comment, author, old_values):
        db = self.env.get_db_cnx()

        links = TicketLinks(self.env, tkt, db)
        links.blocking = set(self.NUMBERS_RE.findall(tkt['blocking'] or ''))
        links.blocked_by = set(self.NUMBERS_RE.findall(tkt['blockedby'] or ''))
        links.save(author, comment, tkt.time_changed, db)

        db.commit()
Exemplo n.º 12
0
 def _update_pages(self):
     all_pages = WikiSystem(self.env).get_pages()
     self.pages = set(
         [p for p in all_pages if len(p) >= self.minimum_length])
     exclude = set([p.strip() for p in (self.exclude or '') if p.strip()])
     self.pages.difference_update(exclude)
     explicitly_wikified = set(
         [p.strip() for p in (self.explicitly_wikify or '') if p.strip()])
     self.pages.update(explicitly_wikified)
Exemplo n.º 13
0
 def ticket_deleted(self, tkt):
     db = self.env.get_db_cnx()
     
     links = TicketLinks(self.env, tkt, db)
     links.blocking = set()
     links.blocked_by = set()
     links.save('trac', 'Ticket #%s deleted'%tkt.id, when=None, db=db)
     
     db.commit()
Exemplo n.º 14
0
    def post_process_request(self, req, template, data, content_type):
        if req.path_info.startswith('/ticket/'):
            # In case of an invalid ticket, the data is invalid
            if not data:
                return template, data, content_type
            tkt = data['ticket']
            links = TicketLinks(self.env, tkt)
            
            for i in links.blocked_by:
                if Ticket(self.env, i)['status'] != 'closed':
                    add_script(req, 'mastertickets/disable_resolve.js')
                    break

            # Add link to depgraph if needed
            if links:
                add_ctxtnav(req, 'Depgraph', req.href.depgraph(tkt.id))
            
            for change in data.get('changes', {}):
                if not change.has_key('fields'):
                    continue
                for field, field_data in change['fields'].iteritems():
                    if field in self.fields:
                        if field_data['new'].strip():
                            new = set([int(n) for n in field_data['new'].split(',')])
                        else:
                            new = set()
                        if field_data['old'].strip():
                            old = set([int(n) for n in field_data['old'].split(',')])
                        else:
                            old = set()
                        add = new - old
                        sub = old - new
                        elms = tag()
                        if add:
                            elms.append(
                                tag.em(u', '.join([unicode(n) for n in sorted(add)]))
                            )
                            elms.append(u' added')
                        if add and sub:
                            elms.append(u'; ')
                        if sub:
                            elms.append(
                                tag.em(u', '.join([unicode(n) for n in sorted(sub)]))
                            )
                            elms.append(u' removed')
                        field_data['rendered'] = elms
            
        #add a link to generate a dependency graph for all the tickets in the milestone
        if req.path_info.startswith('/milestone/'):
            if not data:
                return template, data, content_type
            milestone=data['milestone']
            add_ctxtnav(req, 'Depgraph', req.href.depgraph('milestone', milestone.name))


        return template, data, content_type
Exemplo n.º 15
0
    def testSprintTicketStatsChartUsesAliases(self):
        self.env.compmgr.enabled[SprintTicketStatsChartGenerator] = True
        self.teh.create_ticket(Type.USER_STORY, {Key.SPRINT: self.sprint.name})

        get_widget = ChartGenerator(self.env).get_chartwidget
        widget = get_widget(ChartType.SPRINT_TICKET_STATS,
                            sprint_name=self.sprint.name)

        chart_labels = set([item[1] for item in widget.data['labels']])
        self.assert_equals(set(['User Story', 'Task']), chart_labels)
Exemplo n.º 16
0
 def _field_names_for_backlog_types(self):
     field_names = set()
     ticket_config = AgiloConfig(self.env).ticket_configuration
     for type_name in self.ticket_types:
         # don't trust the type_name in self.ticket_types, backlog admin page
         # does not do validation on that
         if type_name not in ticket_config.fieldnames_per_type:
             continue
         fields_for_this_type = ticket_config.fieldnames_per_type[type_name]
         field_names.update(set(fields_for_this_type))
     return field_names
Exemplo n.º 17
0
 def _field_names_for_backlog_types(self):
     field_names = set()
     ticket_config = AgiloConfig(self.env).ticket_configuration
     for type_name in self.ticket_types:
         # don't trust the type_name in self.ticket_types, backlog admin page
         # does not do validation on that
         if type_name not in ticket_config.fieldnames_per_type:
             continue
         fields_for_this_type = ticket_config.fieldnames_per_type[type_name]
         field_names.update(set(fields_for_this_type))
     return field_names
Exemplo n.º 18
0
    def post_process_request(self,
                             req,
                             template,
                             data,
                             content_type,
                             method=None):
        if req.path_info.startswith('/ticket/'):
            # In case of an invalid ticket, the data is invalid
            if not data:
                return template, data, content_type, method
            tkt = data['ticket']
            with self.env.db_query as db:
                links = CrashDumpTicketLinks(self.env, tkt, db=db)

                for change in data.get('changes', {}):
                    if not change.has_key('fields'):
                        continue
                    for field, field_data in change['fields'].iteritems():
                        if field in self.crashdump_link_fields:
                            if field_data['new'].strip():
                                new = set([
                                    CrashDumpSystem.get_crash_id(n)
                                    for n in field_data['new'].split(',')
                                ])
                            else:
                                new = set()
                            if field_data['old'].strip():
                                old = set([
                                    CrashDumpSystem.get_crash_id(n)
                                    for n in field_data['old'].split(',')
                                ])
                            else:
                                old = set()
                            add = new - old
                            sub = old - new
                            elms = tag()
                            if add:
                                elms.append(
                                    tag.em(u', '.join(
                                        [unicode(n) for n in sorted(add)])))
                                elms.append(u' added')
                            if add and sub:
                                elms.append(u'; ')
                            if sub:
                                elms.append(
                                    tag.em(u', '.join(
                                        [unicode(n) for n in sorted(sub)])))
                                elms.append(u' removed')
                            field_data['rendered'] = elms
                            links.crashes = new

        return template, data, content_type, method
Exemplo n.º 19
0
    def post_process_request(self, req, template, data, content_type):
        if req.path_info.startswith('/ticket/'):
            tkt = data['ticket']
            links = TicketLinks(self.env, tkt)

            for i in links.blocked_by:
                if Ticket(self.env, i)['status'] != 'closed':
                    add_script(req, 'mastertickets/disable_resolve.js')
                    break

            data['mastertickets'] = {
                'field_values': {
                    'blocking': linkify_ids(self.env, req, links.blocking),
                    'blockedby': linkify_ids(self.env, req, links.blocked_by),
                },
            }

            # Add link to depgraph if needed
            if links:
                add_ctxtnav(req, 'Depgraph', req.href.depgraph(tkt.id))

            for change in data.get('changes', []):
                for field, field_data in change['fields'].iteritems():
                    if field in self.fields:
                        if field_data['new'].strip():
                            new = set(
                                [int(n) for n in field_data['new'].split(',')])
                        else:
                            new = set()
                        if field_data['old'].strip():
                            old = set(
                                [int(n) for n in field_data['old'].split(',')])
                        else:
                            old = set()
                        add = new - old
                        sub = old - new
                        elms = tag()
                        if add:
                            elms.append(
                                tag.em(u', '.join(
                                    [unicode(n) for n in sorted(add)])))
                            elms.append(u' added')
                        if add and sub:
                            elms.append(u'; ')
                        if sub:
                            elms.append(
                                tag.em(u', '.join(
                                    [unicode(n) for n in sorted(sub)])))
                            elms.append(u' removed')
                        field_data['rendered'] = elms

        return template, data, content_type
Exemplo n.º 20
0
    def post_process_request(self, req, template, origData, content_type):
        if req.path_info.startswith('/newticket'):
            mode = 'new'
        elif req.path_info.startswith('/ticket/'):
            mode = 'view'
        else:
            return template, origData, content_type
        fieldData = {}
        fieldData['condfields'] = {}

        all_fields = []
        standard_fields = set()
        for f in TicketSystem(self.env).get_ticket_fields():
            all_fields.append(f['name'])
            if not f.get('custom'):
                standard_fields.add(f['name'])

        if 'owner' in all_fields:
            curr_idx = all_fields.index('owner')
            if 'cc' in all_fields:
                insert_idx = all_fields.index('cc')
            else:
                insert_idx = len(all_fields)
            if curr_idx < insert_idx:
                all_fields.insert(insert_idx, all_fields[curr_idx])
                del all_fields[curr_idx]

        for t in self.types:
            fieldData['condfields'][t] = self.get_fields(t, all_fields, standard_fields)
            # fields = set(getattr(self, t+'_fields'))
            # if self.include_std:
            #     fields.update(standard_fields)
            # fields.update(self.forced_fields)
            # fieldData['condfields'][t] = dict([
            #     (f, f in fields) for f in all_fields
            # ])

        self.log.debug(all_fields)
        self.log.info(standard_fields)

        fieldData['mode'] = mode
        fieldData['all_fields'] = list(all_fields)
        fieldData['ok_view_fields'] = sorted(set(all_fields) - self.forced_fields,
                                             key=lambda x: all_fields.index(x))
        fieldData['ok_new_fields'] = sorted((set(all_fields) - self.forced_fields) - set(['owner']),
                                            key=lambda x: all_fields.index(x))

        add_script_data(req, fieldData)
        add_script(req, '/condfields.js')
        return template, origData, content_type
Exemplo n.º 21
0
 def _get_metric_groups(self, available_metrics):
     # Some metrics are well known and we show them together in one chart.
     # We have the RT_USP ratio separate because of two reasons:
     #  - it has not much to do with the other charts
     #  - the numbers are much lower so we would need to add a second scale 
     #    which is not yet implemented in the team metrics chart.
     chart_groups = [(Key.ESTIMATED_VELOCITY, Key.VELOCITY), 
                     (Key.CAPACITY, Key.COMMITMENT), 
                     (Key.RT_USP_RATIO, )]
     grouped_metrics = []
     [grouped_metrics.extend(i) for i in chart_groups]
     other_metrics = set(available_metrics).difference(set(grouped_metrics))
     other_metrics = [(i,) for i in other_metrics]
     return chart_groups + other_metrics
Exemplo n.º 22
0
    def post_process_request(self, req, template, data, content_type):
        if req.path_info.startswith('/ticket/'):
            tkt = data['ticket']
            links = TicketLinks(self.env, tkt)
            
            for i in links.blocked_by:
                if Ticket(self.env, i)['status'] != 'closed':
                    add_script(req, 'mastertickets/disable_resolve.js')
                    break

            data['mastertickets'] = {
                'field_values': {
                    'blocking': linkify_ids(self.env, req, links.blocking),
                    'blockedby': linkify_ids(self.env, req, links.blocked_by),
                },
            }
            
            # Add link to depgraph if needed
            if links:
                add_ctxtnav(req, 'Depgraph', req.href.depgraph(tkt.id))
            
            for change in data.get('changes', []):
                for field, field_data in change['fields'].iteritems():
                    if field in self.fields:
                        if field_data['new'].strip():
                            new = set([int(n) for n in field_data['new'].split(',')])
                        else:
                            new = set()
                        if field_data['old'].strip():
                            old = set([int(n) for n in field_data['old'].split(',')])
                        else:
                            old = set()
                        add = new - old
                        sub = old - new
                        elms = tag()
                        if add:
                            elms.append(
                                tag.em(u', '.join([unicode(n) for n in sorted(add)]))
                            )
                            elms.append(u' added')
                        if add and sub:
                            elms.append(u'; ')
                        if sub:
                            elms.append(
                                tag.em(u', '.join([unicode(n) for n in sorted(sub)]))
                            )
                            elms.append(u' removed')
                        field_data['rendered'] = elms
            
        return template, data, content_type
Exemplo n.º 23
0
    def process_request(self, req):
        data = {}
        ticket_types = {}
        field_types = {}
        mode = req.path_info[12:-3]
        if mode != 'new' and mode != 'view':
            raise TracError('Invalid condfields view')
        all_fields = []
        standard_fields = set()
        for f in TicketSystem(self.env).get_ticket_fields():
            all_fields.append(f['name'])

        field_types[f['name']] = f['type']

        if not f.get('custom'):
            standard_fields.add(f['name'])

        if 'owner' in all_fields:
            curr_idx = all_fields.index('owner')
            if 'cc' in all_fields:
                insert_idx = all_fields.index('cc')
            else:
                insert_idx = len(all_fields)
            if curr_idx < insert_idx:
                all_fields.insert(insert_idx, all_fields[curr_idx])
                del all_fields[curr_idx]

        for t in self.types:
            if not self.show_default:
                hiddenfields = set(getattr(self, t+'_fields'))
                fields = set(all_fields)
                fields.difference_update(hiddenfields)
            else:
                fields = set(getattr(self, t+'_fields'))
                if self.include_std:
                    fields.update(standard_fields)
            fields.update(set(self.forced_fields))
            ticket_types[t] = dict([
                (f, f in fields) for f in all_fields
            ])

        self.log.debug(all_fields)
        self.log.info(standard_fields)

        data['mode'] = mode
        data['types'] = json.dumps(ticket_types)
        data['field_types'] = json.dumps(field_types)
        data['required_fields'] = json.dumps(list(self.forced_fields))

        return 'condfields.js', {'condfields': data}, 'text/plain'
Exemplo n.º 24
0
    def ticket_changed(self, tkt, comment, author, old_values):
        db = self.env.get_db_cnx()

        links = TicketLinks(self.env, tkt, db)

        old_relations = {'blocking': set([]), 'blockedby': set([])}
        if "blocking" in old_values:
            old_relations['blocking'] = extract_ticket_ids(old_values['blocking'])

        if "blockedby" in old_values:
            old_relations['blockedby'] = extract_ticket_ids(old_values['blockedby'])

        links.save(old_relations, author, comment, tkt.time_changed, db)

        db.commit()
Exemplo n.º 25
0
    def get_tagged_resources(self, req, tags):
        if not self.check_permission(req.perm, "view"):
            return
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        args = [self.realm]
        sql = "SELECT DISTINCT name FROM tags WHERE tagspace=%s"
        if tags:
            sql += " AND tags.tag IN (%s)" % ", ".join(["%s" for t in tags])
            args += tags
        sql += " ORDER by name"
        cursor.execute(sql, args)

        resources = {}
        for (name,) in cursor:
            resource = Resource(self.realm, name)
            if self.check_permission(req.perm(resource), "view"):
                resources[resource.id] = resource

        if not resources:
            return

        args = [self.realm] + list(resources)
        # XXX Is this going to be excruciatingly slow?
        sql = "SELECT DISTINCT name, tag FROM tags WHERE tagspace=%%s AND " "name IN (%s) ORDER BY name" % ", ".join(
            ["%s" for _ in resources]
        )
        cursor.execute(sql, args)

        for name, tags in groupby(cursor, lambda row: row[0]):
            resource = resources[name]
            yield resource, set([tag[1] for tag in tags])
Exemplo n.º 26
0
    def query(self, req, query="", attribute_handlers=None):
        """Return a sequence of (resource, tags) tuples matching a query.

        Query syntax is described in tractags.query.

        :param attribute_handlers: Register additional query attribute
                                   handlers. See Query documentation for more
                                   information.
        """

        def realm_handler(_, node, context):
            return query.match(node, [context.realm])

        all_attribute_handlers = {"realm": realm_handler}
        all_attribute_handlers.update(attribute_handlers or {})
        if re.search(r"(expression|tagspace|tagspaces|operation|showheadings" "|expression)=", query):
            message = Markup(
                "You seem to be using an old Tag query. "
                'Try using the <a href="%s">new syntax</a> in your '
                "<strong>ListTagged</strong> macro.",
                req.href("tags"),
            )
            add_warning(req, message)
        query = Query(query, attribute_handlers=all_attribute_handlers)

        query_tags = set(query.terms())
        for provider in self.tag_providers:
            for resource, tags in provider.get_tagged_resources(req, query_tags):
                if query(tags, context=resource):
                    yield resource, tags
Exemplo n.º 27
0
    def render_announcement_preference_box(self, req, panel):
        supported_realms = {}
        for producer in self.producers:
            for realm in producer.realms():
                for distributor in self.distributors:
                    for transport in distributor.transports():
                        for fmtr in self.formatters:
                            for style in fmtr.styles(transport, realm):
                                if realm not in supported_realms:
                                    supported_realms[realm] = set()
                                supported_realms[realm].add(style)

        if req.method == "POST":
            for realm in supported_realms:
                opt = req.args.get('email_format_%s' % realm, False)
                if opt:
                    req.session['announcer_email_format_%s' % realm] = opt
        prefs = {}
        for realm in supported_realms:
            prefs[realm] = req.session.get('announcer_email_format_%s' % realm,
                                           None) or self._get_default_format()
        data = dict(
            realms=supported_realms,
            preferences=prefs,
        )
        return "prefs_announcer_email.html", data
Exemplo n.º 28
0
    def __str__(self):
        edges = []
        nodes = []

        memo = set()

        def process(lst):
            for obj in lst:
                if obj in memo:
                    continue
                memo.add(obj)

                if isinstance(obj, Node):
                    nodes.append(obj)
                    process(obj.edges)
                elif isinstance(obj, Edge):
                    edges.append(obj)
                    if isinstance(obj.source, Node):
                        process((obj.source, ))
                    if isinstance(obj.dest, Node):
                        process((obj.dest, ))

        process(self.nodes)
        process(self.edges)

        lines = [u'digraph "%s" {' % self.name]
        for att, value in self.attributes.iteritems():
            lines.append(u'\t%s="%s";' % (att, value))
        for obj in itertools.chain(nodes, edges):
            lines.append(u'\t%s;' % obj)
        lines.append(u'}')
        return u'\n'.join(lines)
Exemplo n.º 29
0
 def get_all_status(self):
     """Returns a sorted list of all the states all of the action
     controllers know about."""
     valid_states = set()
     for controller in self.action_controllers:
         valid_states.update(controller.get_all_status())
     return sorted(valid_states)
Exemplo n.º 30
0
    def set_tags(self, req, resource, tags):
        """Set tags on a resource.

        Existing tags are replaced.
        """
        return self._get_provider(resource.realm) \
            .set_resource_tags(req, resource, set(tags))
Exemplo n.º 31
0
    def __init__(self, env, tkt, db=None):
        self.env = env
        if not isinstance(tkt, Ticket):
            tkt = Ticket(self.env, tkt)
        self.tkt = tkt

        db = db or self.env.get_db_cnx()
        cursor = db.cursor()

        cursor.execute('SELECT dest FROM mastertickets WHERE source=%s ORDER BY dest', (self.tkt.id,))
        self.blocking = set([int(num) for num, in cursor])
        self._old_blocking = copy.copy(self.blocking)

        cursor.execute('SELECT source FROM mastertickets WHERE dest=%s ORDER BY source', (self.tkt.id,))
        self.blocked_by = set([int(num) for num, in cursor])
        self._old_blocked_by = copy.copy(self.blocked_by)
Exemplo n.º 32
0
    def validate_test_case(self, req, postname, version, fields):
        if 'testcase-preview' in req.args:
            return []

        qa_res = Resource('qa', postname, version)

        if req.perm(qa_res).has_permission('QA_ADMIN'):
            return []

        if version > 1:
            bp = BlogPost(self.env, postname, version)
            last_post_fields = bp._fetch_fields(version=version - 1)
        else:
            last_post_fields = {}

        field_names = set(fields).union(last_post_fields)
        changes = []

        for field in field_names:
            old = to_unicode(last_post_fields.get(field, ''))
            new = to_unicode(fields.get(field, ''))
            if new and old != new:
                changes.append((old, new))
        author = fields.get('author', '')

        if arity(FilterSystem.test) == 4:
            # 0.11 compatible method signature
            FilterSystem(self.env).test(req, author, changes)
        else:
            # 0.12+ compatible that adds an 'ip' argument
            FilterSystem(self.env).test(req, author, changes, req.remote_addr)
        return []
Exemplo n.º 33
0
    def render_announcement_preference_box(self, req, panel):
        supported_realms = {}
        for producer in self.producers:
            for realm in producer.realms():
                for distributor in self.distributors:
                    for transport in distributor.transports():
                        for fmtr in self.formatters:
                            for style in fmtr.styles(transport, realm):
                                if realm not in supported_realms:
                                    supported_realms[realm] = set()
                                supported_realms[realm].add(style)

        settings = {}
        for realm in supported_realms:
            name = 'xmpp_format_%s' % realm
            settings[realm] = SubscriptionSetting(
                self.env, name,
                XmppDistributor(self.env).xmpp_format_setting.default)
        if req.method == "POST":
            for realm, setting in settings.items():
                name = 'xmpp_format_%s' % realm
                setting.set_user_setting(req.session,
                                         req.args.get(name),
                                         save=False)
            req.session.save()
        prefs = {}
        for realm, setting in settings.items():
            prefs[realm] = setting.get_user_setting(req.session.sid)[0]
        data = dict(
            realms=supported_realms,
            preferences=prefs,
        )
        return "prefs_announcer_xmpp.html", data
Exemplo n.º 34
0
    def validate_blog_post(self, req, postname, version, fields):
        if 'blog-preview' in req.args:
            return []

        blog_res = Resource('blog', postname, version)
        if req.perm(blog_res).has_permission('BLOG_ADMIN'):
            return []

        if version > 1:
            bp = BlogPost(self.env, postname, version)
            last_post_fields = bp._fetch_fields(version=version-1)
        else:
            last_post_fields = {}

        field_names = set(fields).union(last_post_fields)
        changes = []
        for field in field_names:
            old = to_unicode(last_post_fields.get(field, ''))
            new = to_unicode(fields.get(field, ''))
            if new and old != new:
                changes.append((old, new))
        author = fields.get('author', '')
        if arity(FilterSystem.test) == 4:
            # 0.11 compatible method signature
            FilterSystem(self.env).test(req, author, changes)
        else:
            # 0.12+ compatible that adds an 'ip' argument
            FilterSystem(self.env).test(req, author, changes, req.remote_addr)
        return []
Exemplo n.º 35
0
 def _all_configured_ticket_fields(self):
     field_names = set()
     ticket_config = AgiloConfig(self.env).ticket_configuration
     for field_names_for_type in ticket_config.fieldnames_per_type.values():
         for field_name in field_names_for_type:
             field_names.add(field_name)
     return list(field_names)
Exemplo n.º 36
0
def render_cloud(env, req, cloud, renderer=None):
    """Render a tag cloud

    :cloud: Dictionary of {object: count} representing the cloud.
    :param renderer: A callable with signature (tag, count, percent) used to
                     render the cloud objects.
    """
    min_px = 10.0
    max_px = 30.0
    scale = 1.0

    if renderer is None:
        def default_renderer(tag, count, percent):
            href = get_resource_url(env, Resource('tag', tag), req.href)
            return builder.a(tag, rel='tag', title='%i' % count, href=href,
                             style='font-size: %ipx' %
                                   int(min_px + percent * (max_px - min_px)))
        renderer = default_renderer

    # A LUT from count to n/len(cloud)
    size_lut = dict([(c, float(i)) for i, c in
                     enumerate(sorted(set([r for r in cloud.values()])))])
    if size_lut:
        scale = 1.0 / len(size_lut)

    ul = builder.ul(class_='tagcloud')
    last = len(cloud) - 1
    for i, (tag, count) in enumerate(sorted(cloud.iteritems())):
        percent = size_lut[count] * scale
        li = builder.li(renderer(tag, count, percent))
        if i == last:
            li(class_='last')
        li()
        ul(li)
    return ul
Exemplo n.º 37
0
    def ticket_deleted(self, tkt):
        with self.env.db_transaction as db:
            links = CrashDumpTicketLinks(self.env, tkt, db)
            links.crashes = set()
            links.save('trac', 'Ticket #%s deleted'%tkt.id, when=None, db=db)

            db.commit()
Exemplo n.º 38
0
    def get_tagged_resources(self, req, tags):
        if 'TAGS_VIEW' not in req.perm or 'QA_VIEW' not in req.perm:
            return

        db = self.env.get_db_cnx()
        cursor = db.cursor()

        args = []
        constraints = []
        sql = "SELECT bp1.name, bp1.categories, bp1.version " \
               "FROM qa_testcases bp1," \
               "(SELECT name, max(version) AS ver " \
               "FROM qa_testcases GROUP BY name) bp2 " \
               "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name"
        if tags:
            constraints.append(
                "(" + ' OR '.join(["bp1.categories LIKE %s"
                                   for t in tags]) + ")")
            args += ['%' + t + '%' for t in tags]
        else:
            constraints.append("bp1.categories != ''")
        if constraints:
            sql += " AND " + " AND ".join(constraints)
        sql += " ORDER BY bp1.name"
        self.env.log.debug(sql)
        cursor.execute(sql, args)
        for row in cursor:
            post_name, categories = row[0], set(_parse_categories(row[1]))
            if not tags or categories.intersection(tags):
                resource = Resource('blog', post_name)
                if 'QA_VIEW' in req.perm(resource) and \
                        'TAGS_VIEW' in req.perm(resource):
                    yield (resource, categories)
Exemplo n.º 39
0
 def _fetch_fields(self, version=0):
     """ Returns a dict with field/value combinations for the content
     of a specific version of a blog post, or last/current version if
     version is 0.
     Returns emtpy dict if no such post or post/version exists. """
     self.versions = self.get_versions()
     if not self.versions or (version and not version in self.versions):
         # No blog post with the name exists
         return {}
     version = version or self.versions[-1]
     cnx = self.env.get_db_cnx()
     cursor = cnx.cursor()
     cursor.execute("SELECT title, body, publish_time, version_time, "
             "version_comment, version_author, author, categories "
             "FROM fullblog_posts "
             "WHERE name=%s AND version=%s",
             (self.name, version) )
     fields = {}
     for row in cursor:
         fields['version'] = version
         fields['title'] = row[0]
         fields['body'] = row[1]
         fields['publish_time'] = to_datetime(row[2], utc)
         fields['version_time'] = to_datetime(row[3], utc)
         fields['version_comment'] = row[4]
         fields['version_author'] = row[5]
         fields['author'] = row[6]
         fields['categories'] = row[7]
         fields['category_list'] = set(_parse_categories(row[7]))
     return fields
Exemplo n.º 40
0
    def query(self, req, query='', attribute_handlers=None):
        """Return a sequence of (resource, tags) tuples matching a query.

        Query syntax is described in tractags.query.

        :param attribute_handlers: Register additional query attribute
                                   handlers. See Query documentation for more
                                   information.
        """
        def realm_handler(_, node, context):
            return query.match(node, [context.realm])

        all_attribute_handlers = {
            'realm': realm_handler,
        }
        all_attribute_handlers.update(attribute_handlers or {})
        if re.search(
                r'(expression|tagspace|tagspaces|operation|showheadings'
                '|expression)=', query):
            message = Markup(
                'You seem to be using an old Tag query. '
                'Try using the <a href="%s">new syntax</a> in your '
                '<strong>ListTagged</strong> macro.', req.href('tags'))
            add_warning(req, message)
        query = Query(query, attribute_handlers=all_attribute_handlers)

        query_tags = set(query.terms())
        for provider in self.tag_providers:
            for resource, tags in provider.get_tagged_resources(
                    req, query_tags):
                if query(tags, context=resource):
                    yield resource, tags
Exemplo n.º 41
0
 def _get_available_metrics(self, metrics_by_sprint):
     "Return a list containing the keys of all available metrics"
     available_metrics = set()
     for sprint, metrics in metrics_by_sprint:
         for metrics_name in metrics:
             available_metrics.add(metrics_name)
     return list(available_metrics)
Exemplo n.º 42
0
    def get_tagged_resources(self, req, tags):
        if not self.check_permission(req.perm, 'view'):
            return
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        args = [self.realm]
        sql = 'SELECT DISTINCT name FROM tags WHERE tagspace=%s'
        if tags:
            sql += ' AND tags.tag IN (%s)' % ', '.join(['%s' for t in tags])
            args += tags
        sql += ' ORDER by name'
        cursor.execute(sql, args)

        resources = {}
        for name, in cursor:
            resource = Resource(self.realm, name)
            if self.check_permission(req.perm(resource), 'view'):
                resources[resource.id] = resource

        if not resources:
            return

        args = [self.realm] + list(resources)
        # XXX Is this going to be excruciatingly slow?
        sql = 'SELECT DISTINCT name, tag FROM tags WHERE tagspace=%%s AND ' \
              'name IN (%s) ORDER BY name' % ', '.join(['%s' for _ in resources])
        cursor.execute(sql, args)

        for name, tags in groupby(cursor, lambda row: row[0]):
            resource = resources[name]
            yield resource, set([tag[1] for tag in tags])
Exemplo n.º 43
0
    def _get_groups(self, user):
        # Get initial subjects
        groups = set([user])
        for provider in self.group_providers:
            for group in provider.get_permission_groups(user):
                groups.add(group)

        # Essentially the default trac PermissionStore ignores user provided
        # groups so we have to look them up manually: 

        # changed this to only do this for the default permission
        # store this has been reported as broken/very slow for the
        # LDAP permission store
        ps = PermissionSystem(self.env) 
        if isinstance(ps.store, DefaultPermissionStore):
            perms = ps.get_all_permissions()
            repeat = True
            while repeat:
                repeat = False
                for subject, action in perms:
                    if subject in groups and not action.isupper() and action not in groups:
                        groups.add(action)
                        repeat = True 
        
        return groups    
    def __str__(self):
        edges = []
        nodes = []

        memo = set()

        def process(lst):
            for obj in lst:
                if obj in memo:
                    continue
                memo.add(obj)

                if isinstance(obj, Node):
                    nodes.append(obj)
                    process(obj.edges)
                elif isinstance(obj, Edge):
                    edges.append(obj)
                    if isinstance(obj.source, Node):
                        process((obj.source,))
                    if isinstance(obj.dest, Node):
                        process((obj.dest,))

        process(self.nodes)
        process(self.edges)

        lines = [u'digraph "%s" {' % self.name]
        for att, value in self.attributes.iteritems():
            lines.append(u'\t%s="%s";' % (att, value))
        for obj in itertools.chain(nodes, edges):
            lines.append(u'\t%s;' % obj)
        lines.append(u'}')
        return u'\n'.join(lines)
Exemplo n.º 45
0
 def _fetch_fields(self, version=0):
     """ Returns a dict with field/value combinations for the content
     of a specific version of a blog post, or last/current version if
     version is 0.
     Returns emtpy dict if no such post or post/version exists. """
     self.versions = self.get_versions()
     if not self.versions or (version and not version in self.versions):
         # No blog post with the name exists
         return {}
     version = version or self.versions[-1]
     sql = "SELECT title, body, publish_time, version_time, " \
           "version_comment, version_author, author, categories " \
           "FROM fullblog_posts " \
           "WHERE name=%s AND version=%s"
     args = (self.name, version)
     if hasattr(self.env, 'db_query'):
         cursor = self.env.db_query(sql, args)
     else:
         db = self.env.get_db_cnx()
         cursor = db.cursor()
         cursor.execute(sql, args)
     fields = {}
     for row in cursor:
         fields['version'] = version
         fields['title'] = row[0]
         fields['body'] = row[1]
         fields['publish_time'] = to_datetime(row[2], utc)
         fields['version_time'] = to_datetime(row[3], utc)
         fields['version_comment'] = row[4]
         fields['version_author'] = row[5]
         fields['author'] = row[6]
         fields['categories'] = row[7]
         fields['category_list'] = set(_parse_categories(row[7]))
     return fields
Exemplo n.º 46
0
    def get_tagged_resources(self, req, tags):
        if 'TAGS_VIEW' not in req.perm or 'BLOG_VIEW' not in req.perm:
            return

        db = self.env.get_db_cnx()
        cursor = db.cursor()

        args = []
        constraints = []
        sql = "SELECT bp1.name, bp1.categories, bp1.version " \
               "FROM fullblog_posts bp1," \
               "(SELECT name, max(version) AS ver " \
               "FROM fullblog_posts GROUP BY name) bp2 " \
               "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name"
        if tags:
            constraints.append("(" + ' OR '.join(
                            ["bp1.categories LIKE %s" for t in tags]) + ")")
            args += ['%' + t + '%' for t in tags]
        else:
            constraints.append("bp1.categories != ''")
        if constraints:
            sql += " AND " + " AND ".join(constraints)
        sql += " ORDER BY bp1.name"
        self.env.log.debug(sql)
        cursor.execute(sql, args)
        for row in cursor:
            post_name, categories = row[0], set(_parse_categories(row[1]))
            if not tags or categories.intersection(tags):
                resource = Resource('blog', post_name)
                if 'BLOG_VIEW' in req.perm(resource) and \
                        'TAGS_VIEW' in req.perm(resource):
                    yield (resource, categories)
Exemplo n.º 47
0
    def set_tags(self, req, resource, tags):
        """Set tags on a resource.

        Existing tags are replaced.
        """
        return self._get_provider(resource.realm) \
            .set_resource_tags(req, resource, set(tags))
Exemplo n.º 48
0
 def __init__(self, env, tkt, db=None):
     self.env = env
     if not isinstance(tkt, Ticket):
         tkt = Ticket(self.env, tkt)
     self.tkt = tkt
     
     db = db or self.env.get_db_cnx()
     cursor = db.cursor()
     
     cursor.execute('SELECT dest FROM mastertickets WHERE source=%s ORDER BY dest', (self.tkt.id,))
     self.blocking = set([int(num) for num, in cursor])
     self._old_blocking = copy.copy(self.blocking)
     
     cursor.execute('SELECT source FROM mastertickets WHERE dest=%s ORDER BY source', (self.tkt.id,))
     self.blocked_by = set([int(num) for num, in cursor])
     self._old_blocked_by = copy.copy(self.blocked_by)
Exemplo n.º 49
0
 def get_months_authors_categories(self, from_dt=None, to_dt=None,
                                             user=None, perm=None):
     """ Returns a structure of post metadata:
         ([ ((year1, month1), count), ((year1, month2), count) ], # newest first
          [ (author1, count), (author2, count) ],                 # alphabetical
          [ (category1, count), (category2, count) ],             # alphabetical
          total)                                                  # num of posts
     * Use 'from_dt' and 'to_dt' (datetime objects) to restrict search to
     posts with a publish_time within the intervals (None means ignore).
     * If user and perm is provided, the list is also filtered for permissions.
     * Note also that it only fetches from most recent version. """
     blog_posts = get_blog_posts(self.env, from_dt=from_dt, to_dt=to_dt)
     a_dict = {}
     c_dict = {}
     m_dict = {}
     total = 0
     for post in blog_posts:
         if user and perm:
             # Check permissions
             bp = BlogPost(self.env, post[0], post[1])
             if not 'BLOG_VIEW' in perm(bp.resource):
                 continue # Skip this post
         post_time = post[2]
         m_dict[(post_time.year, post_time.month)] = m_dict.get(
                 (post_time.year, post_time.month), 0) + 1
         author = post[3]
         a_dict[author] = a_dict.get(author, 0) + 1
         categories = post[6] # a list
         for category in set(categories):
             c_dict[category] = c_dict.get(category, 0) + 1
         total += 1
     return ([(m, m_dict.get(m, 0)) for m in sorted(m_dict.keys(), reverse=True)],
             [(a, a_dict.get(a, 0)) for a in sorted(a_dict.keys())],
             [(c, c_dict.get(c, 0)) for c in sorted(c_dict.keys())],
             total)
Exemplo n.º 50
0
    def tickets_for_crash(db, crashid):
        cursor = db.cursor()

        #print('tickets_for_crash db=%s, crashid=%s %s' % (db, crashid, type(crashid)))

        cursor.execute('SELECT ticket FROM crashdump_ticket WHERE crash=%s ORDER BY ticket', (crashid,))
        return set([int(num) for num, in cursor])
Exemplo n.º 51
0
    def ticket_deleted(self, tkt):
        with self.env.db_transaction as db:
            links = CrashDumpTicketLinks(self.env, tkt, db)
            links.crashes = set()
            links.save('trac', 'Ticket #%s deleted'%tkt.id, when=None, db=db)

            db.commit()
Exemplo n.º 52
0
 def _all_configured_ticket_fields(self):
     field_names = set()
     ticket_config = AgiloConfig(self.env).ticket_configuration
     for field_names_for_type in ticket_config.fieldnames_per_type.values():
         for field_name in field_names_for_type:
             field_names.add(field_name)
     return list(field_names)
Exemplo n.º 53
0
            def attr_modifier(name, event):
                attrs = event[1][1]
                class_list = attrs.get(name, '').split()
                self.log.debug('BH Theme : Element classes ' + str(class_list))

                out_classes = ' '.join(set(class_list + classes))
                self.log.debug('BH Theme : Inserting class ' + out_classes)
                return out_classes
 def test_can_extract_contingent_from_readonly_page(self):
     expected_contingent = dict(name='foo', amount='6.0', used='2.0')
     page = TeamSprintDetailTester(None,
                                   'Foo Team',
                                   'Foo Sprint',
                                   html=no_delete_fixture)
     self.assertEqual(set(['foo']), page.contingent_names())
     self.assertEqual(expected_contingent, page.contingent_for_name('foo'))
Exemplo n.º 55
0
 def _real_send(self, evt):
     """Accepts a single AnnouncementEvent instance (or subclass), and
     returns nothing. 
     
     There is no way (intentionally) to determine what the 
     AnnouncementSystem did with a particular event besides looking through
     the debug logs.
     """
     try:
         supported_subscribers = []
         for sp in self.subscribers:
             categories = sp.get_subscription_categories(evt.realm)
             if categories:
                 if ('*' in categories) or (evt.category in categories):
                     supported_subscribers.append(sp)
         self.log.debug(
             "AnnouncementSystem found the following subscribers capable of"
             " handling '%s, %s': %s" % (evt.realm, evt.category, 
             ', '.join([ss.__class__.__name__ for ss in \
                     supported_subscribers]))
         )
         subscriptions = set()
         for sp in supported_subscribers:
             subscriptions.update(
                 x for x in sp.get_subscriptions_for_event(evt) if x
             )
         self.log.debug(
             "AnnouncementSystem has found the following subscriptions: " \
                     "%s"%(', '.join(['[%s(%s) via %s]' % ((s[1] or s[3]),\
                     s[2] and 'authenticated' or 'not authenticated',s[0])\
                     for s in subscriptions]
                 )
             )
         )
         packages = {}
         for transport, sid, authenticated, address in subscriptions:
             if transport not in packages:
                 packages[transport] = set()
             packages[transport].add((sid,authenticated,address))
         for distributor in self.distributors:
             transport = distributor.get_distribution_transport()
             if transport in packages:
                 distributor.distribute(transport, packages[transport], evt)
     except:
         self.log.error("AnnouncementSystem failed.", exc_info=True)