diff --git a/Campaign/views.py b/Campaign/views.py index ce7cd863..36c7f927 100644 --- a/Campaign/views.py +++ b/Campaign/views.py @@ -23,6 +23,8 @@ from EvalData.models import PairwiseAssessmentResult from EvalData.models import seconds_to_timedelta from EvalData.models import TASK_DEFINITIONS +from EvalData.models import TaskAgenda +from EvalData.models.direct_assessment_document import DirectAssessmentDocumentTask # pylint: disable=import-error @@ -51,19 +53,27 @@ def campaign_status(request, campaign_name, sort_key=2): _msg = 'Failure to identify campaign {0}'.format(campaign_name) return HttpResponse(_msg, content_type='text/plain') + try: + campaign_opts = campaign.campaignOptions.lower().split(";") + # may raise KeyError + result_type = RESULT_TYPE_BY_CLASS_NAME[campaign.get_campaign_type()] + except KeyError as exc: + LOGGER.debug( + f'Invalid campaign type {campaign.get_campaign_type()} for campaign {campaign.campaignName}' + ) + LOGGER.error(exc) + return HttpResponse( + 'Invalid campaign type for campaign {0}'.format(campaign.campaignName), + content_type='text/plain', + ) + + # special handling for ESA + if "esa" in campaign_opts: + return campaign_status_esa(campaign) + _out = [] for team in campaign.teams.all(): for user in team.members.all(): - try: - campaign_opts = campaign.campaignOptions.lower().split(";") - # may raise KeyError - result_type = RESULT_TYPE_BY_CLASS_NAME[campaign.get_campaign_type()] - except KeyError as exc: - LOGGER.debug( - f'Invalid campaign type {campaign.get_campaign_type()} for campaign {campaign.campaignName}' - ) - LOGGER.error(exc) - continue _data = result_type.objects.filter( createdBy=user, completed=True, task__campaign=campaign.id @@ -118,29 +128,6 @@ def campaign_status(request, campaign_name, sort_key=2): (x[0], x[1], -len(json.loads(x[2])), x[3], x[4], x[5], x[6]) for x in _data ] - elif "esa" in campaign_opts: - is_mqm_or_esa = True - _data = _data.values_list( - 'start_time', - 'end_time', - 'score', - 'item__itemID', - 'item__targetID', - 'item__itemType', - 'item__id', - 'item__documentID', - ) - # compute time override based on document times - import collections - - _time_pairs = collections.defaultdict(list) - for x in _data: - _time_pairs[x[7] + " ||| " + x[4]].append((x[0], x[1])) - _time_pairs = [ - (min([x[0] for x in doc_v]), max([x[1] for x in doc_v])) - for doc, doc_v in _time_pairs.items() - ] - _data = [(x[0], x[1], x[2], x[3], x[4], x[5], x[6]) for x in _data] else: _data = _data.values_list( 'start_time', @@ -245,6 +232,131 @@ def campaign_status(request, campaign_name, sort_key=2): return HttpResponse(u'\n'.join(_txt), content_type='text/plain') +def campaign_status_esa(campaign) -> str: + import collections + out_str = """ + + + \n + """ + out_str += f"
| {x} | " for x in ["Username", "Progress", "First Modified", "Last Modified", "Time (Last-First)", "Time (Real)"] + ) + "|||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {user.username} 💤 | " + out_str += f"0/{total_count} (0%) | " + else: + # No task assigned to this user + out_str += f"{user.username} 💤 | " + out_str += "No task assigned | " + out_str += "" + out_str += " | " + out_str += " | " + out_str += " | " + + # If we have data, show the progress + else: + if not task: + # Fallback to checking the first result's task for the task ID + task = DirectAssessmentDocumentTask.objects.filter(id=_data[0].task_id).first() + if not task: + # Skip this user if we can't find the task + out_str += f" | {user.username} ❌ | " + out_str += "Task not found | " + out_str += "" + out_str += " | " + out_str += " | " + out_str += " | " + out_str += " | {user.username} ✅ | " + else: + out_str += f"{user.username} 🛠️ | " + out_str += f"{len(_data)}/{total_count} ({len(_data) / total_count:.0%}) | " + first_modified = min([x.start_time for x in _data]) + last_modified = max([x.end_time for x in _data]) + + first_modified_str = str(datetime(1970, 1, 1) + seconds_to_timedelta(first_modified)).split('.')[0] + last_modified_str = str(datetime(1970, 1, 1) + seconds_to_timedelta(last_modified)).split('.')[0] + # remove seconds + first_modified_str = ":".join(first_modified_str.split(":")[:-1]) + last_modified_str = ":".join(last_modified_str.split(":")[:-1]) + + out_str += f"{first_modified_str} | " + out_str += f"{last_modified_str} | " + annotation_time_upper = last_modified - first_modified + annotation_time_upper = f'{int(floor(annotation_time_upper / 3600)):0>2d}h {int(floor((annotation_time_upper % 3600) / 60)):0>2d}m' + out_str += f"{annotation_time_upper} | " + + times = collections.defaultdict(list) + for item in _data: + times[(item.item.documentID, item.item.targetID)].append((item.start_time, item.end_time)) + times = [ + (min([x[0] for x in doc_v]), max([x[1] for x in doc_v])) + for doc, doc_v in times.items() + ] + + annotation_time = sum([b-a for a, b in times]) + annotation_time = f'{int(floor(annotation_time / 3600)):0>2d}h {int(floor((annotation_time % 3600) / 60)):0>2d}m' + + out_str += f"{annotation_time} | " + + out_str += "\n" + + out_str += "