def project_information(request): try: data = load_encoded_json(request.body) project_ids = data['project_ids'] return get_project_information(project_ids) except KeyError: raise BadRequest('project_ids is required')
def project_management_information(project_id): project = Project.objects.get(id=project_id) project_information = get_project_information(project.id) project_information['project']['status'] = dict( Project.STATUS_CHOICES).get(project.status, None) project_information['project']['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse( 'admin:orchestra_project_change', args=(project_id,))) for slug, task in project_information['tasks'].items(): task['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse( 'admin:orchestra_task_change', args=(task['id'],))) for assignment in task['assignments']: assignment['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse( 'admin:orchestra_taskassignment_change', args=(assignment['id'],))) for iteration in assignment['iterations']: iteration['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse( 'admin:orchestra_iteration_change', args=(iteration['id'],))) if not iteration['end_datetime']: iteration['end_datetime'] = timezone.now().isoformat() return project_information
def project_management_information(project_id): project = Project.objects.get(id=project_id) project_information = get_project_information([project.id]) project_information[project.id]['project']['status'] = dict( Project.STATUS_CHOICES).get(project.status, None) project_information[project.id]['project']['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_project_change', args=(project_id, ))) for slug, task in project_information[project.id]['tasks'].items(): task['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_task_change', args=(task['id'], ))) for assignment in task['assignments']: assignment['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_taskassignment_change', args=(assignment['id'], ))) for iteration in assignment['iterations']: iteration['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_iteration_change', args=(iteration['id'], ))) if not iteration['end_datetime']: iteration['end_datetime'] = timezone.now().isoformat() return project_information
def test_get_project_information(self): projects = Project.objects.all()[:2] projects_info = get_project_information([p.pk for p in projects]) a_project_info_key = list(projects_info.keys())[0] a_project_info = projects_info[a_project_info_key] self.assertTrue(isinstance(a_project_info['project'], dict)) self.assertTrue(isinstance(a_project_info['tasks'], dict)) self.assertTrue(isinstance(a_project_info['steps'], list))
def project_information(request): try: data = load_encoded_json(request.body) project_id = data['project_id'] return get_project_information(project_id) except KeyError: raise BadRequest('project_id is required') except Project.DoesNotExist: raise BadRequest('No project for given id')
def project_information(request): try: # TODO(marcua): Add checking for json.loads exceptions to all # endpoints. return get_project_information(json.loads(request.body.decode())["project_id"]) except KeyError: raise BadRequest("project_id is required") except Project.DoesNotExist: raise BadRequest("No project for given id")
def project_information(request): try: # TODO(marcua): Add checking for json.loads exceptions to all # endpoints. return get_project_information( json.loads(request.body.decode())['project_id']) except KeyError: raise BadRequest('project_id is required') except Project.DoesNotExist: raise BadRequest('No project for given id')
def work_time_df(projects, human_only=True, complete_tasks_only=True): """ Return projects' task assignment iteration timing information. The returned dataframe's schema is: project_id: the project's ID project_description: the project's human readable description task_id: the task's ID task_step_slug: the task's step slug assignment_level: a 1-indexed assignment counter (1 is entry-level, 2 is first review, etc.) worker: the username of the worker on that assignment iteration: a work iteration for the assignment: - Iteration 0 represents the period from previous submission to reviewer assignment: - If this is the first assignment, 'previous submission' means 'task creation'. - For iteration 0, work time will always be 0 - If this task is auto-assigned, iteration 0's calendar time will be close to 0. - Iterations N > 0 represent the period between a previous worker's input (submit/accept/reject) and the worker's submission. start_datetime: the time the iteration started. end_datetime: the time the iteration ended. calendar_time: the wallclock time it took for the worker to complete that iteration. work_time: the amount of work time the worker reported dedicating to that iteration (0 for iteration 0). Args: projects (django.db.models.query.QuerySet): An iterable of projects to include in the report. Returns: df (pandas.DataFrame): A DataFrame with timing information. """ # TODO(marcua): `get_project_information` per project means we do random # access all over the database. Ideally, we'd have a sequential scan # version of this. time_data = list(itertools.chain.from_iterable( project_time_row_generator( get_project_information(project.id), human_only, complete_tasks_only) for project in projects)) # Ensure that even an empty DataFrame has the correct columns df = DataFrame(time_data, columns=DATAFRAME_COLUMNS) # Pandas treats all non-primitives as strings, so we explicitly cast # datetimes as datetimes instead of strings. df['start_datetime'] = df['start_datetime'].astype('datetime64[ns]') df['end_datetime'] = df['end_datetime'].astype('datetime64[ns]') return df
def work_time_df(projects, human_only=True, complete_tasks_only=True): """ Return projects' task assignment iteration timing information. The returned dataframe's schema is: project_id: the project's ID project_description: the project's human readable description task_id: the task's ID task_step_slug: the task's step slug assignment_level: a 1-indexed assignment counter (1 is entry-level, 2 is first review, etc.) worker: the username of the worker on that assignment iteration: a work iteration for the assignment: - Iteration 0 represents the period from previous submission to reviewer assignment: - If this is the first assignment, 'previous submission' means 'task creation'. - For iteration 0, work time will always be 0 - If this task is auto-assigned, iteration 0's calendar time will be close to 0. - Iterations N > 0 represent the period between a previous worker's input (submit/accept/reject) and the worker's submission. start_datetime: the time the iteration started. end_datetime: the time the iteration ended. calendar_time: the wallclock time it took for the worker to complete that iteration. work_time: the amount of work time the worker reported dedicating to that iteration (0 for iteration 0). Args: projects (django.db.models.query.QuerySet): An iterable of projects to include in the report. Returns: df (pandas.DataFrame): A DataFrame with timing information. """ # TODO(marcua): `get_project_information` per project means we do random # access all over the database. Ideally, we'd have a sequential scan # version of this. time_data = list( itertools.chain.from_iterable( project_time_row_generator(get_project_information(project.id), human_only, complete_tasks_only) for project in projects)) # Ensure that even an empty DataFrame has the correct columns df = DataFrame(time_data, columns=DATAFRAME_COLUMNS) # Pandas treats all non-primitives as strings, so we explicitly cast # datetimes as datetimes instead of strings. df['start_datetime'] = df['start_datetime'].astype('datetime64[ns]') df['end_datetime'] = df['end_datetime'].astype('datetime64[ns]') return df
def work_time_df(projects, human_only=True, complete_tasks_only=True): """ Return projects' task assignment iteration timing information. The returned dataframe's schema is: project_id: the project's ID task_id: the task's ID assignment_level: a 1-indexed assignment counter (1 is entry-level, 2 is first review, etc.) worker: the username of the worker on that assignment iteration: a work iteration for the assignment: - Iteration 0 represents the period from previous submission to reviewer assignment: - If this is the first assignment, 'previous submission' means 'task creation'. - For iteration 0, work time will always be 0 - If this task is auto-assigned, iteration 0's calendar time will be close to 0. - Iterations N > 0 represent the period between a previous worker's input (submit/accept/reject) and the worker's submission. start_datetime: the time the iteration started. calendar_time: the wallclock time it took for the worker to complete that iteration. work_time: the amount of work time the worker reported dedicating to that iteration (0 for iteration 0). Args: projects (django.db.models.query.QuerySet): An iterable of projects to include in the report. Returns: df (pandas.DataFrame): A DataFrame with timing information. """ # TODO(marcua): `get_project_information` per project means we do random # access all over the database. Ideally, we'd have a sequential scan # version of this. time_data = list( itertools.chain.from_iterable( project_time_row_generator(get_project_information(project.id), human_only, complete_tasks_only) for project in projects ) ) df = DataFrame(time_data) return df
def project_management_information(project_id): project = Project.objects.get(id=project_id) df = work_time_df([project], human_only=False, complete_tasks_only=False) project_information = get_project_information(project.id) project_information['project']['status'] = dict( Project.STATUS_CHOICES).get(project.status, None) project_information['project']['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_project_change', args=(project_id, ))) for slug, task in project_information['tasks'].items(): task['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_task_change', args=(task['id'], ))) for assignment in task['assignments']: assignment['admin_url'] = urljoin( settings.ORCHESTRA_URL, urlresolvers.reverse('admin:orchestra_taskassignment_change', args=(assignment['id'], ))) iterations = df[(df.worker == assignment['worker']['username']) & (df.task_id == task['id'])] iterations = iterations[['start_datetime', 'end_datetime']] assignment['iterations'] = [] for idx, info in iterations.T.items(): iteration = info.to_dict() assignment['iterations'].append(iteration) if assignment['status'] == 'Processing': last_iteration_end = assignment['start_datetime'] last_assignment = last_snapshotted_assignment(task['id']) if last_assignment and len(assignment['iterations']) > 1: last_iteration_end = ( last_assignment.snapshots['snapshots'][-1]['datetime']) assignment['iterations'].append({ 'start_datetime': last_iteration_end, 'end_datetime': timezone.now() }) if task['status'] in ('Awaiting Processing', 'Pending Review'): last_assignment_end = task['start_datetime'] last_assignment = last_snapshotted_assignment(task['id']) if last_assignment: last_assignment_end = ( last_assignment.snapshots['snapshots'][-1]['datetime']) task['assignments'].append({ 'iterations': [{ 'start_datetime': last_assignment_end, 'end_datetime': timezone.now() }], 'snapshots': empty_snapshots(), 'start_datetime': last_assignment_end, 'status': 'Processing', 'task': task['id'], 'worker': { 'id': None, 'username': None }, }) return project_information