From 9c9ec9f327163c628e861534f5e7522893291d39 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sun, 25 May 2025 15:13:53 -0400 Subject: [PATCH 1/2] When we shadow, trust the filenames and file sizes, but treat them as import-error Fixes #3005 --- webapp/src/Service/SubmissionService.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/Service/SubmissionService.php b/webapp/src/Service/SubmissionService.php index 04410c3c25..1a2b4cbd8c 100644 --- a/webapp/src/Service/SubmissionService.php +++ b/webapp/src/Service/SubmissionService.php @@ -569,7 +569,7 @@ public function submitSolution( if (!empty($entryPoint) && !preg_match(self::FILENAME_REGEX, $entryPoint)) { $message = sprintf("Entry point '%s' contains illegal characters.", $entryPoint); - if ($forceImportInvalid) { + if ($forceImportInvalid || $source === 'shadowing') { $importError = $message; } else { return null; @@ -610,7 +610,7 @@ public function submitSolution( } if (!preg_match(self::FILENAME_REGEX, $file->getClientOriginalName())) { $message = sprintf("Illegal filename '%s'.", $file->getClientOriginalName()); - if ($forceImportInvalid) { + if ($forceImportInvalid || $source === 'shadowing') { $importError = $message; } else { return null; @@ -647,7 +647,7 @@ public function submitSolution( if ($totalSize > $sourceSize * 1024) { $message = sprintf("Submission file(s) are larger than %d kB.", $sourceSize); - if ($forceImportInvalid) { + if ($forceImportInvalid || $source === 'shadowing') { $importError = $message; } else { return null; From b84d42c9c3294b4a1ba3b7709c86372ac1c37510 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Fri, 4 Jul 2025 11:59:55 +0200 Subject: [PATCH 2/2] Use enum for submission source --- .../Controller/API/SubmissionController.php | 3 ++- webapp/src/Controller/BaseController.php | 6 +++--- .../Controller/Jury/SubmissionController.php | 3 ++- .../Controller/Team/SubmissionController.php | 3 ++- webapp/src/Entity/SubmissionSource.php | 14 ++++++++++++++ .../Service/ExternalContestSourceService.php | 3 ++- webapp/src/Service/ImportProblemService.php | 3 ++- webapp/src/Service/SubmissionService.php | 19 ++++++++++--------- .../Jury/QueueTaskControllerTest.php | 3 ++- .../Integration/QueuetaskIntegrationTest.php | 9 +++++---- 10 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 webapp/src/Entity/SubmissionSource.php diff --git a/webapp/src/Controller/API/SubmissionController.php b/webapp/src/Controller/API/SubmissionController.php index 79cfa38626..8018d821b9 100644 --- a/webapp/src/Controller/API/SubmissionController.php +++ b/webapp/src/Controller/API/SubmissionController.php @@ -9,6 +9,7 @@ use App\Entity\Language; use App\Entity\Submission; use App\Entity\SubmissionFile; +use App\Entity\SubmissionSource; use App\Entity\Team; use App\Entity\User; use App\Service\ConfigurationService; @@ -331,7 +332,7 @@ public function addSubmissionAction( // Now submit the solution. $submission = $this->submissionService->submitSolution( $team, $user, $problem, $problem->getContest(), $language, - $files, 'API', null, null, $entryPoint, $submissionId, $time, $message + $files, SubmissionSource::API, null, null, $entryPoint, $submissionId, $time, $message ); // Clean up temporary if needed. diff --git a/webapp/src/Controller/BaseController.php b/webapp/src/Controller/BaseController.php index 2e1548315f..474d093d76 100644 --- a/webapp/src/Controller/BaseController.php +++ b/webapp/src/Controller/BaseController.php @@ -10,7 +10,6 @@ use App\Entity\ExternalIdFromInternalIdInterface; use App\Entity\Problem; use App\Entity\RankCache; -use App\Entity\ScoreboardType; use App\Entity\ScoreCache; use App\Entity\Team; use App\Entity\TeamCategory; @@ -168,8 +167,9 @@ protected function getDatabaseRelations(array $files): array { $parts = explode('/', $file); $shortClass = str_replace('.php', '', $parts[count($parts) - 1]); $class = sprintf('App\\Entity\\%s', $shortClass); - if (class_exists($class) && !in_array($class, - [RankCache::class, ScoreCache::class, BaseApiEntity::class, ScoreboardType::class])) { + if (class_exists($class) && + !in_array($class, [RankCache::class, ScoreCache::class, BaseApiEntity::class]) && + !enum_exists($class)) { $metadata = $this->em->getClassMetadata($class); $tableRelations = []; diff --git a/webapp/src/Controller/Jury/SubmissionController.php b/webapp/src/Controller/Jury/SubmissionController.php index 0d6c551e12..8afa8582f4 100644 --- a/webapp/src/Controller/Jury/SubmissionController.php +++ b/webapp/src/Controller/Jury/SubmissionController.php @@ -17,6 +17,7 @@ use App\Entity\Problem; use App\Entity\Submission; use App\Entity\SubmissionFile; +use App\Entity\SubmissionSource; use App\Entity\Team; use App\Entity\TeamAffiliation; use App\Entity\TeamCategory; @@ -1014,7 +1015,7 @@ public function editSourceAction(Request $request, Submission $submission, #[Map $submission->getContest(), $language, $filesToSubmit, - 'edit/resubmit', + SubmissionSource::EDIT_RESUBMIT, $this->getUser()->getUserIdentifier(), $submission->getOriginalSubmission() ?? $submission, $entryPoint, diff --git a/webapp/src/Controller/Team/SubmissionController.php b/webapp/src/Controller/Team/SubmissionController.php index 5300b2273f..27e565054f 100644 --- a/webapp/src/Controller/Team/SubmissionController.php +++ b/webapp/src/Controller/Team/SubmissionController.php @@ -7,6 +7,7 @@ use App\Entity\Language; use App\Entity\Problem; use App\Entity\Submission; +use App\Entity\SubmissionSource; use App\Entity\Testcase; use App\Form\Type\SubmitProblemType; use App\Service\ConfigurationService; @@ -84,7 +85,7 @@ public function createAction(Request $request, ?Problem $problem = null): Respon } $entryPoint = $form->get('entry_point')->getData() ?: null; $submission = $this->submissionService->submitSolution( - $team, $this->dj->getUser(), $problem->getProbid(), $contest, $language, $files, 'team page', null, + $team, $this->dj->getUser(), $problem->getProbid(), $contest, $language, $files, SubmissionSource::TEAM_PAGE, null, null, $entryPoint, null, null, $message ); diff --git a/webapp/src/Entity/SubmissionSource.php b/webapp/src/Entity/SubmissionSource.php new file mode 100644 index 0000000000..7e699ace19 --- /dev/null +++ b/webapp/src/Entity/SubmissionSource.php @@ -0,0 +1,14 @@ +submissionService->submitSolution( - $team, $jury_user, $contestProblem, $contest, $languageToUse, $filesToSubmit, 'problem import', null, + $team, $jury_user, $contestProblem, $contest, $languageToUse, $filesToSubmit, SubmissionSource::PROBLEM_IMPORT, null, null, $entry_point, null, null, $submissionMessage ); diff --git a/webapp/src/Service/SubmissionService.php b/webapp/src/Service/SubmissionService.php index 1a2b4cbd8c..7dc699d43e 100644 --- a/webapp/src/Service/SubmissionService.php +++ b/webapp/src/Service/SubmissionService.php @@ -11,6 +11,7 @@ use App\Entity\Problem; use App\Entity\Submission; use App\Entity\SubmissionFile; +use App\Entity\SubmissionSource; use App\Entity\Team; use App\Entity\User; use App\Utils\FreezeData; @@ -438,7 +439,7 @@ public function submitSolution( Contest|int $contest, Language|string $language, array $files, - ?string $source = null, + SubmissionSource $source = SubmissionSource::UNKNOWN, ?string $juryMember = null, Submission|int|null $originalSubmission = null, ?string $entryPoint = null, @@ -569,7 +570,7 @@ public function submitSolution( if (!empty($entryPoint) && !preg_match(self::FILENAME_REGEX, $entryPoint)) { $message = sprintf("Entry point '%s' contains illegal characters.", $entryPoint); - if ($forceImportInvalid || $source === 'shadowing') { + if ($forceImportInvalid || $source === SubmissionSource::SHADOWING) { $importError = $message; } else { return null; @@ -610,7 +611,7 @@ public function submitSolution( } if (!preg_match(self::FILENAME_REGEX, $file->getClientOriginalName())) { $message = sprintf("Illegal filename '%s'.", $file->getClientOriginalName()); - if ($forceImportInvalid || $source === 'shadowing') { + if ($forceImportInvalid || $source === SubmissionSource::SHADOWING) { $importError = $message; } else { return null; @@ -618,7 +619,7 @@ public function submitSolution( } $totalSize += $file->getSize(); - if ($source !== 'shadowing' && $language->getFilterCompilerFiles()) { + if ($source !== SubmissionSource::SHADOWING && $language->getFilterCompilerFiles()) { $matchesExtension = false; foreach ($language->getExtensions() as $extension) { if (str_ends_with($file->getClientOriginalName(), '.' . $extension)) { @@ -632,7 +633,7 @@ public function submitSolution( } } - if ($source !== 'shadowing' && $language->getFilterCompilerFiles() && $extensionMatchCount === 0) { + if ($source !== SubmissionSource::SHADOWING && $language->getFilterCompilerFiles() && $extensionMatchCount === 0) { $message = sprintf( "None of the submitted files match any of the allowed " . "extensions for %s (allowed: %s)", @@ -647,7 +648,7 @@ public function submitSolution( if ($totalSize > $sourceSize * 1024) { $message = sprintf("Submission file(s) are larger than %d kB.", $sourceSize); - if ($forceImportInvalid || $source === 'shadowing') { + if ($forceImportInvalid || $source === SubmissionSource::SHADOWING) { $importError = $message; } else { return null; @@ -660,7 +661,7 @@ public function submitSolution( // SQL transaction time below. // Only do this for problem import submissions, as we do not want this for re-submitted submissions nor // submissions that come through the API, e.g. when doing a replay of an old contest. - if ($this->dj->checkrole('jury') && $source == 'problem import') { + if ($this->dj->checkrole('jury') && $source === SubmissionSource::PROBLEM_IMPORT) { $results = null; foreach ($files as $file) { $fileResult = self::getExpectedResults(file_get_contents($file->getRealPath()), @@ -726,7 +727,7 @@ public function submitSolution( $this->em->flush(); $this->dj->maybeCreateJudgeTasks($judging, - $source === 'problem import' ? JudgeTask::PRIORITY_LOW : JudgeTask::PRIORITY_DEFAULT); + $source === SubmissionSource::PROBLEM_IMPORT ? JudgeTask::PRIORITY_LOW : JudgeTask::PRIORITY_DEFAULT); } $this->em->wrapInTransaction(function () use ($contest, $submission) { @@ -755,7 +756,7 @@ public function submitSolution( $language->getLangid(), $problem->getProblem()->getProbid())); $this->dj->auditlog('submission', $submission->getSubmitid(), 'added', - 'via ' . ($source ?? 'unknown'), null, $contest->getCid()); + 'via ' . $source->value, null, $contest->getCid()); if (Utils::difftime((float)$contest->getEndtime(), $submitTime) <= 0) { $this->logger->info( diff --git a/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php b/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php index 0cc32fd6cf..8ce8c25611 100644 --- a/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php +++ b/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php @@ -10,6 +10,7 @@ use App\Entity\Problem; use App\Entity\QueueTask; use App\Entity\Submission; +use App\Entity\SubmissionSource; use App\Entity\Team; use App\Service\ConfigurationService; use App\Service\DOMJudgeService; @@ -196,7 +197,7 @@ protected function addSubmission(string $team, string $problem): Submission return $this->submissionService->submitSolution( $team, null, $problem, $contest, 'c', [new UploadedFile(__FILE__, "foo.c", null, null, true)], - null, null, null, null, null, null, $msg + SubmissionSource::UNKNOWN, null, null, null, null, null, $msg ); } diff --git a/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php b/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php index 63c4d13df4..e39e47e3e0 100644 --- a/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php +++ b/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php @@ -7,6 +7,7 @@ use App\Entity\JudgeTask; use App\Entity\Problem; use App\Entity\QueueTask; +use App\Entity\SubmissionSource; use App\Entity\Team; use App\Entity\TeamCategory; use App\Entity\Testcase; @@ -157,7 +158,7 @@ protected function setUp(): void self::getContainer()->get('security.untracked_token_storage')->setToken($token); } - private function submit(?float $time, ?Team $team = null, ?Problem $problem = null, string $source = 'team page'): QueueTask + private function submit(?float $time, ?Team $team = null, ?Problem $problem = null, SubmissionSource $source = SubmissionSource::TEAM_PAGE): QueueTask { $contest = $this->em->getRepository(Contest::class)->find($this->contest->getCid()); $team ??= $this->teams[0]; @@ -323,15 +324,15 @@ public function testPriorities(): void { $time = Utils::now(); - $normal = $this->submit($time, $this->teams[0], null, 'team page'); + $normal = $this->submit($time, $this->teams[0], null, SubmissionSource::TEAM_PAGE); self::assertEquals((int)$time, $normal->getTeamPriority()); self::assertEquals(JudgeTask::PRIORITY_DEFAULT, $normal->getPriority()); - $api = $this->submit($time, $this->teams[1], null, 'api'); + $api = $this->submit($time, $this->teams[1], null, SubmissionSource::API); self::assertEquals((int)$time, $api->getTeamPriority()); self::assertEquals(JudgeTask::PRIORITY_DEFAULT, $api->getPriority()); - $problem_import = $this->submit($time, $this->teams[2], null, 'problem import'); + $problem_import = $this->submit($time, $this->teams[2], null, SubmissionSource::PROBLEM_IMPORT); self::assertEquals((int)$time, $problem_import->getTeamPriority()); self::assertEquals(JudgeTask::PRIORITY_LOW, $problem_import->getPriority()); }