From 62985ba27a876949149960795d0027a1a055e7e8 Mon Sep 17 00:00:00 2001 From: as6325400 Date: Sun, 22 Sep 2024 02:43:21 +0800 Subject: [PATCH 01/10] add Paste code to submit feature setting paste_code file entry_point add newline and remove comment update paste_code container css site optimize submit logic use cookie to record user submit mode Update webapp/templates/team/submit_modal.html.twig Co-authored-by: MCJ Vasseur <14887731+vmcj@users.noreply.github.com> css new line Update webapp/templates/team/submit_modal.html.twig Co-authored-by: MCJ Vasseur <14887731+vmcj@users.noreply.github.com> fix Submit page error fix submit page error 2 --- etc/db-config.yaml | 8 ++ webapp/public/style_domjudge.css | 22 ++++ .../Controller/Team/SubmissionController.php | 115 ++++++++++++++---- .../src/Form/Type/SubmitProblemPasteType.php | 81 ++++++++++++ webapp/templates/base.html.twig | 2 + webapp/templates/team/submit.html.twig | 12 +- webapp/templates/team/submit_modal.html.twig | 64 ++++++++-- 7 files changed, 260 insertions(+), 44 deletions(-) create mode 100644 webapp/src/Form/Type/SubmitProblemPasteType.php diff --git a/etc/db-config.yaml b/etc/db-config.yaml index 665a48a6e8..7872110f03 100644 --- a/etc/db-config.yaml +++ b/etc/db-config.yaml @@ -201,6 +201,14 @@ - category: Display description: Options related to the DOMjudge user interface. items: + - name: default_submission_code_mode + type: int + default_value: 0 + public: true + description: Select the default submission method for the team + options: + 0: Paste + 1: Upload - name: output_display_limit type: int default_value: 2000 diff --git a/webapp/public/style_domjudge.css b/webapp/public/style_domjudge.css index e443f7271c..b01442e6af 100644 --- a/webapp/public/style_domjudge.css +++ b/webapp/public/style_domjudge.css @@ -699,3 +699,25 @@ blockquote { padding: 3px; border-radius: 5px; } + +#submissionTabs.container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 10px; +} + +.editor-container { + border: 1px solid #ddd; + border-radius: 4px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + padding: 10px; + margin-top: 10px; + margin-bottom: 10px; + background-color: #fafafa; + max-height: 400px; + overflow: auto; +} + +.editor-container:hover { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); +} diff --git a/webapp/src/Controller/Team/SubmissionController.php b/webapp/src/Controller/Team/SubmissionController.php index 35e1a382e7..610ad00e65 100644 --- a/webapp/src/Controller/Team/SubmissionController.php +++ b/webapp/src/Controller/Team/SubmissionController.php @@ -9,6 +9,7 @@ use App\Entity\Submission; use App\Entity\Testcase; use App\Form\Type\SubmitProblemType; +use App\Form\Type\SubmitProblemPasteType; use App\Service\ConfigurationService; use App\Service\DOMJudgeService; use App\Service\EventLogService; @@ -60,47 +61,111 @@ public function createAction(Request $request, ?Problem $problem = null): Respon if ($problem !== null) { $data['problem'] = $problem; } - $form = $this->formFactory + $formUpload = $this->formFactory ->createBuilder(SubmitProblemType::class, $data) ->setAction($this->generateUrl('team_submit')) ->getForm(); - $form->handleRequest($request); + $formPaste = $this->formFactory + ->createBuilder(SubmitProblemPasteType::class, $data) + ->setAction($this->generateUrl('team_submit')) + ->getForm(); - if ($form->isSubmitted() && $form->isValid()) { + $formUpload->handleRequest($request); + $formPaste->handleRequest($request); + if ($formUpload->isSubmitted() || $formPaste->isSubmitted()) { if ($contest === null) { $this->addFlash('danger', 'No active contest'); } elseif (!$this->dj->checkrole('jury') && !$contest->getFreezeData()->started()) { $this->addFlash('danger', 'Contest has not yet started'); } else { - /** @var Problem $problem */ - $problem = $form->get('problem')->getData(); - /** @var Language $language */ - $language = $form->get('language')->getData(); - /** @var UploadedFile[] $files */ - $files = $form->get('code')->getData(); - if (!is_array($files)) { - $files = [$files]; + $problem = null; + $language = null; + $files = []; + $entryPoint = null; + $message = ''; + + if ($formUpload->isSubmitted() && $formUpload->isValid()) { + $problem = $formUpload->get('problem')->getData(); + $language = $formUpload->get('language')->getData(); + $files = $formUpload->get('code')->getData(); + if (!is_array($files)) { + $files = [$files]; + } + $entryPoint = $formUpload->get('entry_point')->getData() ?: null; + } elseif ($formPaste->isSubmitted() && $formPaste->isValid()) { + $problem = $formPaste->get('problem')->getData(); + $language = $formPaste->get('language')->getData(); + $codeContent = $formPaste->get('code_content')->getData(); + + if ($codeContent == null || empty(trim($codeContent))) { + $this->addFlash('danger', 'No code content provided.'); + return $this->redirectToRoute('team_index'); + } + + $tempDir = sys_get_temp_dir(); + $tempFileName = sprintf( + 'submission_%s_%s_%s.%s', + $user->getUsername(), + $problem->getName(), + date('Y-m-d_H-i-s'), + $language->getExtensions()[0] + ); + $tempFileName = preg_replace('/[^a-zA-Z0-9_.-]/', '_', $tempFileName); + $tempFilePath = $tempDir . DIRECTORY_SEPARATOR . $tempFileName; + file_put_contents($tempFilePath, $codeContent); + + $uploadedFile = new UploadedFile( + $tempFilePath, + $tempFileName, + 'application/octet-stream', + null, + true + ); + + $files = [$uploadedFile]; + $entryPoint = $tempFileName; } - $entryPoint = $form->get('entry_point')->getData() ?: null; - $submission = $this->submissionService->submitSolution( - $team, $this->dj->getUser(), $problem->getProbid(), $contest, $language, $files, 'team page', null, - null, $entryPoint, null, null, $message - ); - - if ($submission) { - $this->addFlash( - 'success', - 'Submission done! Watch for the verdict in the list below.' + + if ($problem && $language && !empty($files)) { + $submission = $this->submissionService->submitSolution( + $team, + $this->dj->getUser(), + $problem->getProbid(), + $contest, + $language, + $files, + 'team page', + null, + null, + $entryPoint, + null, + null, + $message ); - } else { - $this->addFlash('danger', $message); + + if ($submission) { + $this->addFlash('success', 'Submission done! Watch for the verdict in the list below.'); + } else { + $this->addFlash('danger', $message); + } + + return $this->redirectToRoute('team_index'); } - return $this->redirectToRoute('team_index'); } } + + $active_tab = (bool) $this->config->get('default_submission_code_mode') == 0 ? 'paste' : 'upload'; + if ($this->dj->getCookie('active_tab') != null) { + $active_tab = $this->dj->getCookie('active_tab'); + } - $data = ['form' => $form->createView(), 'problem' => $problem]; + $data = [ + 'formupload' => $formUpload->createView(), + 'formpaste' => $formPaste->createView(), + 'active_tab' => $active_tab, + 'problem' => $problem, + ]; $data['validFilenameRegex'] = SubmissionService::FILENAME_REGEX; if ($request->isXmlHttpRequest()) { diff --git a/webapp/src/Form/Type/SubmitProblemPasteType.php b/webapp/src/Form/Type/SubmitProblemPasteType.php new file mode 100644 index 0000000000..eb375e27e0 --- /dev/null +++ b/webapp/src/Form/Type/SubmitProblemPasteType.php @@ -0,0 +1,81 @@ +dj->getUser(); + $contest = $this->dj->getCurrentContest($user->getTeam()->getTeamid()); + + $builder->add('code_content', HiddenType::class, [ + 'required' => true, + ]); + $problemConfig = [ + 'class' => Problem::class, + 'query_builder' => fn(EntityRepository $er) => $er->createQueryBuilder('p') + ->join('p.contest_problems', 'cp', Join::WITH, 'cp.contest = :contest') + ->select('p', 'cp') + ->andWhere('cp.allowSubmit = 1') + ->setParameter('contest', $contest) + ->addOrderBy('cp.shortname'), + 'choice_label' => fn(Problem $problem) => sprintf( + '%s - %s', + $problem->getContestProblems()->first()->getShortName(), + $problem->getName() + ), + 'placeholder' => 'Select a problem', + ]; + $builder->add('problem', EntityType::class, $problemConfig); + + $builder->add('language', EntityType::class, [ + 'class' => Language::class, + 'query_builder' => fn(EntityRepository $er) => $er + ->createQueryBuilder('l') + ->andWhere('l.allowSubmit = 1'), + 'choice_label' => 'name', + 'placeholder' => 'Select a language', + ]); + + $builder->add('entry_point', TextType::class, [ + 'label' => 'Entry point', + 'required' => false, + 'help' => 'The entry point for your code.', + 'row_attr' => ['data-entry-point' => ''] + ]); + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($problemConfig) { + $data = $event->getData(); + if (isset($data['problem'])) { + $problemConfig += ['row_attr' => ['class' => 'd-none']]; + $event->getForm()->add('problem', EntityType::class, $problemConfig); + } + }); + } +} diff --git a/webapp/templates/base.html.twig b/webapp/templates/base.html.twig index 895750ede8..6ccf9845de 100644 --- a/webapp/templates/base.html.twig +++ b/webapp/templates/base.html.twig @@ -14,6 +14,8 @@ + + {% for file in customAssetFiles('js') %} {% endfor %} diff --git a/webapp/templates/team/submit.html.twig b/webapp/templates/team/submit.html.twig index af6ce61722..be969d98e2 100644 --- a/webapp/templates/team/submit.html.twig +++ b/webapp/templates/team/submit.html.twig @@ -14,16 +14,16 @@ {% else %} - {{ form_start(form) }} - {{ form_row(form.code) }} - {{ form_row(form.problem) }} - {{ form_row(form.language) }} - {{ form_row(form.entry_point) }} + {{ form_start(formupload) }} + {{ form_row(formupload.code) }} + {{ form_row(formupload.problem) }} + {{ form_row(formupload.language) }} + {{ form_row(formupload.entry_point) }}
- {{ form_end(form) }} + {{ form_end(formupload) }} {% endif %} {% endif %} diff --git a/webapp/templates/team/submit_modal.html.twig b/webapp/templates/team/submit_modal.html.twig index cf72bb3119..7a731e9c18 100644 --- a/webapp/templates/team/submit_modal.html.twig +++ b/webapp/templates/team/submit_modal.html.twig @@ -19,21 +19,59 @@ {% include 'partials/alert.html.twig' with {'type': 'danger', 'message': 'Submissions (temporarily) disabled.'} %} {% else %} - {{ form_start(form) }} - - {{ form_end(form) }} {% endif %} From 56f076e577721250869ae85fadea3df61903ac96 Mon Sep 17 00:00:00 2001 From: as6325400 Date: Sat, 5 Oct 2024 18:04:11 +0800 Subject: [PATCH 02/10] update button text --- webapp/templates/team/submit_modal.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/templates/team/submit_modal.html.twig b/webapp/templates/team/submit_modal.html.twig index 7a731e9c18..9586d88e9b 100644 --- a/webapp/templates/team/submit_modal.html.twig +++ b/webapp/templates/team/submit_modal.html.twig @@ -39,7 +39,7 @@ {{ form_end(formupload) }} @@ -65,7 +65,7 @@ {{ form_end(formpaste) }} From aa8ed3579a30a89d1306be95109f133b23d33ae6 Mon Sep 17 00:00:00 2001 From: as6325400 Date: Sat, 5 Oct 2024 18:57:32 +0800 Subject: [PATCH 03/10] update submit model display --- etc/db-config.yaml | 8 +- .../Controller/Team/SubmissionController.php | 19 +++- webapp/templates/team/submit_modal.html.twig | 107 +++++++++++------- 3 files changed, 83 insertions(+), 51 deletions(-) diff --git a/etc/db-config.yaml b/etc/db-config.yaml index 7872110f03..17a77aa006 100644 --- a/etc/db-config.yaml +++ b/etc/db-config.yaml @@ -202,13 +202,13 @@ description: Options related to the DOMjudge user interface. items: - name: default_submission_code_mode - type: int - default_value: 0 + type: array_val + default_value: [upload] public: true description: Select the default submission method for the team options: - 0: Paste - 1: Upload + - paste + - upload - name: output_display_limit type: int default_value: 2000 diff --git a/webapp/src/Controller/Team/SubmissionController.php b/webapp/src/Controller/Team/SubmissionController.php index 610ad00e65..1f5e32a032 100644 --- a/webapp/src/Controller/Team/SubmissionController.php +++ b/webapp/src/Controller/Team/SubmissionController.php @@ -155,15 +155,28 @@ public function createAction(Request $request, ?Problem $problem = null): Respon } } - $active_tab = (bool) $this->config->get('default_submission_code_mode') == 0 ? 'paste' : 'upload'; - if ($this->dj->getCookie('active_tab') != null) { - $active_tab = $this->dj->getCookie('active_tab'); + $active_tab_array = $this->config->get('default_submission_code_mode'); + $active_tab = ""; + if (count($active_tab_array) == 1) { + $active_tab = reset($active_tab_array); + $this->dj->setCookie('active_tab', $active_tab); + } + else if ($this->dj->getCookie('active_tab') != null) { + $cookie_active_tab = $this->dj->getCookie('active_tab'); + if(in_array($cookie_active_tab, $active_tab_array)) { + $active_tab = $cookie_active_tab; + } + else { + $active_tab = reset($active_tab); + $this->dj->setCookie('active_tab', $active_tab); + } } $data = [ 'formupload' => $formUpload->createView(), 'formpaste' => $formPaste->createView(), 'active_tab' => $active_tab, + 'active_tab_array' => $active_tab_array, 'problem' => $problem, ]; $data['validFilenameRegex'] = SubmissionService::FILENAME_REGEX; diff --git a/webapp/templates/team/submit_modal.html.twig b/webapp/templates/team/submit_modal.html.twig index 9586d88e9b..244baba060 100644 --- a/webapp/templates/team/submit_modal.html.twig +++ b/webapp/templates/team/submit_modal.html.twig @@ -20,62 +20,81 @@ {% else %}