Source code for oioioi.exportszu.utils

import csv
import os
import shutil
import tarfile
import tempfile

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.utils.encoding import force_str

from oioioi.filetracker.client import get_client
from oioioi.filetracker.utils import django_to_filetracker_path
from oioioi.participants.models import Participant
from oioioi.programs.models import ProgramSubmission
from oioioi.programs.utils import get_extension


[docs]class SubmissionData(object):
[docs] submission_id = None
[docs] user_id = None
[docs] username = None
[docs] first_name = None
[docs] last_name = None
[docs] city = None
[docs] school = None
[docs] school_city = None
[docs] problem_short_name = None
[docs] score = None
[docs] solution_language = None
[docs] source_file = None
[docs]class SubmissionsWithUserDataCollector(object): """ Collects submissions with some associated data in specific contest with some filtering. We want the user of collector objects to know nothing (or very little) about the database, controller logic etc. It is responsibility of the collector to provide access to fully prepared data. """ def __init__( self, contest, round=None, problem_instance=None, language=None, only_final=True ): self.contest = contest self.round = round self.problem_instance = problem_instance if language: exts = getattr(settings, 'SUBMITTABLE_EXTENSIONS', {}) if language not in exts: raise InvalidValue("Invalid programming language") self.lang_exts = exts[language] else: self.lang_exts = None self.only_final = only_final self.filetracker = get_client()
[docs] def get_contest_id(self): return self.contest.id
[docs] def collect_list(self): ccontroller = self.contest.controller q_expressions = Q(user__isnull=False) if self.round: q_expressions &= Q(problem_instance__round=self.round) else: q_expressions &= Q(problem_instance__contest=self.contest) if self.problem_instance: q_expressions &= Q(problem_instance=self.problem_instance) if self.lang_exts: q_expr_langs = Q() for ext in self.lang_exts: q_expr_langs |= Q(source_file__contains='.%s@' % ext) q_expressions &= q_expr_langs if self.only_final: q_expressions &= Q(submissionreport__userresultforproblem__isnull=False) submissions_list = [] psubmissions = ProgramSubmission.objects.filter(q_expressions).select_related() for s in psubmissions: data = SubmissionData() data.submission_id = s.id data.user_id = s.user_id data.username = s.user.username data.first_name = s.user.first_name data.last_name = s.user.last_name data.problem_short_name = s.problem_instance.short_name data.score = s.score data.solution_language = get_extension(s.source_file.name) data.source_file = s.source_file # here we try to get some optional data, it just may not be there # and it's ok try: registration = ( Participant.objects.select_related() .get(contest_id=self.contest.id, user=s.user) .registration_model ) try: data.city = registration.city except AttributeError: pass try: data.school = registration.school.name data.school_city = registration.school.city except AttributeError: pass except (Participant.DoesNotExist, ObjectDoesNotExist): pass submissions_list.append(data) return submissions_list
[docs] def get_submission_source(self, out_file_path, source): ft_file = django_to_filetracker_path(source) self.filetracker.get_file(ft_file, out_file_path, add_to_cache=False)
[docs]def build_submissions_archive(out_file, submission_collector): """ Builds submissions archive, in szubrawcy format, in out_file from data provided by submission_collector. Argument out_file should be a file-like object. """ submission_list = submission_collector.collect_list() tmpdir = tempfile.mkdtemp() try: contest_id = submission_collector.get_contest_id() files_dir = os.path.join(tmpdir, contest_id) os.mkdir(files_dir, 0o700) with open(os.path.join(files_dir, 'INDEX'), 'w') as f: index_csv = csv.writer(f) header = [ 'submission_id', 'user_id', 'username', 'first_name', 'last_name', 'city', 'school', 'school_city', 'problem_short_name', 'score', ] index_csv.writerow(header) for s in submission_list: index_entry = [ s.submission_id, s.user_id, s.username, s.first_name, s.last_name, s.city, s.school, s.school_city, s.problem_short_name, s.score, ] def encode(obj): if obj is None: return 'NULL' else: return force_str(obj, errors="ignore") index_csv.writerow([encode(col) for col in index_entry]) for s in submission_list: filename = '%s:%s:%s.%s' % ( s.submission_id, s.username, s.problem_short_name, s.solution_language, ) dest = os.path.join(files_dir, filename) submission_collector.get_submission_source(dest, s.source_file) with tarfile.open(fileobj=out_file, mode='w:gz') as tar: tar.add(files_dir, arcname=contest_id) finally: shutil.rmtree(tmpdir)