def setUp(self):
     self.super()
     config = AgiloConfig(self.env)
     # Adding properties for multiple calculated property testing
     # The problem is that at this point the linkConfiguration as been
     # already initialized so we will need to do it again manually
     config.change_option('actual_time', 'text', 
                          section=AgiloConfig.TICKET_CUSTOM)
     config.change_option(Type.TASK, 
                          'sprint, remaining_time, actual_time, estimated_time, owner, drp_resources',
                          section=AgiloConfig.AGILO_TYPES)
     config.change_option('story.calculate', 
                          'total_remaining_time=sum:get_outgoing.remaining_time, total_actual_time=sum:get_outgoing.actual_time',
                          section=AgiloConfig.AGILO_LINKS)
     config.save()
     
     self.assert_true(config.is_agilo_enabled)
     self.assert_true('actual_time' in config.get_list(Type.TASK, section=AgiloConfig.AGILO_TYPES))
     self.assert_true('actual_time' in config.get_fields_for_type().get(Type.TASK))
     self.assert_equals(config.get('story.calculate', section=AgiloConfig.AGILO_LINKS), 
                      'total_remaining_time=sum:get_outgoing.remaining_time, total_actual_time=sum:get_outgoing.actual_time')
     self._reset_links_configuration()
     # Creates tickets
     self.t1 = self.teh.create_ticket(Type.USER_STORY)
     self.t2 = self.teh.create_ticket(Type.TASK, 
                                      props={Key.REMAINING_TIME: u'20', 
                                             Key.RESOURCES: u'Tim, Tom'})
     self.t3 = self.teh.create_ticket(Type.TASK, 
                                      props={Key.REMAINING_TIME: u'10', 
                                             Key.RESOURCES: u'Tim, Tom'})
     # Now actual_time should be a valid field for Task...
     self.assert_not_none(self.t2.get_field('actual_time'))
 def runTest(self):
     env = self._testenv.get_trac_environment()
     config = AgiloConfig(env).get_section(AgiloConfig.AGILO_LINKS)
     option_name = '%s.calculate' % Type.REQUIREMENT
     configured_properties = config.get_list(option_name)
     broken_definition = 'sum:get_outgoing.blubber'
     configured_properties.append(broken_definition)
     config.change_option(option_name, ', '.join(configured_properties))
     config.save()
     self._tester.login_as(Usernames.admin)
     page_url = self._tester.url + '/admin/agilo/types/%s' % Type.REQUIREMENT
     tc.go(page_url)
     tc.code(200)
     
     html = tc.show()
     assert "sum:get_outgoing.rd_points|type=story|story_priority=Mandatory" in html
     assert 'blubber' not in html
Example #3
0
    def initialize(self):
        """Initialize the links configuration from the give config key"""
        self._currently_initializing = True

        # Prevent recursive imports (AgiloConfig needs to import the ticket
        # module)
        from agilo.utils.config import AgiloConfig
        if self._initialized and AgiloConfig(self.env).is_agilo_enabled:
            return

        links = AgiloConfig(self.env).get_section(AgiloConfig.AGILO_LINKS)
        for pair in links.get_list(LinkOption.ALLOW):
            if pair.find('-') == -1:
                continue
            self._parse_option(pair, links)
        # Set to initialized
        self._initialized = True
        self._currently_initializing = False
Example #4
0
 def initialize(self):
     """Initialize the links configuration from the give config key"""
     self._currently_initializing = True
     
     # Prevent recursive imports (AgiloConfig needs to import the ticket
     # module)
     from agilo.utils.config import AgiloConfig
     if self._initialized and AgiloConfig(self.env).is_agilo_enabled:
         return
     
     links = AgiloConfig(self.env).get_section(AgiloConfig.AGILO_LINKS)
     for pair in links.get_list(LinkOption.ALLOW):
         if pair.find('-') == -1:
             continue
         self._parse_option(pair, links)
     # Set to initialized
     self._initialized = True
     self._currently_initializing = False
Example #5
0
class TypesAdminPanel(AgiloAdminPanel):
    """
    Administration panel for different ticket types and their fields.
    Needs to get imported in agilo/admin/__init__.py in order to appear
    on the web interface.
    """

    _type = 'types'
    _label = ('Types', _('Types'))

    def __init__(self):
        self.agilo_config = AgiloConfig(self.env)

    def _get_field_labels(self):
        """Returns a dictionary of fields and their labels."""
        labels = {}
        for f_name, label in self.agilo_config.LABELS.items():
            if f_name not in MANDATORY_FIELDS:
                labels[f_name] = label
        return labels

    def _get_fields(self, type_name=None):
        """
        If type_name is not set, return a dictionary of ticket types 
        and the corresponding fields as a list. If a type_name gets 
        passed, return a list of fields corresponding to this ticket 
        type.
        """
        fields = self.agilo_config.get_available_types(with_fields=True)
        if type_name:
            fields = fields.get(type_name)
        return fields

    def detail_save_view(self, req, cat, page, ticket_type):
        """Save the detail panel view"""
        # The types will be stored in lowercase and the space is not a
        # valid character for the config file key
        ticket_type = normalize_ticket_type(ticket_type)

        alias = req.args.get(Key.ALIAS)
        if alias:
            self.agilo_config.change_option('%s.%s' % (ticket_type, Key.ALIAS),
                                            alias,
                                            section=AgiloConfig.AGILO_TYPES,
                                            save=False)
        # save fields as string or comma-separated list of values
        # FIXME: (AT) after going crazy, it came out that some types are not
        # saved because there is no specific field assigned and the config
        # won't store the property in the trac.ini. So the agilo type will also
        # not be loaded, even if the alias would be set.
        fields = req.args.get(Key.FIELDS, '')
        # We have to save strings not lists
        if isinstance(fields, list):
            fields = ', '.join(fields)
        self.agilo_config.change_option(ticket_type,
                                        fields,
                                        section=AgiloConfig.AGILO_TYPES,
                                        save=False)
        calc = []
        for res, func in zip(req.args.getlist('result'),
                             req.args.getlist('function')):
            if res and func:
                configstring = u'%s=%s' % (res.strip(), func.strip())
                parsed = parse_calculated_field(configstring)
                if parsed == None:
                    msg = u"Wrong format for calculated property '%s'"
                    raise TracError(_(msg) % res)
                calc.append(configstring)
        calc = ','.join(calc)
        if calc:
            self.agilo_config.change_option(
                '%s.%s' % (ticket_type, LinkOption.CALCULATE),
                calc,
                section=AgiloConfig.AGILO_LINKS,
                save=False)
        self.agilo_config.save()

        # on 0.12 we need to reset the ticket fields explicitely as the synchronization
        # is not done with the trac.ini anymore
        if AgiloTicketSystem(self.env).is_trac_012():
            AgiloTicketSystem(self.env).reset_ticket_fields()
        return req.redirect(req.href.admin(cat, page))

    def detail_view(self, req, cat, page, ticket_type):
        # All keys are saved lower-cased, but this is not done
        # automatically for retrieval
        calc_prop = self.agilo_config.get_list(
            '%s.%s' % (ticket_type, LinkOption.CALCULATE),
            section=AgiloConfig.AGILO_LINKS)
        calculated_properties = []
        if len(calc_prop) > 0:
            for definition in calc_prop:
                parts = definition.split('=', 1)
                if len(parts) == 2:
                    property_name, formula = parts
                    calculated_properties.append(
                        (property_name.strip(), formula.strip()))
                else:
                    message = u"Ignoring broken definition for " \
                              "calculated property: %s" % definition
                    warning(self, message)
        data = {
            'calculate': calculated_properties,
            'view': 'detail',
            'type': ticket_type,
            'alias': self.agilo_config.ALIASES.get(ticket_type, ''),
            'type_fields': self._get_fields(ticket_type),
            'labels': self._get_field_labels(),
        }
        return 'agilo_admin_types.html', data

    def list_view(self, req, cat, page):
        data = {
            'view': 'list',
            'fields': self._get_fields(),
            'aliases': self.agilo_config.ALIASES,
            'labels': self._get_field_labels(),
        }
        return 'agilo_admin_types.html', data
Example #6
0
class TypesAdminPanel(AgiloAdminPanel):
    """
    Administration panel for different ticket types and their fields.
    Needs to get imported in agilo/admin/__init__.py in order to appear
    on the web interface.
    """
    
    _type = 'types'
    _label = ('Types', _('Types'))

    def __init__(self):
        self.agilo_config = AgiloConfig(self.env)

    def _get_field_labels(self):
        """Returns a dictionary of fields and their labels."""
        labels = {}
        for f_name, label in self.agilo_config.LABELS.items():
            if f_name not in MANDATORY_FIELDS:
                labels[f_name] = label
        return labels

    def _get_fields(self, type_name=None):
        """
        If type_name is not set, return a dictionary of ticket types 
        and the corresponding fields as a list. If a type_name gets 
        passed, return a list of fields corresponding to this ticket 
        type.
        """
        fields = self.agilo_config.get_available_types(with_fields=True)
        if type_name:
            fields = fields.get(type_name)
        return fields
    
    def detail_save_view(self, req, cat, page, ticket_type):
        """Save the detail panel view"""
        # The types will be stored in lowercase and the space is not a
        # valid character for the config file key
        ticket_type = normalize_ticket_type(ticket_type)
        
        alias = req.args.get(Key.ALIAS)
        if alias:
            self.agilo_config.change_option('%s.%s' % (ticket_type, Key.ALIAS), 
                                            alias, 
                                            section=AgiloConfig.AGILO_TYPES,
                                            save=False)
        # save fields as string or comma-separated list of values
        # FIXME: (AT) after going crazy, it came out that some types are not
        # saved because there is no specific field assigned and the config 
        # won't store the property in the trac.ini. So the agilo type will also
        # not be loaded, even if the alias would be set.
        fields = req.args.get(Key.FIELDS, '') 
        # We have to save strings not lists
        if isinstance(fields, list):
            fields = ', '.join(fields)
        self.agilo_config.change_option(ticket_type, 
                                        fields,
                                        section=AgiloConfig.AGILO_TYPES,
                                        save=False)
        calc = []
        for res, func in zip(req.args.getlist('result'), 
                             req.args.getlist('function')):
            if res and func:
                configstring = u'%s=%s' % (res.strip(), func.strip())
                parsed = parse_calculated_field(configstring)
                if parsed == None:
                    msg = u"Wrong format for calculated property '%s'"
                    raise TracError(_(msg) % res)
                calc.append(configstring)
        calc = ','.join(calc)
        if calc:
            self.agilo_config.change_option('%s.%s' % (ticket_type, 
                                                       LinkOption.CALCULATE), 
                                            calc,
                                            section=AgiloConfig.AGILO_LINKS,
                                            save=False)
        self.agilo_config.save()
        
        # on 0.12 we need to reset the ticket fields explicitely as the synchronization 
        # is not done with the trac.ini anymore
        if AgiloTicketSystem(self.env).is_trac_012():
            AgiloTicketSystem(self.env).reset_ticket_fields()
        return req.redirect(req.href.admin(cat, page))
    
    def detail_view(self, req, cat, page, ticket_type):
        # All keys are saved lower-cased, but this is not done 
        # automatically for retrieval
        calc_prop = self.agilo_config.get_list('%s.%s' % (ticket_type, 
                                                          LinkOption.CALCULATE),
                                               section=AgiloConfig.AGILO_LINKS)
        calculated_properties = []
        if len(calc_prop) > 0:
            for definition in calc_prop:
                parts = definition.split('=', 1)
                if len(parts) == 2:
                    property_name, formula = parts
                    calculated_properties.append((property_name.strip(), 
                                                  formula.strip()))
                else:
                    message = u"Ignoring broken definition for " \
                              "calculated property: %s" % definition
                    warning(self, message)
        data = {
            'calculate' : calculated_properties,
            'view': 'detail',
            'type': ticket_type,
            'alias' : self.agilo_config.ALIASES.get(ticket_type, ''),
            'type_fields' : self._get_fields(ticket_type),
            'labels' : self._get_field_labels(),
        }
        return 'agilo_admin_types.html', data
    
    def list_view(self, req, cat, page):
        data = {
            'view': 'list',
            'fields': self._get_fields(),
            'aliases' : self.agilo_config.ALIASES,
            'labels' : self._get_field_labels(),
        }
        return 'agilo_admin_types.html', data