From c2f323e199b192c5916026b69db2c1ff16b5b143 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:50:46 +0200 Subject: [PATCH 01/17] Don't run composer as root if unneeded We now track the autoload_runtime file and create it as the normal user and because it exists we don't recreate it in the install-domserver step as root (assuming it runs with `sudo`). It will still create it if it doesn't exist, because domserver is a dependency for install-domserver (and in that case `composer` would run as root again, so prompting the user to accept this risk). This also works for the inplace targets as those depend on `build` which runs the `domserver` part. (cherry picked from commit b40438377cc2c49b3f82a7f8bb2d7e34c02fca5f) --- Makefile | 14 ++++---------- lib/Makefile | 5 +++++ lib/vendor/Makefile | 12 ++++++++++++ 3 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 lib/vendor/Makefile diff --git a/Makefile b/Makefile index df4f2069a03..1f8bea70473 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ endif domserver: domserver-configure paths.mk config judgehost: judgehost-configure paths.mk config docs: paths.mk config -install-domserver: domserver composer-dump-autoload domserver-create-dirs +install-domserver: domserver domserver-create-dirs install-judgehost: judgehost judgehost-create-dirs install-docs: docs-create-dirs dist: configure composer-dependencies @@ -76,12 +76,6 @@ endif composer-dependencies-dev: composer $(subst 1,-q,$(QUIET)) install --prefer-dist --no-scripts --no-plugins -# Dump autoload dependencies (including plugins) -# This is needed since symfony/runtime is a Composer plugin that runs while dumping -# the autoload file -composer-dump-autoload: - composer $(subst 1,-q,$(QUIET)) dump-autoload -o -a - composer-dump-autoload-dev: composer $(subst 1,-q,$(QUIET)) dump-autoload @@ -101,7 +95,7 @@ build-scripts: # List of SUBDIRS for recursive targets: build: SUBDIRS= lib misc-tools -domserver: SUBDIRS=etc sql misc-tools webapp +domserver: SUBDIRS=etc lib sql misc-tools webapp install-domserver: SUBDIRS=etc lib sql misc-tools webapp example_problems judgehost: SUBDIRS=etc judge misc-tools install-judgehost: SUBDIRS=etc lib judge misc-tools @@ -222,7 +216,7 @@ webapp/.env.local: # symlinks where necessary to let it work from the source tree. # This stuff is a hack! maintainer-install: inplace-install composer-dump-autoload-dev -inplace-install: build composer-dump-autoload domserver-create-dirs judgehost-create-dirs +inplace-install: build domserver-create-dirs judgehost-create-dirs inplace-install-l: # Replace libjudgedir with symlink to prevent lots of symlinks: -rmdir $(judgehost_libjudgedir) @@ -341,5 +335,5 @@ clean-autoconf: $(addprefix inplace-,conf conf-common install uninstall) \ $(addprefix maintainer-,conf install) clean-autoconf config distdocs \ composer-dependencies composer-dependencies-dev \ - composer-dump-autoload composer-dump-autoload-dev \ + composer-dump-autoload-dev \ coverity-conf coverity-build diff --git a/lib/Makefile b/lib/Makefile index 5f2e2dea763..24cd0f82de3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,9 @@ ifndef TOPDIR TOPDIR=.. endif + +REC_TARGETS = domserver + include $(TOPDIR)/Makefile.global OBJECTS = $(addsuffix $(OBJEXT),lib.error lib.misc) @@ -31,3 +34,5 @@ install-domserver: install-judgehost: $(INSTALL_DATA) -t $(DESTDIR)$(judgehost_libdir) *.php *.sh $(INSTALL_PROG) -t $(DESTDIR)$(judgehost_libdir) alert + +domserver: SUBDIRS=vendor diff --git a/lib/vendor/Makefile b/lib/vendor/Makefile new file mode 100644 index 00000000000..b6ee26a3613 --- /dev/null +++ b/lib/vendor/Makefile @@ -0,0 +1,12 @@ +ifndef TOPDIR +TOPDIR=../.. +endif +include $(TOPDIR)/Makefile.global + +clean-l: + rm -f autoload_runtime.php + +autoload_runtime.php: + composer $(subst 1,-q,$(QUIET)) dump-autoload -o -a -d $(TOPDIR) + +domserver: autoload_runtime.php From 762ac7ddd949680118d1f94be9c7125602870d5e Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:34:57 +0200 Subject: [PATCH 02/17] Refer to correct field to prevent HTTP500 This triggered an error and broke the webstandard test. (cherry picked from commit 68628406189d127cc74ca1233f33a65a5c3ec76a) --- webapp/src/Controller/Jury/TeamCategoryController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/TeamCategoryController.php b/webapp/src/Controller/Jury/TeamCategoryController.php index 2cdba5b9225..0cc075696c7 100644 --- a/webapp/src/Controller/Jury/TeamCategoryController.php +++ b/webapp/src/Controller/Jury/TeamCategoryController.php @@ -250,7 +250,7 @@ public function requestRemainingRunsWholeTeamCategoryAction(string $categoryId): ->join('t.category', 'tc') ->andWhere('j.valid = true') ->andWhere('j.result != :compiler_error') - ->andWhere('tc.category = :categoryId') + ->andWhere('tc.categoryid = :categoryId') ->setParameter('compiler_error', 'compiler-error') ->setParameter('categoryId', $categoryId); if ($contestId > -1) { From 2ccabd25a1de427672826aa92bd612c90eb9651a Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:11:04 +0200 Subject: [PATCH 03/17] Disable (broken) Mayhem tests The authentication fails so needs to be rewritten with the new github action. --- .github/workflows/mayhem-api-template.yml | 93 ----------------------- .github/workflows/mayhem-daily.yml | 14 ---- .github/workflows/mayhem-weekly.yml | 25 ------ 3 files changed, 132 deletions(-) delete mode 100644 .github/workflows/mayhem-api-template.yml delete mode 100644 .github/workflows/mayhem-daily.yml delete mode 100644 .github/workflows/mayhem-weekly.yml diff --git a/.github/workflows/mayhem-api-template.yml b/.github/workflows/mayhem-api-template.yml deleted file mode 100644 index 9556bb37187..00000000000 --- a/.github/workflows/mayhem-api-template.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: "Mayhem API analysis (Template)" - -on: - workflow_call: - inputs: - version: - required: true - type: string - duration: - required: true - type: string - secrets: - MAPI_TOKEN: - required: true - -jobs: - mayhem: - name: Mayhem API analysis - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - env: - DB_DATABASE: domjudge - DB_USER: user - DB_PASSWORD: password - steps: - - uses: actions/checkout@v4 - - - name: Install DOMjudge - run: .github/jobs/baseinstall.sh ${{ inputs.version }} - - - name: Dump the OpenAPI - run: .github/jobs/getapi.sh - - - uses: actions/upload-artifact@v3 - if: ${{ inputs.version == 'guest' }} - with: - name: all-apispec - path: | - /home/runner/work/domjudge/domjudge/openapi.json - - - name: Mayhem for API - uses: ForAllSecure/mapi-action@v1 - if: ${{ inputs.version == 'guest' }} - continue-on-error: true - with: - mapi-token: ${{ secrets.MAPI_TOKEN }} - api-url: http://localhost/domjudge - api-spec: http://localhost/domjudge/api/doc.json # swagger/openAPI doc hosted here - duration: "auto" # Only spend time if we need to recheck issues from last time or find issues - sarif-report: mapi.sarif - run-args: | - --config - .github/jobs/data/mapi.config - --ignore-endpoint - ".*strict=true.*" - --ignore-endpoint - ".*strict=True.*" - - - name: Mayhem for API (For application role) - uses: ForAllSecure/mapi-action@v1 - if: ${{ inputs.version != 'guest' }} - continue-on-error: true - with: - mapi-token: ${{ secrets.MAPI_TOKEN }} - target: domjudge-${{ inputs.version }} - api-url: http://localhost/domjudge - api-spec: http://localhost/domjudge/api/doc.json # swagger/openAPI doc hosted here - duration: "${{ inputs.duration }}" - sarif-report: mapi.sarif - run-args: | - --config - .github/jobs/data/mapi.config - --basic-auth - admin:password - --ignore-endpoint - ".*strict=true.*" - --ignore-endpoint - ".*strict=True.*" - - - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: mapi.sarif - - - uses: actions/upload-artifact@v3 - with: - name: ${{ inputs.version }}-logs - path: | - /var/log/nginx - /opt/domjudge/domserver/webapp/var/log/*.log diff --git a/.github/workflows/mayhem-daily.yml b/.github/workflows/mayhem-daily.yml deleted file mode 100644 index 2118bf6920c..00000000000 --- a/.github/workflows/mayhem-daily.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: "Mayhem API daily (admin role only)" - -on: - schedule: - - cron: '0 23 * * *' - -jobs: - mayhem-template: - uses: ./.github/workflows/mayhem-api-template.yml - with: - version: "admin" - duration: "auto" - secrets: - MAPI_TOKEN: ${{ secrets.MAPI_TOKEN }} diff --git a/.github/workflows/mayhem-weekly.yml b/.github/workflows/mayhem-weekly.yml deleted file mode 100644 index 71cc90ecbaf..00000000000 --- a/.github/workflows/mayhem-weekly.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "Mayhem API weekly (all roles)" - -on: - schedule: - - cron: '0 23 * * 0' - -jobs: - mayhem-template: - strategy: - matrix: - include: - - version: "team" - duration: "5m" - - version: "guest" - duration: "auto" - - version: "jury" - duration: "5min" - - version: "admin" - duration: "10m" - uses: ./.github/workflows/mayhem-api-template.yml - with: - version: "${{ matrix.version }}" - duration: "${{ matrix.duration }}" - secrets: - MAPI_TOKEN: ${{ secrets.MAPI_TOKEN }} From f0218fc3e902eaf0ed3b615a135c8506b915c922 Mon Sep 17 00:00:00 2001 From: Dup4 Date: Sun, 16 Jun 2024 14:27:08 +0800 Subject: [PATCH 04/17] fix: time_limit type in ProblemEvent Object Signed-off-by: Dup4 --- webapp/src/DataTransferObject/Shadowing/ProblemEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/DataTransferObject/Shadowing/ProblemEvent.php b/webapp/src/DataTransferObject/Shadowing/ProblemEvent.php index 2aa47e6e279..7c5b76d348c 100644 --- a/webapp/src/DataTransferObject/Shadowing/ProblemEvent.php +++ b/webapp/src/DataTransferObject/Shadowing/ProblemEvent.php @@ -7,7 +7,7 @@ class ProblemEvent implements EventData public function __construct( public readonly string $id, public readonly string $name, - public readonly int $timeLimit, + public readonly float $timeLimit, public readonly ?string $label, public readonly ?string $rgb, ) {} From 83d5836d0314a12ef5d03dd2dd92046a0d4acd13 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Wed, 19 Jun 2024 20:49:52 +0200 Subject: [PATCH 05/17] Escape \ in Python strings It seems Python complains about this for some Python versions. --- misc-tools/import-contest.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc-tools/import-contest.in b/misc-tools/import-contest.in index 756c03d7f04..79d6ffaa9a3 100755 --- a/misc-tools/import-contest.in +++ b/misc-tools/import-contest.in @@ -149,10 +149,10 @@ if import_file('organizations', ['organizations.json']): # Also import logos if we have any # We prefer the 64x64 logo. If it doesn't exist, accept a generic logo (which might be a SVG) # We also prefer PNG/SVG before JPG - import_images('organizations', 'logo', ['^logo\.64x\d+\.png$', '^logo\.(png|svg)$', '^logo\.64x\d+\.jpg$', '^logo\.jpg$']) + import_images('organizations', 'logo', ['^logo\\.64x\\d+\\.png$', '^logo\\.(png|svg)$', '^logo\\.64x\\d+\\.jpg$', '^logo\\.jpg$']) if import_file('teams', ['teams.json', 'teams2.tsv']): # Also import photos if we have any, but prefer JPG over SVG and PNG - import_images('teams', 'photo', ['^photo\.jpg$', '^photo\.(png|svg)$']) + import_images('teams', 'photo', ['^photo\\.jpg$', '^photo\\.(png|svg)$']) import_file('accounts', ['accounts.json', 'accounts.yaml', 'accounts.tsv']) problems_imported = False From 0f59e75371452da6b1b1fc052f33840242f2e861 Mon Sep 17 00:00:00 2001 From: undefined Date: Sun, 16 Jun 2024 14:47:52 +0800 Subject: [PATCH 06/17] ui: problem_list: fix line break --- webapp/templates/partials/problem_list.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/templates/partials/problem_list.html.twig b/webapp/templates/partials/problem_list.html.twig index f00ef14482e..0733241dddc 100644 --- a/webapp/templates/partials/problem_list.html.twig +++ b/webapp/templates/partials/problem_list.html.twig @@ -94,7 +94,7 @@ data-bs-toggle="tooltip" data-placement="top" data-html="true" - title="Between {{ stat.start.timestamp | printtime(null, contest) }} and {{ stat.end.timestamp | printtime(null, contest) }}:
{{ label }}"> + title="Between {{ stat.start.timestamp | printtime(null, contest) }} and {{ stat.end.timestamp | printtime(null, contest) }}:{{ '\n' }}{{ label }}"> {% endfor %} From 063824ce24fd2108124fb11c067d517d6a8d3b5d Mon Sep 17 00:00:00 2001 From: Soha Jin Date: Mon, 17 Jun 2024 20:03:31 +0800 Subject: [PATCH 07/17] Revert "Select shortname from current contestproblem" This reverts commit 0219d8e173540e26b5867d219753dcb23f08fcc5. (cherry picked from commit 98c29f714d56b7e4dddbd46d208f145f60bb2c2c) --- webapp/src/Controller/Team/MiscController.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/webapp/src/Controller/Team/MiscController.php b/webapp/src/Controller/Team/MiscController.php index 648b4bf727b..e714d6737b5 100644 --- a/webapp/src/Controller/Team/MiscController.php +++ b/webapp/src/Controller/Team/MiscController.php @@ -95,12 +95,10 @@ public function homeAction(Request $request): Response $clarifications = $this->em->createQueryBuilder() ->from(Clarification::class, 'c') ->leftJoin('c.problem', 'p') - ->leftJoin('p.contest_problems', 'cp') ->leftJoin('c.sender', 's') ->leftJoin('c.recipient', 'r') - ->select('c', 'cp', 'p') + ->select('c', 'p') ->andWhere('c.contest = :contest') - ->andWhere('cp.contest = :contest') ->andWhere('c.sender IS NULL') ->andWhere('c.recipient = :team OR c.recipient IS NULL') ->setParameter('contest', $contest) @@ -114,12 +112,10 @@ public function homeAction(Request $request): Response $clarificationRequests = $this->em->createQueryBuilder() ->from(Clarification::class, 'c') ->leftJoin('c.problem', 'p') - ->leftJoin('p.contest_problems', 'cp') ->leftJoin('c.sender', 's') ->leftJoin('c.recipient', 'r') - ->select('c', 'cp', 'p') + ->select('c', 'p') ->andWhere('c.contest = :contest') - ->andWhere('cp.contest = :contest') ->andWhere('c.sender = :team') ->setParameter('contest', $contest) ->setParameter('team', $team) From 9d228e93efa77cbaa89c1c6450629a61e4eaaa84 Mon Sep 17 00:00:00 2001 From: Soha Jin Date: Mon, 17 Jun 2024 20:10:24 +0800 Subject: [PATCH 08/17] Add `getContestProblem` to Contest for getting an associated ContestProblem (cherry picked from commit 56104f63024f11599719b1e4553d732cf8e6cbce) --- webapp/src/Entity/Contest.php | 10 ++++++++++ webapp/src/Twig/TwigExtension.php | 11 ++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/webapp/src/Entity/Contest.php b/webapp/src/Entity/Contest.php index 0b88932cd6a..9c5cfe6ab38 100644 --- a/webapp/src/Entity/Contest.php +++ b/webapp/src/Entity/Contest.php @@ -913,6 +913,16 @@ public function getProblems(): Collection return $this->problems; } + public function getContestProblem(Problem $problem): ?ContestProblem + { + foreach ($this->getProblems() as $contestProblem) { + if ($contestProblem->getProblem() === $problem) { + return $contestProblem; + } + } + return null; + } + public function addClarification(Clarification $clarification): Contest { $this->clarifications[] = $clarification; diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index 7238f436825..3fd902e29f4 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -1093,14 +1093,11 @@ public function problemBadge(ContestProblem $problem): string ); } - public function problemBadgeForProblemAndContest(Problem $problem, ?Contest $contest): string + public function problemBadgeForProblemAndContest(Problem $problem, ?Contest $contest = null): string { - foreach ($problem->getContestProblems() as $contestProblem) { - if ($contestProblem->getContest() === $contest) { - return $this->problemBadge($contestProblem); - } - } - return ''; + $contest ??= $this->dj->getCurrentContest(); + $contestProblem = $contest?->getContestProblem($problem); + return $contestProblem === null ? '' : $this->problemBadge($contestProblem); } public function printMetadata(?string $metadata): string From cddeaf14d733923ca812aad6547de9a2d07c99a8 Mon Sep 17 00:00:00 2001 From: Soha Jin Date: Mon, 17 Jun 2024 22:45:39 +0800 Subject: [PATCH 09/17] Rename `problemBadgeForProblemAndContest` to `problemBadgeForContest` (cherry picked from commit eaf95fecd838f6774494db1411bb07710ce41d88) --- webapp/src/Twig/TwigExtension.php | 4 ++-- webapp/templates/jury/executable.html.twig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index 3fd902e29f4..deff4a4f9c2 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -108,7 +108,7 @@ public function getFilters(): array new TwigFilter('tsvField', $this->toTsvField(...)), new TwigFilter('fileTypeIcon', $this->fileTypeIcon(...)), new TwigFilter('problemBadge', $this->problemBadge(...), ['is_safe' => ['html']]), - new TwigFilter('problemBadgeForProblemAndContest', $this->problemBadgeForProblemAndContest(...), ['is_safe' => ['html']]), + new TwigFilter('problemBadgeForContest', $this->problemBadgeForContest(...), ['is_safe' => ['html']]), new TwigFilter('printMetadata', $this->printMetadata(...), ['is_safe' => ['html']]), new TwigFilter('printWarningContent', $this->printWarningContent(...), ['is_safe' => ['html']]), new TwigFilter('entityIdBadge', $this->entityIdBadge(...), ['is_safe' => ['html']]), @@ -1093,7 +1093,7 @@ public function problemBadge(ContestProblem $problem): string ); } - public function problemBadgeForProblemAndContest(Problem $problem, ?Contest $contest = null): string + public function problemBadgeForContest(Problem $problem, ?Contest $contest = null): string { $contest ??= $this->dj->getCurrentContest(); $contestProblem = $contest?->getContestProblem($problem); diff --git a/webapp/templates/jury/executable.html.twig b/webapp/templates/jury/executable.html.twig index 95cbe3956eb..0cf94b261ca 100644 --- a/webapp/templates/jury/executable.html.twig +++ b/webapp/templates/jury/executable.html.twig @@ -48,14 +48,14 @@ {% if executable.type == 'compare' %} {% for problem in executable.problemsCompare %} - p{{ problem.probid }} {{ problem | problemBadgeForProblemAndContest(current_contest) }} + p{{ problem.probid }} {{ problem | problemBadgeForContest }} {% set used = true %} {% endfor %} {% elseif executable.type == 'run' %} {% for problem in executable.problemsRun %} - p{{ problem.probid }} {{ problem | problemBadgeForProblemAndContest(current_contest) }} + p{{ problem.probid }} {{ problem | problemBadgeForContest }} {% set used = true %} {% endfor %} From 75c16e09a9d5435bbcbe34e4b3db8a6882b1efee Mon Sep 17 00:00:00 2001 From: Soha Jin Date: Mon, 17 Jun 2024 20:10:57 +0800 Subject: [PATCH 10/17] Fix #2279: get associated ContestProblem with Clarification entity (cherry picked from commit affacb4ed043efd88c5d7e51f2ea8fdddb9a0576) --- webapp/src/Entity/Clarification.php | 8 ++++++++ .../templates/jury/partials/clarification_list.html.twig | 2 +- webapp/templates/team/partials/clarification.html.twig | 2 +- .../templates/team/partials/clarification_list.html.twig | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/webapp/src/Entity/Clarification.php b/webapp/src/Entity/Clarification.php index ed62d6013f5..b52765b2189 100644 --- a/webapp/src/Entity/Clarification.php +++ b/webapp/src/Entity/Clarification.php @@ -236,6 +236,14 @@ public function getProblem(): ?Problem return $this->problem; } + public function getContestProblem(): ?ContestProblem + { + if (!$this->problem) { + return null; + } + return $this->contest->getContestProblem($this->problem); + } + #[OA\Property(nullable: true)] #[Serializer\VirtualProperty] #[Serializer\SerializedName('problem_id')] diff --git a/webapp/templates/jury/partials/clarification_list.html.twig b/webapp/templates/jury/partials/clarification_list.html.twig index 337499bb1c9..09874023bed 100644 --- a/webapp/templates/jury/partials/clarification_list.html.twig +++ b/webapp/templates/jury/partials/clarification_list.html.twig @@ -71,7 +71,7 @@ {%- if clarification.problem -%} - problem {{ clarification.problem.contestProblems.first | problemBadge -}} + problem {{ clarification.contestProblem | problemBadge -}} {%- elseif clarification.category -%} {{- categories[clarification.category]|default('general') -}} {%- else -%} diff --git a/webapp/templates/team/partials/clarification.html.twig b/webapp/templates/team/partials/clarification.html.twig index eda98ce2937..5004e4c0d42 100644 --- a/webapp/templates/team/partials/clarification.html.twig +++ b/webapp/templates/team/partials/clarification.html.twig @@ -4,7 +4,7 @@
Subject: {% if clarification.problem %} - Problem {{ clarification.problem.contestProblems.first.shortname }}: {{ clarification.problem.name }} + Problem {{ clarification.contestProblem.shortname }}: {{ clarification.problem.name }} {% elseif clarification.category %} {{ categories[clarification.category]|default('general') }} {% else %} diff --git a/webapp/templates/team/partials/clarification_list.html.twig b/webapp/templates/team/partials/clarification_list.html.twig index a36c1e0f30a..47b154c5423 100644 --- a/webapp/templates/team/partials/clarification_list.html.twig +++ b/webapp/templates/team/partials/clarification_list.html.twig @@ -44,7 +44,7 @@ {%- if clarification.problem -%} - problem {{ clarification.problem.contestProblems.first | problemBadge -}} + problem {{ clarification.contestProblem | problemBadge -}} {%- elseif clarification.category -%} {{- categories[clarification.category]|default('general') -}} {%- else -%} From 532f4ae6a7e3338ad46da9a66951a255288687d5 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:43:25 +0200 Subject: [PATCH 11/17] Fix CI In main this file already uses another image so composer was missing. --- .github/workflows/autoconf-check-different-distro.yml | 2 +- .github/workflows/autoconf-check.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/autoconf-check-different-distro.yml b/.github/workflows/autoconf-check-different-distro.yml index 8216eb3a26b..9db54dfaa8d 100644 --- a/.github/workflows/autoconf-check-different-distro.yml +++ b/.github/workflows/autoconf-check-different-distro.yml @@ -20,7 +20,7 @@ jobs: image: ${{ matrix.os }}:${{ matrix.version }} steps: - name: Install git so we get the .github directory - run: dnf install -y git + run: dnf install -y git composer - uses: actions/checkout@v4 - name: Setup image and run bats tests run: .github/jobs/configure-checks/setup_configure_image.sh diff --git a/.github/workflows/autoconf-check.yml b/.github/workflows/autoconf-check.yml index 016ec024f71..58f6f691d10 100644 --- a/.github/workflows/autoconf-check.yml +++ b/.github/workflows/autoconf-check.yml @@ -32,7 +32,7 @@ jobs: image: ${{ matrix.os }}:${{ matrix.version }} steps: - name: Install git so we get the .github directory - run: apt-get update; apt-get install -y git + run: apt-get update; apt-get install -y git composer - uses: actions/checkout@v4 - name: Setup image and run bats tests run: .github/jobs/configure-checks/setup_configure_image.sh From 92e3ad705cef4b6e4db2033751384327437e4a9a Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sat, 20 Jul 2024 10:25:17 +0200 Subject: [PATCH 12/17] Release the patch release --- ChangeLog | 3 +++ README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 30ebc035f24..5bc61994784 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ DOMjudge Programming Contest Judging System +Version 8.3.1 - 21 July 2024 + - Create autoload_runtime.php as normal user to prevent a composer warning. + Version 8.3.0 - 31 May 2024 --------------------------- - [security] Close metadata file descriptor for the child in runguard. diff --git a/README.md b/README.md index 5499da3e0a8..eaa23881ee5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DOMjudge [![Coverity Scan Status](https://img.shields.io/coverity/scan/671.svg)](https://scan.coverity.com/projects/domjudge) [![CodeQL alerts](https://github.com/DOMjudge/domjudge/actions/workflows/codeql-analysis.yml/badge.svg?branch=main&event=push)](https://github.com/DOMjudge/domjudge/actions/workflows/codeql-analysis.yml) -This is the Programming Contest Jury System "DOMjudge" version 8.3.0 +This is the Programming Contest Jury System "DOMjudge" version 8.3.1 DOMjudge is a system for running a programming contest, like the ICPC regional and world championship programming contests. From 6f223eafe50a829887451127ae589379b44464e5 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:27:24 +0200 Subject: [PATCH 13/17] Fix start of MySQL container The native password module used was deprecated with MySQL8 and doesn't work with MySQL9 anymore. It seems we don't need it anymore (I think we needed it because the mariadb-utils did not have support for caching_sha2_password yet), but the alternative is to keep using the MySQL8 container and not test for MySQL9. Under the hood in the past we used to store the password as a hash in the mysql.user table and now it's stored in another way (https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password) which should also give better performance. See: https://dba.stackexchange.com/a/209520 (cherry picked from commit 9c2bb9906c384e6b4292ec973cbcf2edb392dd79) --- gitlab/ci/template.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/gitlab/ci/template.yml b/gitlab/ci/template.yml index 5b954aff68f..1c75a358a99 100644 --- a/gitlab/ci/template.yml +++ b/gitlab/ci/template.yml @@ -36,7 +36,6 @@ - /bin/true services: - name: mysql - command: ["--mysql-native-password", "--authentication_policy=mysql_native_password"] alias: sqlserver .mariadb_job: From 719746d9b17ddc625ebcca88296be8070c7e25de Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Fri, 16 Aug 2024 07:51:35 +0200 Subject: [PATCH 14/17] Fix saving new problems with statements Fixes #2646. We used to persist the entity both before and after calling the lifecycle callbacks ourselves, which would introduce weird behavior where Doctrine wanted to insert some rows twice. By not persisting before calling the callbacks ourselves, this issue goes away. (cherry picked from commit 9f12b776881148aeb65e4c067e7290791752ea05) --- ChangeLog | 4 ++++ webapp/src/Controller/Jury/ProblemController.php | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5bc61994784..3436f744452 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ DOMjudge Programming Contest Judging System +Version 8.3.2 +--------------------------- + - Fix saving new problems with problem statement from web UI. + Version 8.3.1 - 21 July 2024 - Create autoload_runtime.php as normal user to prevent a composer warning. diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index 56ed94d5f89..95d40eafdbf 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -1087,7 +1087,6 @@ public function addAction(Request $request): Response $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $this->em->persist($problem); $this->saveEntity($this->em, $this->eventLogService, $this->dj, $problem, null, true); return $this->redirectToRoute('jury_problem', ['probId' => $problem->getProbid()]); } From 3324986cd7243c31987fdbc976411027e6c610b6 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:14:06 +0200 Subject: [PATCH 15/17] Release now as we didn't at that date --- ChangeLog | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3436f744452..ccd133df9b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,9 @@ DOMjudge Programming Contest Judging System -Version 8.3.2 ---------------------------- - - Fix saving new problems with problem statement from web UI. - -Version 8.3.1 - 21 July 2024 +Version 8.3.1 - 13 September 2024 +--------------------------------- - Create autoload_runtime.php as normal user to prevent a composer warning. + - Fix saving new problems with problem statement from web UI. Version 8.3.0 - 31 May 2024 --------------------------- From 12fe2698436a8cb86dd57587e151f039582ad817 Mon Sep 17 00:00:00 2001 From: as6325400 Date: Sun, 22 Sep 2024 02:43:21 +0800 Subject: [PATCH 16/17] add Paste code to submit feature --- etc/db-config.yaml | 8 ++ .../Controller/Team/SubmissionController.php | 104 ++++++++++++++++-- .../src/Form/Type/SubmitProblemPasteType.php | 99 +++++++++++++++++ webapp/templates/base.html.twig | 2 + webapp/templates/team/submit_modal.html.twig | 96 +++++++++++++--- 5 files changed, 286 insertions(+), 23 deletions(-) create mode 100644 webapp/src/Form/Type/SubmitProblemPasteType.php diff --git a/etc/db-config.yaml b/etc/db-config.yaml index 9c6b0866b48..174c9791e88 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/src/Controller/Team/SubmissionController.php b/webapp/src/Controller/Team/SubmissionController.php index e6cfbf223f1..7cd4d8e9021 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\SubmissionService; @@ -54,34 +55,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() && $formUpload->isValid()) { 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(); + $problem = $formUpload->get('problem')->getData(); /** @var Language $language */ - $language = $form->get('language')->getData(); + $language = $formUpload->get('language')->getData(); /** @var UploadedFile[] $files */ - $files = $form->get('code')->getData(); + $files = $formUpload->get('code')->getData(); if (!is_array($files)) { $files = [$files]; } - $entryPoint = $form->get('entry_point')->getData() ?: null; + $entryPoint = $formUpload->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 + $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.' + ); + } else { + $this->addFlash('danger', $message); + } + return $this->redirectToRoute('team_index'); + } + } elseif ($formPaste->isSubmitted() && $formPaste->isValid()) { + 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 { + $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 = $formPaste->get('entry_point')->getData() ?: null; + $submission = $this->submissionService->submitSolution( + $team, + $this->dj->getUser(), + $problem, + $contest, + $language, + $files, + 'team page', + null, + null, + $entryPoint, + null, + null, + $message + ); if ($submission) { $this->addFlash( 'success', @@ -90,11 +168,17 @@ public function createAction(Request $request, ?Problem $problem = null): Respon } else { $this->addFlash('danger', $message); } + return $this->redirectToRoute('team_index'); } } - $data = ['form' => $form->createView(), 'problem' => $problem]; + $data = [ + 'formupload' => $formUpload->createView(), + 'formpaste' => $formPaste->createView(), + 'problem' => $problem, + 'defaultSubmissionCodeMode' => (bool) $this->config->get('default_submission_code_mode'), + ]; $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 00000000000..b0ee0f2f187 --- /dev/null +++ b/webapp/src/Form/Type/SubmitProblemPasteType.php @@ -0,0 +1,99 @@ +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' => ''], + 'constraints' => [ + new Callback(function ($value, ExecutionContextInterface $context) { + /** @var Form $form */ + $form = $context->getRoot(); + /** @var Language $language */ + $language = $form->get('language')->getData(); + if ($language && $language->getRequireEntryPoint() && empty($value)) { + $message = sprintf( + '%s required, but not specified', + $language->getEntryPointDescription() ?: 'Entry point' + ); + $context + ->buildViolation($message) + ->atPath('entry_point') + ->addViolation(); + } + }), + ] + ]); + $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); + } + }); + } +} \ No newline at end of file diff --git a/webapp/templates/base.html.twig b/webapp/templates/base.html.twig index 895750ede82..6ccf9845de3 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_modal.html.twig b/webapp/templates/team/submit_modal.html.twig index cf72bb3119c..ebb459ce699 100644 --- a/webapp/templates/team/submit_modal.html.twig +++ b/webapp/templates/team/submit_modal.html.twig @@ -19,21 +19,64 @@ {% include 'partials/alert.html.twig' with {'type': 'danger', 'message': 'Submissions (temporarily) disabled.'} %}
{% else %} - {{ form_start(form) }} + {% set active_tab = defaultSubmissionCodeMode == 0 ? 'paste' : 'upload' %} + + - - {{ form_end(form) }} {% endif %} @@ -80,4 +123,31 @@ filesSelected.removeClass('d-none'); }); + From bb8e1e5133e34f8ce3523c9c67a3af40d0adff37 Mon Sep 17 00:00:00 2001 From: as6325400 Date: Sun, 22 Sep 2024 19:10:15 +0800 Subject: [PATCH 17/17] setting paste_code file entry_point --- .../Controller/Team/SubmissionController.php | 3 +-- .../src/Form/Type/SubmitProblemPasteType.php | 20 +------------------ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/webapp/src/Controller/Team/SubmissionController.php b/webapp/src/Controller/Team/SubmissionController.php index 7cd4d8e9021..d5d9eb3d06a 100644 --- a/webapp/src/Controller/Team/SubmissionController.php +++ b/webapp/src/Controller/Team/SubmissionController.php @@ -67,7 +67,6 @@ public function createAction(Request $request, ?Problem $problem = null): Respon $formUpload->handleRequest($request); $formPaste->handleRequest($request); - if ($formUpload->isSubmitted() && $formUpload->isValid()) { if ($contest === null) { $this->addFlash('danger', 'No active contest'); @@ -144,7 +143,7 @@ public function createAction(Request $request, ?Problem $problem = null): Respon ); $files = [$uploadedFile]; - $entryPoint = $formPaste->get('entry_point')->getData() ?: null; + $entryPoint = $tempFileName; $submission = $this->submissionService->submitSolution( $team, $this->dj->getUser(), diff --git a/webapp/src/Form/Type/SubmitProblemPasteType.php b/webapp/src/Form/Type/SubmitProblemPasteType.php index b0ee0f2f187..71050b95a8c 100644 --- a/webapp/src/Form/Type/SubmitProblemPasteType.php +++ b/webapp/src/Form/Type/SubmitProblemPasteType.php @@ -68,25 +68,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'label' => 'Entry point', 'required' => false, 'help' => 'The entry point for your code.', - 'row_attr' => ['data-entry-point' => ''], - 'constraints' => [ - new Callback(function ($value, ExecutionContextInterface $context) { - /** @var Form $form */ - $form = $context->getRoot(); - /** @var Language $language */ - $language = $form->get('language')->getData(); - if ($language && $language->getRequireEntryPoint() && empty($value)) { - $message = sprintf( - '%s required, but not specified', - $language->getEntryPointDescription() ?: 'Entry point' - ); - $context - ->buildViolation($message) - ->atPath('entry_point') - ->addViolation(); - } - }), - ] + 'row_attr' => ['data-entry-point' => ''] ]); $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($problemConfig) { $data = $event->getData();