def remove(request, group_id, set_id): item_is_staff('group', request.user, group_id) tg_set = get_object_or_404(TaskGroupSet, task_group_id=group_id, pk=set_id) if tg_set.task_set.exists(): messages.error(request, 'Task set can be deleted only if empty') else: messages.success(request, 'Task set deleted successfully') tg_set.delete() return redirect('staff_group_tasks', group_id=group_id)
def publish_all(request, group_id, set_id): group, role = item_is_staff('group', request.user, group_id) rd = redirect('staff_group_tasks', group_id=group_id) if group.archived: messages.warning(request, 'Unable to publish tasks in archived group') return rd tg = get_object_or_404(TaskGroupSet, task_group_id=group_id, pk=set_id) tasks = tg.task_set.filter(published=False) if not tasks: messages.warning(request, 'There are no unpublished tasks in the set') return rd if request.POST: for task in tasks: task.published = True task.save() return rd context = { 'title': 'Bulk publish', 'bulk': True, 'group': group, 'tasks': tasks, 'set_name': tg.name } return render(request, 'webapp/admin/task/publish.html', context)
def create(request, group_id): group, role = item_is_staff('group', request.user, group_id) rd = redirect('staff_group_tasks', group_id=group_id) if group.archived: messages.warning(request, 'Set cannot be created in archived group') return rd if request.POST: instance = TaskGroupSet(task_group_id=group_id) form = TaskGroupSetForm(request.POST, instance=instance) if form.is_valid: form.save() messages.success(request, 'Task set is created successfully') return rd else: messages.error(request, 'Form was filled incorrectly') context = { 'title': 'Create task set in {}'.format(group.name), 'group': group, 'form': TaskGroupSetForm() } return render(request, 'webapp/admin/group/taskset/actions.html', context)
def edit(request, group_id, set_id): group, role = item_is_staff('group', request.user, group_id) rd = redirect('staff_group_tasks', group_id=group_id) if group.archived: messages.warning(request, 'Set in the archived group cannot be edited') return rd task_set = get_object_or_404(TaskGroupSet, task_group_id=group_id, pk=set_id) form = TaskGroupSetForm(instance=task_set) if request.POST: form = TaskGroupSetForm(request.POST, instance=task_set) if form.is_valid: form.save() messages.success(request, 'Changes saved') return rd else: messages.error(request, 'Form was filled incorrectly') context = { 'group': group, 'set': task_set, 'title': 'Edit task set {}'.format(task_set.name), 'form': form } return render(request, 'webapp/admin/group/taskset/actions.html', context) pass
def create(request, group_id, set_id): group, role = item_is_staff('group', request.user, group_id) rd = redirect('staff_group_tasks', group_id=group_id) if group.archived: messages.warning(request, 'Task cannot be added to archived group.') return rd try: task_set = TaskGroupSet.objects.get(pk=set_id) except TaskGroupSet.DoesNotExist: messages.warning(request, 'Task cannot be added to nonexistent task set.') return rd if request.method == 'POST': instance = Task(owner=request.user, task_group=group, tg_set=task_set) form = TaskForm(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() return rd messages.error(request, 'Form was filled incorrectly') else: form = TaskForm() context = { 'form': form, 'group': group, 'set': task_set, 'title': 'Create task' } return render(request, 'webapp/admin/task/actions.html', context)
def list_user(request, task_id, user_id): task, role = item_is_staff('task', request.user, task_id) user = get_object_or_404(User, pk=user_id) evaluations = SubmissionEvaluation.objects.select_related( 'submission').filter( submission__user_id=user_id, submission__task_id=task_id).order_by('submission__submitted') context = { 'title': 'Submissions of {} {} on {}'.format(short_name(user.first_name), user.last_name, task.name), 'task': task, 'group': task.task_group, 'user': user, 'evaluations': evaluations } return render(request, 'webapp/admin/submission/list_user_task.html', context)
def publish(request, task_id): task, role = item_is_staff('task', request.user, task_id) if task.published: messages.warning(request, 'This task is already published') elif task.task_group.archived: messages.warning( request, 'The group, to which this task belongs is archived. Task cannot be published' ) elif request.method == 'POST': task.published = True task.save() messages.success(request, 'Task was published successfully.') else: return render( request, 'webapp/admin/task/publish.html', { 'task': task, 'group': task.task_group, 'title': 'Publish ' + task.name }) return redirect('staff_task_details', task_id=task.id)
def copy(request, group_id): group, role = item_is_staff('group', request.user, group_id) if request.POST: form = CopyTaskGroup(request.POST) if form.is_valid(): new_group = TaskGroup.objects.create( name=form.cleaned_data['name'], description=form.cleaned_data['description']) new_group.save() # creating access to the new group try: provider_id = request.user.casusermeta.ext_id except CASUserMeta.DoesNotExist: provider_id = None access = TaskGroupAccess(user=request.user, role='owner', task_group=new_group, provider_id=provider_id) access.save() for tg_set in TaskGroupSet.objects.filter(task_group=group): tasks = Task.objects.filter(task_group=group, tg_set=tg_set) tg_set.pk = None # reset pk so that insert will be performed instead of update tg_set.task_group = new_group tg_set.save() for task in tasks: task.pk = None # reset pk task.deadline = None task.published = False task.archived = False task.task_group = new_group task.tg_set = tg_set # new TaskGroupSet task.save() messages.success(request, 'Group was copied successfully') return redirect('staff_group_tasks', group_id=new_group.pk) else: messages.error(request, 'Please fill in the new group name') return redirect('staff_group_copy', group_id=group_id) context = { 'group': group, 'tasks': Task.objects.filter(task_group=group), 'title': group.name + ' copy', 'form': CopyTaskGroup(initial={ 'name': group.name, 'description': group.description }) } return render(request, 'webapp/admin/group/copy.html', context)
def deadlines(request, group_id): group, role = item_is_staff('group', request.user, group_id) if group.archived: messages.warning( request, 'Group is archived, setting bulk deadlines is not possible.') return redirect('staff_group_tasks', group_id=group_id) formset = formset_factory(TaskGroupBulkDeadlines, extra=0) if request.POST: forms = formset(request.POST) if forms.is_valid(): filled = False for data in forms.cleaned_data: if data['deadline']: filled = True for task in Task.objects.filter(tg_set=data['set_id']): task.deadline = data['deadline'] task.save() if filled: messages.success(request, 'Changes applied') return redirect('staff_group_tasks', group_id=group_id) else: messages.warning(request, 'No changes were made') return redirect('staff_group_deadlines', group_id=group_id) else: initial_data = [] for item in [ st for st in TaskGroupSet.objects.filter(task_group=group) if st.task_set.exists() ]: initial_data.append({ 'set_id': item.id, 'set_name': item.name[:20] + (item.name[20:] and '...') }) forms = formset(initial=initial_data) context = { 'group': group, 'forms': forms, 'title': 'Set bulk deadlines for {}'.format(group.name) } return render(request, 'webapp/admin/group/deadlines.html', context)
def item_archive(request, item_name, item_id): item, role = item_is_staff(item_name, request.user, item_id) if request.method == 'POST': item.archived = not item.archived item.save() return redirect('staff_task_details', task_id=item_id) \ if item_name == 'task' else redirect('staff_group_tasks', group_id=item_id) return render(request, 'webapp/admin/item_archive.html', { 'item_name': item_name, 'item': item, 'title': 'Unarchive ' if item.archived else 'Archive ' + item.name })
def perform_action(request, s_uuid, action): try: submission = Submission.objects.get(uuid=s_uuid) task, role = item_is_staff('task', request.user, submission.task_id) except (Submission.DoesNotExist, ValueError): messages.warning(request, 'Unable to find submission with given uuid.') return redirect('staff_dashboard') # pass redirect argument if existent redirect_to = request.GET.get('next') if request.GET.get('next') else \ reverse('staff_submission_report', args=[submission.uuid]) if action not in ['reevaluate', 'validate', 'invalidate']: messages.warning(request, 'Invalid action') return redirect(redirect_to) return submission_operation_create(request.user, action, [s_uuid], task.id, redirect_to, False)
def task_list(request, group_id): group, role = item_is_staff('group', request.user, group_id) context = { 'user_role': role, 'group': group, 'sets': [ dict(id=tg_set.id, name=tg_set.name, description=tg_set.description, tasks=tg_set.task_set.filter(task_group=group), has_unpublished=tg_set.task_set.filter( task_group=group, published=False).exists()) for tg_set in TaskGroupSet.objects.filter(task_group=group) ], 'title': group.name + ' task list' } return render(request, 'webapp/admin/group/index.html', context)
def item_edit(request, item_name, item_id): item, role = item_is_staff(item_name, request.user, item_id) context = { 'title': 'Edit ' + item.name } if item_name == 'group': form_object = TaskGroupForm context['group'] = item rd = redirect('staff_group_tasks', group_id=item_id) else: form_object = TaskForm context['group'] = item.task_group context['task'] = item rd = redirect('staff_task_details', task_id=item_id) if item.archived or (item.task_group.archived if hasattr(item, 'task_group') else False): messages.warning(request, 'Archived {} cannot be edited'.format(item_name)) return rd if request.method == 'POST': if item_name == 'group': form = form_object(request.POST, instance=item) else: form = form_object(request.POST, request.FILES, edit=1, instance=item) if form.is_valid(): form.save() messages.success(request, 'Changes saved successfully') return rd else: messages.error(request, 'Form was filled incorrectly') else: form = form_object(instance=item, edit=1) context['form'] = form return render(request, 'webapp/admin/{}/actions.html'.format(item_name), context)
def list_all(request, task_id): task, role = item_is_staff('task', request.user, task_id) evaluations = SubmissionEvaluation.objects.select_related( 'submission', 'submission__user').filter(submission__task_id=task_id).annotate( best=RawSQL( '''dense_rank() over(partition by webapp_submission.user_id order by webapp_submissionevaluation.score desc, webapp_submission.submitted desc)''', []), latest=RawSQL( '''dense_rank() over(partition by webapp_submission.user_id order by webapp_submission.submitted desc)''', [])).order_by('-submission__submitted') context = { 'title': 'Submissions to {}'.format(task.name), 'task': task, 'group': task.task_group, 'evaluations': evaluations } if request.POST: s_ids = [] action = request.POST.get('action') if action and action in ['reevaluate', 'invalidate', 'validate']: objects = build_http_array(request.POST, 'submission') for index in objects: s_ids.append(objects[index]['uuid']) redirect_to = reverse('staff_task_submissions_all', args=[task_id]) return submission_operation_create(request.user, action, s_ids, task_id, redirect_to) else: messages.warning( request, 'Action parameter was not received or is invalid') return render(request, 'webapp/admin/submission/list_all.html', context)
def user_reports(request, group_id, user_id): group, role = item_is_staff('group', request.user, group_id) try: user = User.objects.get(pk=user_id) except User.DoesNotExist: messages.warning(request, 'User with given ID does not exist') return redirect('staff_group_tasks', group_id=group_id) evaluations = SubmissionEvaluation.objects.filter( submission__user=user, submission__task__task_group_id=group_id).select_related( 'submission', ).annotate( task_name=F('submission__task__name'), set_name=F('submission__task__tg_set__name'), best=RawSQL( '''dense_rank() over(partition by webapp_submission.task_id order by webapp_submissionevaluation.score desc, webapp_submission.submitted desc)''', []), latest=RawSQL( '''dense_rank() over(partition by webapp_submission.task_id order by webapp_submission.submitted desc)''', [])).order_by('-submission__submitted') context = { 'title': 'Submissions from {} to group {}'.format(user.last_name, group.name), 'group': group, 'user': user, 'evaluations': evaluations } return render(request, 'webapp/admin/submission/list_user_group.html', context)
def details(request, task_id): task, role = item_is_staff('task', request.user, task_id) ids = SubmissionEvaluation.objects.annotate(rank=RawSQL( '''dense_rank() over(partition by webapp_submission.user_id order by {}webapp_submission.submitted desc)'''.format( 'webapp_submissionevaluation.score desc, ' if task.result_type == 'best' else ''), [])).values( 'id', 'rank', 'status', 'received', 'worker_took_time', 'submission__submitted').filter(submission__task_id=task_id, is_invalid=False) results = SubmissionEvaluation.objects.select_related( 'submission', 'submission__user').filter(pk__in=(pk['id'] for pk in ids if pk['rank'] == 1)).order_by( '-score', 'submission__submitted') # separating staff and user submissions staff_members = task.task_group.taskgroupaccess_set.filter(~Q( role='user')).values_list('user_id', flat=True) d_results = [] s_results = [] for r in results: if r.submission.user_id in staff_members: d_results.append(r) else: s_results.append(r) # gathering stats stats = { 'avg_check_time': 'n/a', 'avg_wait_time': 'n/a', 'avg_score': '0.0', 'sbm_count': 0 } total_check = 0 total_wait = 0 index = 0 for i in ids: try: if i['status'] == 'ok' and i['worker_took_time'] is not None: worker_took = i[ 'worker_took_time'] / 1000 # ms to seconds without loosing precision total_check += worker_took # wait time is calculated by subtracting submit unix time and worker_took_time assuming remaining # time gap to be the time spent in queue total_wait += (i['received'] - i['submission__submitted'] ).total_seconds() - worker_took index += 1 except KeyError: pass if index > 0: stats['avg_check_time'] = format_int(round(total_check / index)) stats['avg_wait_time'] = format_int(round(total_wait / index)) if s_results: stats.update( SubmissionEvaluation.objects.filter( pk__in=(pk.id for pk in s_results)).aggregate( avg_score=Avg(F('score')), sbm_count=Count(F('score')))) context = { 'title': 'Task: ' + task.name, 'task': task, 'group': task.task_group, 'pack_url': get_package_link(task), 'are_results': len(ids) > 0, 's_results': s_results, 'd_results': d_results, 'stats': stats, } return render(request, 'webapp/admin/task/index.html', context)
def operation_handle(request, task_id, sop_uuid): task, role = item_is_staff('task', request.user, task_id) # set redirect targets redirect_to = request.GET.get('next') self_rd = redirect('staff_task_operation_handle', sop_uuid=sop_uuid, task_id=task_id) if redirect_to: rd = HttpResponseRedirect(redirect_to) self_rd['Location'] += '?next={}'.format(redirect_to) else: rd = redirect('staff_task_submissions_all', task_id=task_id) # SubmissionOperation's task_id must correspond to the given task_id try: op = SubmissionOperation.objects.get(pk=sop_uuid, task_id=task_id) except (SubmissionOperation.DoesNotExist, ValueError): messages.error(request, 'The operation cannot be found') return rd # here we also select only submissions with evaluations and those which belong to the task try: evaluations = SubmissionEvaluation.objects.filter( submission__pk__in=json.loads(op.submission_list), submission__task_id=task_id).select_related( 'submission', 'submission__user') except ValueError: messages.error(request, 'The operation is invalid') op.delete() return rd if not evaluations: if op.is_bulk: message = 'You have to select at least one submission in order to perform any action.' else: message = 'The operation cannot be performed. (no submission received)' messages.warning(request, message) op.delete() return rd if op.has_started: if op.action == 'reevaluate': extra = json.loads(op.extra) if not len(extra): messages.error( request, 'The operation cannot be performed. (no pending submissions received)' ) op.delete() return rd try: pending_submissions = Submission.objects.select_related( 'user').filter(pk__in=extra) except ValueError: messages.error( request, 'The operation cannot be performed. (no valid pending submissions received)' ) op.delete() return rd context = { 'task': task, 'group': task.task_group, 'role': role, 'submissions': pending_submissions, 'title': 'Re-evaluating submission{}'.format('s' if op.is_bulk else ''), 'tokens': {}, 'old_scores': {}, 'bulk': op.is_bulk } for e in evaluations: context['old_scores'][e.submission_id] = e.score signer = TimestampSigner() for ps in pending_submissions: context['tokens'][ps.uuid] = signer.sign(ps.uuid) return render(request, 'webapp/admin/submission/reevaluation.html', context) elif op.action == 'invalidate' or op.action == 'validate': messages.warning(request, 'This operation has already been invoked.') return rd else: messages.error( request, 'The operation cannot be performed. (invalid action)') op.delete() return rd else: if request.POST: if request.POST.get('cancel-action') == '1': # action cancelled op.delete() return rd # confirmation received: if op.action == 'reevaluate': pending = [] for evaluation in evaluations: old_submission = evaluation.submission files = SubmissionFile.objects.filter( submission=old_submission) new_s = Submission.objects.create( uuid=str(uuid.uuid4()), user=evaluation.submission.user, task=task, reevaluated=True, copy_of=old_submission, invoked_by=request.user, queue_priority="low") pending.append(str(new_s.uuid)) for file in files: SubmissionFile.objects.create(submission=new_s, name=file.name, contents=file.contents) try: upload_submission(new_s) except redis.exceptions.RedisError: new_s.delete() op.delete() return render(request, 'webapp/submit_fail.html', {'task': task}) op.has_started = True op.extra = json.dumps(pending) op.save() return self_rd elif op.action == 'invalidate': form = InvalidateSubmissionForm(request.POST) if form.is_valid(): evaluation_set_validity(evaluations, False, form.cleaned_data['comment'], request.user.id) else: messages.error( request, 'Please fill in the reason of invalidation.') return self_rd elif op.action == 'validate': evaluation_set_validity(evaluations, True) else: messages.error( request, 'The operation cannot be performed. (invalid action)') op.delete() return rd op.has_started = True op.save() return rd else: # ask for a confirmation if op.action == 'invalidate' or op.action == 'validate': evaluations = evaluations.filter( is_invalid=False if op.action == 'invalidate' else True) if not evaluations: messages.warning( request, '{} submission{} already {}'.format( 'Selected' if op.is_bulk else 'This', 's are' if op.is_bulk else ' is', 'invalid' if op.action == 'invalidate' else 'valid')) op.delete() return rd context = { 'title': 'Confirm operation', 'evaluations': evaluations, 'task': task, 'group': task.task_group, 'op': op, 'form': InvalidateSubmissionForm() } return render(request, 'webapp/admin/task/confirm_operation.html', context)