def test_doesnt_overwrite_custom_favicons(self): custom_favicon = 'fnord' project_section = AgiloConfig(self.env).get_section('project') project_section.change_option('icon', custom_favicon) self.assert_equals(custom_favicon, project_section.get('icon')) initialize_config(self.env, {}) project_section = AgiloConfig(self.env).get_section('project') self.assert_equals(custom_favicon, project_section.get('icon'))
def test_reload_config(self): """Tests the reload of the config""" types = AgiloConfig(self.env).get_section(AgiloConfig.AGILO_TYPES) # Add a ticket type types.change_option('my_type', ', '.join([Key.PRIORITY, Key.COMPONENT])) types.change_option('my_type.alias', 'My Type') types.save() self.assert_true('my_type' in AgiloConfig(self.env).ALIASES, "Type not found in aliases, AgiloConfig not reloaded?")
def _hide_fields_not_configured_for_this_type(self, req, data): ticket_type = req.args[Key.TYPE] ats = AgiloTicketSystem(self.env) normalized_type = ats.normalize_type(ticket_type) data[Key.TYPE] = normalized_type fields_for_type = AgiloConfig(self.env).TYPES.get(normalized_type, []) create_perms = CoreTemplateProvider(self.env).create_permissions(req) if normalized_type in create_perms: for data_field in data['fields']: field_name = data_field[Key.NAME] if field_name == Key.TYPE: current_options = data_field.get('options', []) data_field['options'] = \ self._ticket_types_the_user_can_create_or_modify(normalized_type, current_options, create_perms) data['type_selection'] = data_field data_field[Key.SKIP] = True elif not field_name in fields_for_type: # Skip the field and the value if it's not for this type data_field[Key.SKIP] = True elif data_field[Key.SKIP] and (field_name not in MANDATORY_FIELDS): # We have to make all fields visible which belong to # this ticket type. Unfortunately, Trac just creates # a Ticket (though an AgiloTicket due to our monkey # patching) and we can't influence the instantiation # itself. # Therefore it just depends on the default ticket type # set in the environment what fields this ticket has. # Therefore some fields are marked skipped although they # should be displayed. # trac itself skips some fields because it want to have # more control over the positioning. We have to respect # that. # fs, 04.11.2008: I thought about moving this condition # to_prepare_fields where I think this code should live # but then I would have to copy all the conditions and # probably the code is here for a good reason so I'm # just adding it here. data_field[Key.SKIP] = False elif field_name == Key.OWNER and ats.restrict_owner: # we need to transform the field into a list of users ats.eventually_restrict_owner(data_field) elif len(create_perms) > 0: # Redirect to the first allowed type for the given user. first_allowed_type = create_perms[0] req.redirect(req.href.newticket(type=first_allowed_type)) else: if ticket_type not in AgiloConfig(self.env).ALIASES: raise TracError(u"Unkown type '%s'!" % ticket_type) raise TracError("You are not allowed to create a %s!" % ticket_type) return data
def testCanDisableSprintStartDateNormalization(self): config = AgiloConfig(self.env).get_section(AgiloConfig.AGILO_GENERAL) option_name = 'sprints_can_start_or_end_on_weekends' self.assert_false(config.get_bool(option_name)) config.change_option(option_name, True, save=True) self.assert_true( AgiloConfig(self.env).sprints_can_start_or_end_on_weekends) start = datetime(2009, 05, 30, tzinfo=utc) sprint = self.teh.create_sprint('Foo', start=start) self.assert_equals(start, sprint.start) self.assert_equals(utc, sprint.start.tzinfo)
def testTimeRenderer(self): """Tests the time renderer""" task = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '2.5'}) r = Renderer(task, Key.REMAINING_TIME) # force hours AgiloConfig(self.teh.get_env()).use_days = False self.assert_equals('2.5h', r()) self.assert_equals('2.5h', '%s' % r) # force days AgiloConfig(self.teh.get_env()).use_days = True self.assert_equals('2.5d', r()) self.assert_equals('2.5d', '%s' % r)
def _filter_info(self): config = AgiloConfig(self.env) if not config.backlog_filter_attribute: return dict() return dict(should_filter_by_attribute=config.backlog_filter_attribute, should_reload_burndown_on_filter_change_when_filtering_by_component= \ config.should_reload_burndown_on_filter_change_when_filtering_by_component)
def _prepare_fields(self, req, ticket, field_changes=None): """Set specific renderer for the ticket fields""" fields = super(AgiloTicketModule, self)._prepare_fields(req, ticket) if not AgiloConfig(self.env).is_agilo_enabled: return fields from agilo.scrum import SprintController sp_controller = SprintController(self.env) for field in fields: field[Key.RENDERED] = self._rendered_ticket_value(ticket, field) # makes the nice Sprint pulldown to emulate the milestone one if field[Key.NAME] == Key.SPRINT: get_options = SprintController.GetSprintOptionListCommand( self.env, sprint_names=field[Key.OPTIONS]) closed, running, to_start = sp_controller.process_command( get_options) field[Key.OPTIONS] = [] field[Key.OPTIONS_GROUP] = [ { Key.LABEL: _('Running (by Start Date)'), Key.OPTIONS: running }, { Key.LABEL: _('To Start (by Start Date)'), Key.OPTIONS: to_start }, { Key.LABEL: _('Closed (by Start Date)'), Key.OPTIONS: closed }, ] return fields
def environment_created(self): for table in db_default.schema: create_table(self.env, table) cache_manager = HttpRequestCacheManager(self.env) po_manager = PersistentObjectManager(self.env) for manager in cache_manager.managers: model_class = manager.for_model() if issubclass(model_class, PersistentObject): module_name = model_class.__module__ # We don't want to create tables for dummy classes automatically # but the test finder may load some of these managers so we # need to exclude them here. if ('tests.' not in module_name): po_manager.create_table(model_class) # Need to create Agilo types in the database before writing to the # configuration - otherwise we get a warning during config setup (you'll # see it in every test case during setUp) db_default.create_default_types(self.env) initialize_config(self.env, __CONFIG_PROPERTIES__) db_default.create_default_backlogs(self.env) super(AgiloInit, self).environment_created() for listener in self.setup_listeners: listener.agilo_was_installed() # Reload the AgiloConfig to make sure all the changes have been updated AgiloConfig(self.env).reload() info(self, 'Agilo environment initialized')
def _filter_by(self, data): filter_by = None if AgiloConfig( self.env ).should_reload_burndown_on_filter_change_when_filtering_by_component: filter_by = data.get('filter_by') return filter_by
def detail_view(self, req, cat, page, name, backlog_config=None): backlog_config = self._backlog_config_with_changed_ticket_types( req, cat, page, name, backlog_config=backlog_config) # REFACT: Maybe we should use JSON here rather than xml? if ajax.is_ajax(req): # we got called by an Ajax request -> get available fields fields_for_selected_types = backlog_config.columns_as_fields( all_fields=False) items = [field[Key.NAME] for field in fields_for_selected_types] return 'ajax_response.xml', {'items': items} # TODO: Go for ticket configuration agilo_config = AgiloConfig(self.env) data = { 'view': 'detail', 'backlog': backlog_config, 'backlog_types': BacklogType.LABELS, 't_types': [(t_type, t_type in backlog_config.ticket_types, agilo_config.ALIASES.get(t_type, t_type)) for t_type in agilo_config.TYPES.keys()], 'fields': backlog_config.columns_as_fields(all_fields=True), } add_script(req, 'agilo/js/backlog_admin.js') add_script(req, 'common/js/wikitoolbar.js') return 'agilo_admin_backlog.html', data
def testTimeRendererWithIntegers(self): task = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '2'}) r = Renderer(task, Key.REMAINING_TIME) # force hours AgiloConfig(self.teh.get_env()).use_days = False self.assert_equals('2.0h', r())
def remove_all_account_manager_components_from_config(self): env = self._testenv.get_trac_environment() components = AgiloConfig(env).get_section('components') for name in components.get_options_by_prefix('acct_mgr', chop_prefix=False): components.remove_option(name, save=False) components.save()
def _all_field_names(self): all_field_names = set() ticket_configuration = AgiloConfig(self.env).ticket_configuration for field_names in ticket_configuration.fieldnames_per_type.values(): for field_name in field_names: all_field_names.add(field_name) return all_field_names
def initialize_agilo(self, project_name, db_url, svn_repo, demo=False): try: self.do_initenv( '%s %s %s %s' % (project_name, db_url, 'svn', svn_repo or 'somewhere')) # Now add agilo and the template path env = Environment(self.envname) ac = AgiloConfig(env) if not svn_repo: # remove the fake from the config ac.change_option('repository_dir', '', 'trac') # sets the restric_owner option ac.change_option('restrict_owner', 'true', 'ticket') # this is also saving the config ac.enable_agilo() # update wiki wiki = WikiPage(env, name='WikiStart') wiki.text = agilo_wiki wiki.save('admin', 'Updated to Agilo', '127.0.0.1') # reset the env self.env_set(envname=self.envname, env=env) # Now initialize Agilo self.do_upgrade('upgrade --no-backup') # Now create the demo if needed if demo: try: from create_demo_data import _create_demo_data _create_demo_data(env) except ImportError, e: env.log.error(exception_to_unicode(e)) except: pass
def config_reloaded(self): """Recreate mapping dictionaries when needed""" config = AgiloConfig(self.env) if config.ALIASES is not None: self._alias_to_type = dict( zip(config.ALIASES.values(), config.ALIASES.keys())) self.cp = CommandParser(self.env, config.ALIASES, self._alias_to_type)
def test_changing_type_restore_correct_fields(self): """Tests that changing a ticket type restores the correct fields for that type""" t = AgiloTicket(self.env, t_type=Type.TASK) self.assert_true(self._matching_properties(t)) # Now change that to a story t[Key.TYPE] = Type.USER_STORY self.assert_true(self._matching_properties(t)) # Now reload config and change to bug ac = AgiloConfig(self.env) ac.reload() t[Key.TYPE] = Type.BUG self.assert_true(self._matching_properties(t)) # Now add a field on the fly and see if it is adapting to it agilo_types = ac.get_section(ac.AGILO_TYPES) ticket_custom = ac.get_section(ac.TICKET_CUSTOM) ticket_custom.change_option('customer', 'text') ticket_custom.change_option('customer.label', 'Customer') fields = agilo_types.get_list(Type.BUG) fields.append('customer') # notice the save to force the reload of the config agilo_types.change_option('story', ','.join(fields), save=True) t[Key.TYPE] = Type.USER_STORY self.assert_true('customer' in t.fields_for_type, \ "No 'customer' in %s" % t.fields_for_type) t['customer'] = 'My Own Customer' self.assert_true(self._matching_properties(t)) t.insert() self.assert_true(self._matching_properties(t)) self.assert_equals('My Own Customer', t['customer'])
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)
def is_email_verification_enabled(env): AgiloConfig(env).clear_trac_component_cache() try: from acct_mgr.web_ui import EmailVerificationModule return env.is_component_enabled(EmailVerificationModule) except ImportError: return None
def test_can_extract_remaining_time_with_unit(self): task_id = self.teh.create_task().id parsed = [('rem', "%s" % task_id, '3h')] self.assert_equals(parsed, self.parse('rem #%s:3h' % task_id)) AgiloConfig(self.env).use_days = True parsed = [('TIME', "%s" % task_id, '3d')] self.assert_equals(parsed, self.parse('TIME #%s:3d' % task_id))
def _days_to_remove_from_burndown(self, sprint, viewer_timezone): if not AgiloConfig(self.env).burndown_should_show_working_days_only: return [] if sprint.team is None: return [] days_to_remove = sprint.team.capacity(viewer_timezone).days_without_capacity_in_interval(sprint.start, sprint.end) return days_to_remove
def _set_duration(self, value): """Sets the duration of the Sprint and recalculates the end Date""" if value is not None: week_days_off = None if AgiloConfig(self.env).sprints_can_start_or_end_on_weekends: week_days_off = [] self.end = add_to_date(self.start, value, week_days_off=week_days_off) debug(self, "Setting Sprint end date to: %s" % self.end)
def _set_default_type(self, new_value): agilo_config = AgiloConfig(self.env) old_value = agilo_config.get('default_type', 'ticket') agilo_config.change_option('default_type', new_value, section='ticket', save=True) return old_value
def test_do_not_sets_default_logo_if_changed(self): test_src = 'my_logo' agilo_config = AgiloConfig(self.env) header_logo = agilo_config.get_section('header_logo') header_logo.change_option('src', test_src) self.assert_equals(test_src, header_logo.get('src')) set_default_agilo_logo(agilo_config) self.assert_equals(test_src, header_logo.get('src'))
def get_actions_for_custom_types(self): for typename in AgiloConfig(self.env).get_available_types(): plain_name = str('CREATE_' + typename.upper()) aliased_permission_name = getattr(Action, plain_name, plain_name) if aliased_permission_name not in self.actions: self.actions.append(aliased_permission_name) # Trac admin will get all these permissions implicitly so we # don't need to give him the permission explicitly. self._add_permission_for_role(Role.TICKET_ADMIN, aliased_permission_name)
def _set_restrict_owner_option(self, new_value): env = self._testenv.get_trac_environment() agilo_config = AgiloConfig(env) old_value = agilo_config.get_bool('restrict_owner', 'ticket') agilo_config.change_option('restrict_owner', new_value, section='ticket', save=True) return old_value
def render(self): """Returns the rendered property with a d or h""" if self.value_is_a_number() or isinstance(self.value, (float, int, Decimal)): if AgiloConfig(self.env).use_days: return u"%sd" % round(float(self.value), 2) else: return u"%sh" % round(float(self.value), 1) return self.value
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
def _update_configuration(env): my_config = copy(__CONFIG_PROPERTIES__) del my_config[AgiloConfig.AGILO_LINKS] del my_config[AgiloConfig.AGILO_TYPES] initialize_config(env, my_config) config = AgiloConfig(env).tc # Only the trac config wrapper _update_agilo_types(config) _update_calculated_properties(config, env)
def set_sprint_can_start_or_end_on_weekends(self): # The sprint must be running only for exactly one day, otherwise # confirm commitment is not possible anymore (and the total capacity # might be different) env = self.testenv.get_trac_environment() config = AgiloConfig(env) config.change_option('sprints_can_start_or_end_on_weekends', True, section='agilo-general') config.save()
def validate_includes_configured_unit_in_remaining_time(self, remaining_time): if len(remaining_time) > 0 and remaining_time[-1] not in ('h', 'd'): self.validation_errors.append("Need h(our) or d(ay) unit for remaining time '%s'" % remaining_time) return config = AgiloConfig(self.env) if config.use_days and remaining_time.endswith('h'): self.validation_errors.append("Wrong unit used in remaining time '%s' (Agilo is configured to use days)" % remaining_time) if not config.use_days and remaining_time.endswith('d'): self.validation_errors.append("Wrong unit used in remaining time '%s' (Agilo is configured to use hours)" % remaining_time)