def test_add_inactive_project(cli, data_dir): project = Project(1, 'test project', Project.STATUS_FINISHED) project.activities = [Activity(2, 'test activity', 0)] p = ProjectsDb(str(data_dir)) p.update([project]) output = cli('project', ['alias', 'test project'], input='test_alias') assert "No active project matches your search string" in output
def test_add_inactive_project(self): project = Project(1, 'test project', Project.STATUS_FINISHED) project.activities = [Activity(2, 'test activity', 0)] p = ProjectsDb(self.taxi_dir) p.update([project]) output = self.run_project_command(['alias', 'test project'], input='test_alias') self.assertIn("No active project matches your search string", output)
def test_add_single_choice(self): project = Project(1, 'test project', Project.STATUS_ACTIVE) project.activities = [Activity(2, 'test activity', 0)] p = ProjectsDb(self.taxi_dir) p.update([project]) self.run_project_command(['alias', 'test project'], input='test_alias') with open(self.config_file, 'r') as f: self.assertIn('test_alias = 1/2\n', f.readlines())
def get_projects(self): p = Project(self.name, self.name, Project.STATUS_ACTIVE, description=self.name) a = Activity(0, "No activity") p.add_activity(a) p.aliases[self.name] = a.id return [p]
def test_add_single_choice(cli, data_dir, config): project = Project(1, 'test project', Project.STATUS_ACTIVE) project.activities = [Activity(2, 'test activity', 0)] p = ProjectsDb(str(data_dir)) p.update([project]) cli('project', ['alias', 'test project'], input='test_alias') with open(config.path, 'r') as f: lines = f.readlines() assert 'test_alias = 1/2\n' in lines
def test_add_multiple_choices(self): p1 = Project(1, 'test project', Project.STATUS_ACTIVE) p1.activities = [Activity(2, 'test activity', 0)] p2 = Project(2, 'test project 2', Project.STATUS_ACTIVE) p2.activities = [Activity(3, 'test activity 2', 0)] p = ProjectsDb(self.taxi_dir) p.update([p1, p2]) self.run_project_command(['alias', 'test project'], input='1\ntest_alias') with open(self.config_file, 'r') as f: self.assertIn('test_alias = 2/3\n', f.readlines())
def test_project_status(cli, config, data_dir): config.set_dict({ 'test_aliases': { 'alias_not_started': '0/0', 'alias_active': '1/0', 'alias_finished': '2/0', 'alias_cancelled': '3/0', } }) projects_db = ProjectsDb(str(data_dir)) project_not_started = Project(0, 'not started project', Project.STATUS_NOT_STARTED) project_not_started.backend = 'test' project_not_started.activities.append(Activity(0, 'activity', 0)) project_active = Project(1, 'active project', Project.STATUS_ACTIVE) project_active.backend = 'test' project_active.activities.append(Activity(0, 'activity', 0)) project_finished = Project(2, 'finished project', Project.STATUS_FINISHED) project_finished.backend = 'test' project_finished.activities.append(Activity(0, 'activity', 0)) project_cancelled = Project(3, 'cancelled project', Project.STATUS_CANCELLED) project_cancelled.backend = 'test' project_cancelled.activities.append(Activity(0, 'activity', 0)) projects_db.update([ project_not_started, project_active, project_finished, project_cancelled ]) cli('clean-aliases', ['--yes']) settings = Settings(config.path) assert list(settings.get_aliases().keys()) == ['alias_active']
def test_add_multiple_choices(cli, data_dir, config): p1 = Project(1, 'test project', Project.STATUS_ACTIVE) p1.activities = [Activity(2, 'test activity', 0)] p2 = Project(2, 'test project 2', Project.STATUS_ACTIVE) p2.activities = [Activity(3, 'test activity 2', 0)] p = ProjectsDb(str(data_dir)) p.update([p1, p2]) cli('project', ['alias', 'test project'], input='1\ntest_alias') with open(config.path, 'r') as f: lines = f.readlines() assert 'test_alias = 2/3\n' in lines
def get_projects(self): projects_list = [] for (project, activities) in self.projects.iteritems(): p = Project(project, 'foo', 1, 'bar', '1000') p.start_date = None p.end_date = None for activity in activities: p.add_activity(activity) projects_list.append(p) return projects_list
def get_projects(self): projects_list = [] for project_name, count in self.settings.config.items('tempo_projects'): project_name = project_name.upper() p = Project(self.get_project_hash(project_name), project_name, Project.STATUS_ACTIVE) for i in range(1, int(count) + 1): name = f'{project_name}-{i}' a = Activity(i, name, 0) p.add_activity(a) p.aliases[name] = a.id projects_list.append(p) return projects_list
def setUp(self): super(ShowCommandTestCase, self).setUp() self.projects_db = ProjectsDb(self.taxi_dir) projects_list = [] project = Project(42, 'not started project', Project.STATUS_NOT_STARTED) project.backend = 'test' project.activities.append(Activity(1, 'activity 1', 0)) project.activities.append(Activity(2, 'activity 2', 0)) projects_list.append(project) project = Project(123, 'my project', Project.STATUS_ACTIVE) project.backend = 'test' project.activities.append(Activity(456, 'my activity', 0)) projects_list.append(project) self.projects_db.update(projects_list)
def overwrite_alias(self, alias, mapping, retry=True): mapping_name = Project.tuple_to_str(mapping) if retry: choices = 'y/n/R(etry)' default_choice = 'r' choice_regexp = r'^[ynr]$' else: choices = 'y/N' default_choice = 'n' choice_regexp = r'^[yn]$' s = (u"The alias `%s` is already mapped to `%s`.\nDo you want to " "overwrite it [%s]? " % (alias, mapping_name, choices)) overwrite = terminal.select_string( s, choice_regexp, re.I, default_choice ) if overwrite == 'n': return False elif overwrite == 'y': return True return None
def get_projects(self): projects_list = [] for project_name, count in self.settings.config.items('jira_projects'): project_name = project_name.upper() p = Project(project_name, f"[JIRA] {project_name}", Project.STATUS_ACTIVE, description=f"JIRA Project {project_name} (created by backend {self.name})" ) for i in range(1, int(count) + 1): name = f"{project_name}-{i}" a = Activity(i, name) p.add_activity(a) p.aliases[name] = a.id projects_list.append(p) return projects_list
def projects_db(data_dir): projects_db = ProjectsDb(str(data_dir)) projects_list = [] project = Project(42, 'not started project', Project.STATUS_NOT_STARTED) project.backend = 'test' projects_list.append(project) project = Project(43, 'active project', Project.STATUS_ACTIVE) project.backend = 'test' project.activities.append(Activity(1, 'activity 1', 0)) project.activities.append(Activity(2, 'activity 2', 0)) projects_list.append(project) project = Project(44, '2nd active project', Project.STATUS_ACTIVE) project.backend = 'test' project.activities.append(Activity(1, 'activity 1', 0)) projects_list.append(project) projects_db.update(projects_list) return projects_db
def get_projects(self): projects_url = self.get_api_url('/projects/') try: response = self._session.get(projects_url) projects = response.json() except ValueError: raise TaxiException( "Unexpected response from the server (%s). Check your " "credentials" % response.content) projects_list = [] date_attrs = (('start_date', 'startdate'), ('end_date', 'enddate')) for project in projects['data']: p = Project(int(project['id']), project['name'], Project.STATUS_ACTIVE, project['description'], project['budget']) for date_attr, proj_date in date_attrs: try: date = datetime.strptime(project[proj_date], '%Y-%m-%d').date() except (ValueError, TypeError): date = None setattr(p, date_attr, date) for activity in project['activities']: a = Activity(int(activity['id']), activity['name'], activity['rate']) p.add_activity(a) if activity['alias']: p.aliases[activity['alias']] = activity['id'] projects_list.append(p) return projects_list
def get_projects(self): projects_list = [] p = Project(self.instance.upper(), f"[{self.name}] {self.instance}", Project.STATUS_ACTIVE, description=f"{self.name} Project {self.instance}") r = requests.get(f"https://{self.hostname}/2.0/pr_project", headers={ 'Accept': 'application/json', 'Authorization': f"Bearer {self.api_key}" }) response = r.json() if r.status_code != 200: raise Exception( f"[{self.name}] API error: HTTP {r.status_code} - {response['message']}" ) for project in response: name = f"{self.instance.upper()}-{project['id']}" # @todo Ideally, we should have a [bexio_active_project_states] configuration that lists only active # projects and filter here again against /2.0/pr_project_state if project['end_date'] is not None: if datetime.datetime.strptime( project['end_date'], '%Y-%m-%d %H:%M:%S') < datetime.datetime.today(): continue a = Activity(project['id'], project['name']) p.add_activity(a) p.aliases[name] = a.id projects_list.append(p) return projects_list
def setUp(self): super(ProjectCommandTestCase, self).setUp() self.projects_db = ProjectsDb(self.taxi_dir) projects_list = [] project = Project(42, 'not started project', Project.STATUS_NOT_STARTED) project.backend = 'test' projects_list.append(project) project = Project(43, 'active project', Project.STATUS_ACTIVE) project.backend = 'test' project.activities.append(Activity(1, 'activity 1', 0)) project.activities.append(Activity(2, 'activity 2', 0)) projects_list.append(project) project = Project(44, '2nd active project', Project.STATUS_ACTIVE) project.backend = 'test' project.activities.append(Activity(1, 'activity 1', 0)) projects_list.append(project) self.projects_db.update(projects_list)
def get_projects(self): projects = self._request(path='/projects') activities_dict = self.get_activities() projects_list = [] for project in projects: project = project['project'] if not project['code']: continue p = Project( int(project['id']), project['name'], { True: Project.STATUS_ACTIVE, False: Project.STATUS_FINISHED }[project['active']], project['notes'], project['budget'] ) if project['starts_on']: p.start_date = arrow.get(project['starts_on']).date() if project['ends_on']: p.start_date = arrow.get(project['ends_on']).date() activities = self._request(path='/projects/%s/task_assignments' % project['id']) for activity in activities: activity = activity['task_assignment'] try: a = Activity(int(activity['id']), activities_dict[activity['task_id']]['name'], activity['hourly_rate']) p.add_activity(a) except ValueError: logger.warn( "Cannot import activity %s for project %s because " "activity id is not an int" % (activity, p.id) ) activity_alias = '%s_%s' % ( project['code'], slugify(activities_dict[activity['task_id']]['name'], separator='_') ) p.aliases[activity_alias] = activity['id'] projects_list.append(p) return projects_list
def _add_alias(self, alias_name, mapping): project_activity = Project.str_to_tuple(mapping) if project_activity is None: raise UsageError("The mapping must be in the format xxxx/yyyy") if self.settings.activity_exists(alias_name): existing_mapping = self.settings.get_aliases()[alias_name] confirm = self.view.overwrite_alias(alias_name, existing_mapping, False) if not confirm: return self.settings.add_alias(alias_name, project_activity[0], project_activity[1]) self.settings.write_config() self.view.alias_added(alias_name, project_activity)
def run(self): # 2 arguments, add a new alias if self.mode == self.MODE_ADD_ALIAS: self._add_alias(self.alias, self.mapping) # 1 argument, display the alias or the project id/activity id tuple elif self.mode == self.MODE_SHOW_MAPPING: mapping = Project.str_to_tuple(self.alias) if mapping is not None: for m in self.settings.search_aliases(mapping): self.view.mapping_detail(m, self.projects_db.get(m[1][0])) else: self.mode = self.MODE_LIST_ALIASES # No argument, display the mappings if self.mode == self.MODE_LIST_ALIASES: for m in self.settings.search_mappings(self.alias): self.view.alias_detail( m, self.projects_db.get(m[1][0]) if m[1] is not None else None )
def test_project_status(self): projects_db = ProjectsDb(self.taxi_dir) project_not_started = Project(0, 'not started project', Project.STATUS_NOT_STARTED) project_not_started.backend = 'test' project_not_started.activities.append(Activity(0, 'activity', 0)) project_active = Project(1, 'active project', Project.STATUS_ACTIVE) project_active.backend = 'test' project_active.activities.append(Activity(0, 'activity', 0)) project_finished = Project(2, 'finished project', Project.STATUS_FINISHED) project_finished.backend = 'test' project_finished.activities.append(Activity(0, 'activity', 0)) project_cancelled = Project(3, 'cancelled project', Project.STATUS_CANCELLED) project_cancelled.backend = 'test' project_cancelled.activities.append(Activity(0, 'activity', 0)) projects_db.update([ project_not_started, project_active, project_finished, project_cancelled ]) self.run_command('clean-aliases', args=['--yes']) settings = Settings(self.config_file) self.assertEqual(list(settings.get_aliases().keys()), ['alias_active'])
def alias_added(self, alias, mapping): mapping_name = Project.tuple_to_str(mapping) self.msg(u"The following alias has been added to your configuration " "file: %s = %s" % (alias, mapping_name))
def get_projects(self): projects_url = self.get_full_url('project/all.json') response = self._session.get(projects_url).json() projects = response['command']['projects']['project'] activities = response['command']['activities']['activity'] activities_dict = {} for activity in activities: a = Activity(int(activity['id']), activity['name'], activity['rate_eur']) activities_dict[a.id] = a projects_list = [] i = 0 for project in projects: p = Project(int(project['id']), project['name'], project['status'], project['description'], project['budget']) try: p.start_date = datetime.strptime( project['startdate'], '%Y-%m-%d').date() except ValueError: p.start_date = None try: p.end_date = datetime.strptime( project['enddate'], '%Y-%m-%d').date() except ValueError: p.end_date = None i += 1 activities = project['activities']['activity'] # Sometimes the activity list just contains an @attribute # element, in this case we skip it if isinstance(activities, dict): continue # If there's only 1 activity, this won't be a list but a simple # element if not isinstance(activities, list): activities = [activities] for activity in activities: try: if int(activity) in activities_dict: p.add_activity(activities_dict[int(activity)]) except ValueError: logger.warn( "Cannot import activity %s for project %s because " "activity id is not an int" % (activity, p.id) ) if 'activity_aliases' in project and project['activity_aliases']: for alias, mapping in project['activity_aliases'].items(): p.aliases[alias] = int(mapping) projects_list.append(p) return projects_list