diff --git a/judge/management/commands/export_contest_submissions_details.py b/judge/management/commands/export_contest_submissions_details.py index 2d00b65b7..a98e4c683 100644 --- a/judge/management/commands/export_contest_submissions_details.py +++ b/judge/management/commands/export_contest_submissions_details.py @@ -1,10 +1,27 @@ import csv +import re from django.core.management.base import BaseCommand, CommandError -from judge.models import Contest, Submission, SubmissionTestCase +from judge.models import Contest, ContestSubmission, SubmissionTestCase from judge.utils.raw_sql import use_straight_join -from judge.views.submission import submission_related + +# https://stackoverflow.com/a/14693789/16224359 +# Error messages may sometimes be formatted with +# ANSI sequences representing text colors and text weight, +# which may display dirty text in raw text files. +# The following regex is to filter such sequences. +ansi_escape = re.compile(r""" + \x1B # ESC + (?: # 7-bit C1 Fe (except CSI) + [@-Z\\-_] + | # or [ for CSI, followed by a control sequence + \[ + [0-?]* # Parameter bytes + [ -/]* # Intermediate bytes + [@-~] # Final byte + ) +""", re.VERBOSE) class Command(BaseCommand): @@ -21,10 +38,11 @@ def handle(self, *args, **options): if contest is None: raise CommandError('contest not found') - queryset = Submission.objects.all() + queryset = ContestSubmission.objects.all() use_straight_join(queryset) - queryset = submission_related(queryset.order_by('-id')) - queryset = queryset.filter(contest_object=contest) + queryset = queryset.filter(submission__contest_object=contest, + participation__virtual=0) \ + .order_by('-id') self.export_queryset_to_output(queryset, options['output']) @@ -32,10 +50,26 @@ def export_queryset_to_output(self, queryset, output_file): fout = open(output_file, 'w', newline='') writer = csv.DictWriter(fout, fieldnames=['username', 'problem', 'submission', 'testcase', - 'points', 'time', 'memory', 'feedback']) + 'result', 'points', 'time', 'memory', 'feedback']) writer.writeheader() - for submission in queryset: + for contest_submission in queryset: + submission = contest_submission.submission + + # Submission row + escaped_error = ansi_escape.sub('', submission.error) + + writer.writerow({ + 'username': submission.user.username, + 'problem': submission.problem.code, + 'submission': submission.id, + 'result': submission.result, + 'points': submission.case_points, + 'time': submission.time, + 'memory': submission.memory, + 'feedback': escaped_error, + }) + testcases = SubmissionTestCase.objects.filter(submission=submission) for testcase in testcases: @@ -43,11 +77,13 @@ def export_queryset_to_output(self, queryset, output_file): if submission.batch: case_id += f'/batch{testcase.batch}' + # Testcase rows writer.writerow({ 'username': submission.user.username, 'problem': submission.problem.code, 'submission': submission.id, 'testcase': case_id, + 'result': testcase.status, 'points': testcase.points, 'time': testcase.time, 'memory': testcase.memory,