Source code for oioioi.oireports.views

import itertools
from operator import attrgetter  # pylint: disable=E0611

import six
from django.contrib.auth.models import User
from django.core.exceptions import SuspiciousOperation
from django.core.files.base import ContentFile
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from oioioi.base.permissions import enforce_condition
from oioioi.base.utils.pdf import generate_pdf
from oioioi.base.utils.user_selection import get_user_hints_view
from oioioi.contests.menu import contest_admin_menu_registry
from oioioi.contests.models import Round, Submission, UserResultForProblem
from oioioi.contests.utils import contest_exists, has_any_rounds, is_contest_admin
from oioioi.filetracker.utils import stream_file
from oioioi.oireports.forms import CONTEST_REPORT_KEY, OIReportForm
from oioioi.participants.models import Region
from oioioi.programs.models import CompilationReport, GroupReport, TestReport

# FIXME conditions for views expressing oi dependence?


[docs]def _users_in_contest(request, region=None): queryset = User.objects.filter( participant__contest=request.contest, participant__status='ACTIVE' ) if region is not None: queryset = queryset.filter( participant__participants_onsiteregistration__region_id=region ) return queryset
@contest_admin_menu_registry.register_decorator( _("Printing reports"), lambda request: reverse('oireports', kwargs={'contest_id': request.contest.id}), order=440, ) @enforce_condition(contest_exists & is_contest_admin) @enforce_condition(has_any_rounds, 'oireports/no-reports.html')
[docs]def oireports_view(request): if request.method == 'POST': form = OIReportForm(request, request.POST) if form.is_valid(): form_type = form.cleaned_data['form_type'] if form_type == 'pdf_report': return generate_pdfreport(request, form) elif form_type == 'xml_report': return generate_xmlreport(request, form) else: raise SuspiciousOperation else: form = OIReportForm(request) return TemplateResponse( request, 'oireports/report-options.html', {'form': form, 'CONTEST_REPORT_KEY': CONTEST_REPORT_KEY}, )
[docs]def _render_report( request, template_name, title, users, problem_instances, test_groups ): rows = _serialize_reports(users, problem_instances, test_groups) return render_to_string( template_name, request=request, context={ 'rows': rows, 'title': title, }, )
[docs]def _serialize_report(user, problem_instances, test_groups): """Generates a dictionary representing a single report. :param request: Django request :type user: :cls:`django.contrib.auth.User` :param user: user to generate the report for :type problem_instances: list of :cls:`oioioi.contests.ProblemInstance` :param problem_instances: problem instances to include in the report :type test_groups: dict(:cls:`oioioi.contests.ProblemInstance` -> list of str) :param test_groups: dictionary mapping problem instances into lists of names of test groups to include """ resultsets = [] total_score = None results = UserResultForProblem.objects.filter( user=user, problem_instance__in=list(problem_instances), submission_report__isnull=False, ) for r in results: problem_instance = r.problem_instance submission_report = r.submission_report submission = submission_report.submission source_file = submission.programsubmission.source_file groups = list(test_groups[problem_instance]) try: compilation_report = CompilationReport.objects.get( submission_report=submission_report ) except CompilationReport.DoesNotExist: compilation_report = None try: test_reports = ( TestReport.objects.filter(submission_report__submission=submission) .filter(submission_report__status='ACTIVE') .filter(submission_report__kind__in=['INITIAL', 'NORMAL']) .filter(test_group__in=groups) .order_by('test__kind', 'test__order', 'test_name') ) except TestReport.DoesNotExist: test_reports = [] group_reports = ( GroupReport.objects.filter(submission_report__submission=submission) .filter(submission_report__status='ACTIVE') .filter(submission_report__kind__in=['INITIAL', 'NORMAL']) .filter(group__in=groups) ) group_reports = dict((g.group, g) for g in group_reports) groups = [] for group_name, tests in itertools.groupby( test_reports, attrgetter('test_group') ): groups.append({'tests': list(tests), 'report': group_reports[group_name]}) problem_score = None max_problem_score = None for group in groups: group_score = group['report'].score group_max_score = group['report'].max_score if problem_score is None: problem_score = group_score elif group_score is not None: problem_score += group_score if max_problem_score is None: max_problem_score = group_max_score elif group_max_score is not None: max_problem_score += group_max_score resultsets.append( dict( result=r, score=problem_score, max_score=max_problem_score, compilation_report=compilation_report, groups=groups, code=six.ensure_text(source_file.read(), errors="replace"), codefile=source_file.file.name, ) ) if total_score is None: total_score = problem_score elif problem_score is not None: total_score += problem_score return { 'user': user, 'resultsets': resultsets, 'sum': total_score, }
[docs]def _serialize_reports(users, problem_instances, test_groups): """Runs :meth:`serialize_report` for a number of users. Returns a list of objects produced by serialize_report, sorted by user's last name and first name. """ data = [] for user in users.order_by('last_name', 'first_name', 'username'): user_data = _serialize_report(user, problem_instances, test_groups) if user_data['resultsets']: data.append(user_data) return data
[docs]def _report_text(request, template_file, report_form): round_key = report_form.cleaned_data['report_round'] if round_key == CONTEST_REPORT_KEY: round = None else: round = Round.objects.get(contest=request.contest, id=round_key) title = request.contest.name if round: title += ' -- ' + round.name # Region object region_key = report_form.cleaned_data['report_region'] if region_key == CONTEST_REPORT_KEY: region = None else: region = Region.objects.get(short_name=region_key, contest=request.contest) if report_form.cleaned_data['is_single_report']: users = User.objects.filter( username=report_form.cleaned_data['single_report_user'] ) else: users = _users_in_contest(request, region) # Generate report testgroups = report_form.get_testgroups(request) return _render_report( request, template_file, title, users, list(testgroups.keys()), testgroups )
[docs]def generate_pdfreport(request, report_form): report = _report_text(request, 'oireports/pdfreport.tex', report_form) filename = '%s-%s-%s.pdf' % ( request.contest.id, report_form.cleaned_data['report_round'], report_form.cleaned_data['report_region'], ) return generate_pdf(report, filename)
[docs]def generate_xmlreport(request, report_form): report = _report_text(request, 'oireports/xmlreport.xml', report_form) filename = '%s-%s-%s.xml' % ( request.contest.id, report_form.cleaned_data['report_round'], report_form.cleaned_data['report_region'], ) return stream_file(ContentFile(report.encode('utf-8')), filename)
@enforce_condition(contest_exists & is_contest_admin)
[docs]def get_report_users_view(request): queryset = Submission.objects.filter(problem_instance__contest=request.contest) return get_user_hints_view(request, 'substr', queryset, 'user')