def __init__(self, *args, **kwargs): self.competition = kwargs.pop('competition') self.evaluator = get_evaluator(self.competition.evaluator_version) self.fixed_score = self.competition.fixed_task_score user = kwargs.pop('user') super(CompetitionTaskForm, self).__init__(*args, **kwargs) self.t_comment_extra_class = "ctask-comment" if self.instance.pk: self.fields['text'].initial = self.instance.task.content.text self.fields['comment'].initial = self.instance.comment.text self.t_comment_extra_class += \ " " + ctask_comment_class(self.instance, user) descriptor = self.initial.get('descriptor') if descriptor: variables = safe_parse_descriptor(self.evaluator, descriptor) self.fields['descriptor'].help_text = get_solution_help_text( variables, error_message=_("Invalid!"), show_types=True) self.fields['descriptor'].label = mark_safe( xss.escape(_("Solution")) + \ ' <a href="' + comp_url(self.competition, 'rules') + '" target="_blank"><i class="icon-question-sign" title="' + xss.escape(_("Help")) + '"></i></a>') if self.fixed_score: del self.fields['score'] self.fields['text'].widget.attrs.update( {'class': 'comp-mathcontent-text', 'rows': 5}) self.fields['comment'].widget.attrs.update( {'class': 'comp-mathcontent-text ctask-comment', 'rows': 3})
def rules(request, competition, data): evaluator = get_evaluator(competition.evaluator_version) types = evaluator.get_variable_types() # Class object is a callable, so wrap it with another function. If the # lambda was simply written as "lambda: x", all the values would have the # same x. data['variable_types'] = [(lambda y=x: y) for x in types] data['help_authors_general'] = evaluator.help_authors_general() return data
def refresh_submissions_cache_is_correct(submissions=None, ctasks=None, competitions=None): """Returns the number of solutions updated.""" if not submissions and not ctasks and not competitions: raise ValueError # TODO: simplify this if competitions: competitions = list(competitions) id_to_comp = {x.id: x for x in competitions} if ctasks is None: ctasks = CompetitionTask.objects \ .filter(competition_id__in=id_to_comp.keys()) for ctask in ctasks: ctask.competition = id_to_comp[ctask.competition_id] # TODO: select only given ctasks if submissions is None: submissions = Submission.objects \ .filter(ctask__competition_id__in=id_to_comp.keys()) elif ctasks is None: # TODO: get submissions if not provided. ctask_ids = set(submission.ctask_id for submission in submissions) ctasks = CompetitionTask.objects.filter(id__in=ctask_ids) \ .select_related('competition__evaluator_version') ctasks = list(ctasks) ctasks_dict = {ctask.id: ctask for ctask in ctasks} updated = 0 for submission in submissions: ctask = ctasks_dict[submission.ctask_id] evaluator = get_evaluator(ctask.competition.evaluator_version) old = submission.cache_is_correct try: new = evaluator.check_result(ctask.descriptor, submission.result) except InvalidSolution, InvalidDescriptor: new = False if old != new: submission.cache_is_correct = new submission.save() updated += 1
def task_detail(request, competition, data, ctask_id): is_admin = data['is_admin'] extra = ['task__author'] if is_admin else [] ctask = get_object_or_404( CompetitionTask.objects.select_related('chain', 'task', 'task__content', *extra), competition=competition, id=ctask_id) ctask_id = int(ctask_id) team = data['team'] if not is_admin: if (not team and not data['has_finished']) or not data['has_started'] \ or ctask.chain.unlock_minutes > data['minutes_passed']: raise Http404 if ctask.score > 1: ctask.t_score_text = ungettext( "This task is worth %d point.", "This task is worth %d points.", ctask.score) % ctask.score evaluator = get_evaluator(competition.evaluator_version) variables = safe_parse_descriptor(evaluator, ctask.descriptor) if team: ctasks, chain_submissions = preprocess_chain( competition, ctask.chain, team, preloaded_ctask=ctask) submissions = [x for x in chain_submissions if x.ctask_id == ctask_id] submissions.sort(key=lambda x: x.date) if data['has_finished']: ctask.t_is_locked = False if ctask.t_is_locked and not is_admin: raise Http404 if request.method == 'POST' and (not data['has_finished'] or is_admin): solution_form = CompetitionSolutionForm(request.POST, descriptor=ctask.descriptor, evaluator=evaluator) submission = None delete = False if is_admin and 'delete-submission' in request.POST: try: submission = Submission.objects.get( id=request.POST['delete-submission']) chain_submissions = \ [x for x in chain_submissions if x != submission] submissions = [x for x in submissions if x != submission] submission.delete() delete = True except Submission.DoesNotExist: pass elif solution_form.is_valid(): # TODO: Ignore submission if already correctly solved. if len(submissions) < ctask.max_submissions: result = solution_form.cleaned_data['result'] is_correct = evaluator.check_result( ctask.descriptor, result) submission = Submission(ctask=ctask, team=team, result=result, cache_is_correct=is_correct) submission.save() chain_submissions.append(submission) submissions.append(submission) if delete or submission: if is_admin and team.is_admin_private(): update_ctask_cache_admin_solved_count( competition, ctask, ctask.chain) update_score_on_ctask_action(competition, team, ctask.chain, ctask, submission, delete, chain_ctask_ids=[x.id for x in ctasks], chain_submissions=chain_submissions) # Prevent form resubmission. return (ctask.get_absolute_url(), ) else: solution_form = CompetitionSolutionForm( descriptor=ctask.descriptor, evaluator=evaluator) data['is_solved'] = any(x.cache_is_correct for x in submissions) data['solution_form'] = solution_form data['submissions'] = submissions data['submissions_left'] = ctask.max_submissions - len(submissions) if is_admin: data['all_ctask_submissions'] = list(Submission.objects \ .filter(ctask_id=ctask_id) \ .select_related('team') \ .order_by('id')) for submission in data['all_ctask_submissions']: submission.team.competition = competition data['help_text'] = get_solution_help_text(variables) data['chain'] = ctask.chain data['ctask'] = ctask if competition.show_solutions and data['has_finished'] \ and not data.get('is_solved', False): data['sample_solution'] = get_sample_solution(variables) return data
def chain_new(request, competition, data, chain_id=None): if chain_id: chain = get_object_or_404( Chain, id=chain_id, competition_id=competition.id) edit = True else: chain = None edit = False # CompetitionTaskFormSet = modelformset_factory(CompetitionTask, # formset=BaseCompetitionTaskFormSet, # fields=('descriptor', 'score'), extra=3) evaluator = get_evaluator(competition.evaluator_version) class CompetitionTaskFormLambda(CompetitionTaskForm): def __init__(self, *args, **kwargs): super(CompetitionTaskFormLambda, self).__init__(evaluator=evaluator, fixed_score=competition.fixed_task_score, user=request.user, *args, **kwargs) # TODO: Set min_num and max_num after migrating to Django 1.7. CompetitionTaskFormSet = modelformset_factory(CompetitionTask, form=CompetitionTaskFormLambda, formset=BaseCompetitionTaskFormSet, extra=5, can_order=True, can_delete=True) POST = request.POST if request.method == 'POST' else None chain_form = ChainForm(data=POST, instance=chain) queryset = CompetitionTask.objects.filter(chain_id=chain_id) \ .select_related('task__content', 'comment') \ .order_by('chain_position', 'id') was_order_fixed = fix_ctask_order(competition, chain, list(queryset)) formset = CompetitionTaskFormSet(data=POST, queryset=queryset) if request.method == 'POST': if chain_form.is_valid() and formset.is_valid(): chain = chain_form.save(commit=False) if not edit: chain.competition = competition chain.save() # Save to get an ID. instances = formset.save(commit=False) for form in formset.ordered_forms: _index = form.cleaned_data['ORDER'] if _index: form.instance._index = _index for index, instance in enumerate(instances): instance.competition = competition instance.chain = chain instance.chain_position = getattr(instance, '_index', index) instance.max_submissions = competition.default_max_submissions _create_or_update_task(instance, request.user, competition, chain, index, instance._text, instance._comment) instance.save() chain_ctasks = CompetitionTask.objects.filter(chain=chain) \ .select_related('comment').only('id', 'comment') update_chain_comments_cache(chain, chain_ctasks) chain.save() # Problems with existing formset... ahh, just refresh return (chain.get_absolute_url(), ) data.update({ 'chain_form': chain_form, 'formset': formset, 'was_order_fixed': was_order_fixed, }) return data