Beispiel #1
0
    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})
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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