From a2dfa3525460938dffea4be0cc6d933b1a996d66 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 6 Mar 2023 19:46:41 +0100 Subject: [PATCH 01/80] Start development for patch release --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0131d618b..5a34e620b7 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) [![LGTM alerts](https://img.shields.io/lgtm/alerts/g/DOMjudge/domjudge.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/DOMjudge/domjudge/alerts/) -This is the Programming Contest Jury System "DOMjudge" version 8.2.0 +This is the Programming Contest Jury System "DOMjudge" version 8.2.1DEV DOMjudge is a system for running a programming contest, like the ICPC regional and world championship programming contests. From 64c9aac4d2af3c6fbd63e6e60825ed50e749f82c Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 5 Mar 2023 15:28:53 +0100 Subject: [PATCH 02/80] Remove (after_)event_id from scoreboard API in strict mode. This was removed in the 2022-07 version of the Contest API, see https://ccs-specs.icpc.io/2022-07/ (cherry picked from commit 86a5cdbcfe25e572311af3d88eac47efd77190a4) --- webapp/src/Controller/API/ScoreboardController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webapp/src/Controller/API/ScoreboardController.php b/webapp/src/Controller/API/ScoreboardController.php index b97a3b1cb6..e96562390f 100644 --- a/webapp/src/Controller/API/ScoreboardController.php +++ b/webapp/src/Controller/API/ScoreboardController.php @@ -125,7 +125,6 @@ public function getScoreboardAction(Request $request): array $contest = $this->em->getRepository(Contest::class)->find($this->getContestId($request)); // Get the event for this scoreboard. - // TODO: Add support for after_event_id. /** @var Event $event */ $event = $this->em->createQueryBuilder() ->from(Event::class, 'e') @@ -141,12 +140,14 @@ public function getScoreboardAction(Request $request): array if ($event) { // Build up scoreboard results. $results = [ - 'event_id' => (string)$event->getEventid(), 'time' => Utils::absTime($event->getEventtime()), 'contest_time' => Utils::relTime($event->getEventtime() - $contest->getStarttime()), 'state' => $contest->getState(), 'rows' => [], ]; + if (!$request->query->getBoolean('strict')) { + $results['event_id'] = (string)$event->getEventid(); + } } // Return early if there's nothing to display yet. From d0d70390bc4963f22bfbed2fe5858532e4b3eff3 Mon Sep 17 00:00:00 2001 From: Maarten Sijm <9739541+mpsijm@users.noreply.github.com> Date: Tue, 7 Mar 2023 09:52:06 +0100 Subject: [PATCH 03/80] CONTRIBUTORS.md: fix link to CONTRIBUTING.md (cherry picked from commit 948b599afcd468cc57a1e0be6d1cc43b224b10d4) --- CONTRIBUTORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ab7a5fde37..0e82db51fa 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -64,7 +64,7 @@ Many people have contributed over the years. Many thanks: Some code has been ported from the ETH Zurich fork by Christoph Krautz, Thomas Rast et al. -The file (CONTRIBUTING.md)[CONTRIBUTING.md] has instructions on +The file [CONTRIBUTING.md](CONTRIBUTING.md) has instructions on how to best contribute. ## Special thanks From 6d113b454487f9ec0650f641fd3b88de0ce06c18 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Tue, 7 Mar 2023 21:00:47 +0100 Subject: [PATCH 04/80] Add missing return for depreciation (cherry picked from commit 5d0968d34bac8b713e2032d1740c8bffd6892875) --- webapp/src/Command/CallApiActionCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Command/CallApiActionCommand.php b/webapp/src/Command/CallApiActionCommand.php index db666494f2..dac4c860a4 100644 --- a/webapp/src/Command/CallApiActionCommand.php +++ b/webapp/src/Command/CallApiActionCommand.php @@ -63,7 +63,7 @@ protected function configure(): void ); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { if (!in_array($input->getOption('method'), [Request::METHOD_GET, Request::METHOD_POST], true)) { $output->writeln('Error: only GET and POST methods are supported'); From 066a4d9b4b836860b32635340b8825581e3710f7 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Fri, 10 Mar 2023 16:26:48 +0100 Subject: [PATCH 05/80] Make configure-domjudge also use the new logic to determine to use the API or the CLI to talk to the API. (cherry picked from commit e22b37b992c8506536c322f364ec784b2e0f3740) --- misc-tools/configure-domjudge.in | 4 +--- misc-tools/dj_utils.py | 24 ++++++++++++++------- webapp/src/Command/CallApiActionCommand.php | 20 ++++++++++++----- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/misc-tools/configure-domjudge.in b/misc-tools/configure-domjudge.in index fa13db6d6b..b7f1e43e73 100755 --- a/misc-tools/configure-domjudge.in +++ b/misc-tools/configure-domjudge.in @@ -79,9 +79,7 @@ if os.path.exists('config.json'): print(f' - missing keys from new config = {missing_keys}') if diffs or new_keys or missing_keys: if dj_utils.confirm(' - Upload these configuration changes?', True): - url = f'{dj_utils.api_url}/config' - response = requests.put(url, headers=dj_utils.headers, json=expected_config) - actual_config = dj_utils.parse_api_response('config', response) + actual_config = dj_utils.do_api_request('config', 'PUT', expected_config) diffs, new_keys, missing_keys = compare_configs( actual_config=actual_config, expected_config=expected_config diff --git a/misc-tools/dj_utils.py b/misc-tools/dj_utils.py index 75e2d9c98b..17956a469b 100644 --- a/misc-tools/dj_utils.py +++ b/misc-tools/dj_utils.py @@ -47,7 +47,7 @@ def parse_api_response(name: str, response: requests.Response): return json.loads(response.text) -def do_api_request(name: str): +def do_api_request(name: str, method: str = 'GET', jsonData: dict = {}): '''Perform an API call to the given endpoint and return its data. Based on whether `domjudge_webapp_folder_or_api_url` is a folder or URL this @@ -55,6 +55,8 @@ def do_api_request(name: str): Parameters: name (str): the endpoint to call + method (str): the method to use, GET or PUT are supported + jsonData (dict): the JSON data to PUT. Only used when method is PUT Returns: The endpoint contents. @@ -64,13 +66,16 @@ def do_api_request(name: str): ''' if os.path.isdir(domjudge_webapp_folder_or_api_url): - return api_via_cli(name) + return api_via_cli(name, method, {}, {}, jsonData) else: global ca_check url = f'{domjudge_webapp_folder_or_api_url}/{name}' try: - response = requests.get(url, headers=headers, verify=ca_check) + if method == 'GET': + response = requests.get(url, headers=headers, verify=ca_check) + elif method == 'PUT': + response = requests.put(url, headers=headers, verify=ca_check, json=json) except requests.exceptions.SSLError as e: ca_check = not confirm( "Can not verify certificate, ignore certificate check?", False) @@ -83,7 +88,6 @@ def do_api_request(name: str): raise RuntimeError(e) return parse_api_response(name, response) - def upload_file(name: str, apifilename: str, file: str, data: dict = {}): '''Upload the given file to the API at the given path with the given name. @@ -126,14 +130,15 @@ def upload_file(name: str, apifilename: str, file: str, data: dict = {}): return parse_api_response(name, response) -def api_via_cli(name: str, method: str = 'GET', data: dict = {}, files: dict = {}): +def api_via_cli(name: str, method: str = 'GET', data: dict = {}, files: dict = {}, jsonData: dict = {}): '''Perform the given API request using the CLI Parameters: name (str): the endpoint to call - method (str): the method to use. Either GET or POST - data (dict): the POST data to use. Only used when method is POST - files (dict): the files to use. Only used when method is POST + method (str): the method to use. Either GET, POST or PUT + data (dict): the POST data to use. Only used when method is POST or PUT + files (dict): the files to use. Only used when method is POST or PUT + jsonData (dict): the JSON data to use. Only used when method is POST or PUT Returns: The parsed endpoint contents. @@ -155,6 +160,9 @@ def api_via_cli(name: str, method: str = 'GET', data: dict = {}, files: dict = { for item in files: command.extend(['-f', f'{item}={files[item]}']) + if jsonData: + command.extend(['-j', json.dumps(jsonData)]) + command.append(name) result = subprocess.run(command, capture_output=True) diff --git a/webapp/src/Command/CallApiActionCommand.php b/webapp/src/Command/CallApiActionCommand.php index dac4c860a4..61712bf884 100644 --- a/webapp/src/Command/CallApiActionCommand.php +++ b/webapp/src/Command/CallApiActionCommand.php @@ -47,13 +47,19 @@ protected function configure(): void 'data', 'd', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'POST data to use as key=value. Only allowed when the method is POST' + 'POST data to use as key=value. Only allowed when the method is POST or PUT' + ) + ->addOption( + 'json', + 'j', + InputOption::VALUE_REQUIRED, + 'JSON body data to use. Only allowed when the method is POST or PUT' ) ->addOption( 'file', 'f', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Files to use as field=filename. Only allowed when the method is POST' + 'Files to use as field=filename. Only allowed when the method is POST or PUT' ) ->addOption( 'user', @@ -65,8 +71,8 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - if (!in_array($input->getOption('method'), [Request::METHOD_GET, Request::METHOD_POST], true)) { - $output->writeln('Error: only GET and POST methods are supported'); + if (!in_array($input->getOption('method'), [Request::METHOD_GET, Request::METHOD_POST, Request::METHOD_PUT], true)) { + $output->writeln('Error: only GET, POST and PUT methods are supported'); return self::FAILURE; } @@ -98,7 +104,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $data = []; $files = []; - if ($input->getOption('method') === Request::METHOD_POST) { + if (in_array($input->getOption('method'), [Request::METHOD_POST, Request::METHOD_PUT], true)) { foreach ($input->getOption('data') as $dataItem) { $parts = explode('=', $dataItem, 2); if (count($parts) !== 2) { @@ -109,6 +115,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $data[$parts[0]] = $parts[1]; } + if ($json = $input->getOption('json')) { + $data = array_merge($data, $this->dj->jsonDecode($json)); + } + foreach ($input->getOption('file') as $fileItem) { $parts = explode('=', $fileItem, 2); if (count($parts) !== 2) { From 2145cbf9f64848316edccfb0baf00960861a5b68 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 11 Mar 2023 14:27:10 +0100 Subject: [PATCH 06/80] Let scripts use the CLI to internally access the API by default. This simplifies usage, and is typically what you want when you run these commands locally on the domserver. (cherry picked from commit 1699d754526766aa265de75690944722e8f7b268) --- doc/manual/import.rst | 14 +++++++------- misc-tools/configure-domjudge.in | 16 ++++++++++------ misc-tools/import-contest.in | 16 +++++++++------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/doc/manual/import.rst b/doc/manual/import.rst index 8a25924f64..5ff4eefdbb 100644 --- a/doc/manual/import.rst +++ b/doc/manual/import.rst @@ -10,7 +10,7 @@ in your `.netrc`_ file. You need to install `httpie`_ and replace the ```` in the examples below with the API URL of your local DOMjudge installation. -For using the CLI, you need to replace ```` with the path to +To use the CLI, you need to replace ```` with the path to the ``webapp`` directory of the DOMserver. Importing team categories @@ -444,11 +444,11 @@ Call it from your contest folder like this:: misc-tools/import-contest -to use the API, or:: +to use the API, or simply:: - misc-tools/import-contest + misc-tools/import-contest -to use the CLI. +to use the CLI. In this case you must run it from the DOMserver. Importing from ICPC CMS API --------------------------- @@ -487,11 +487,11 @@ called `config.json` in your current directory:: misc-tools/configure-domjudge -to use the API or:: +to use the API, or simply:: - misc-tools/configure-domjudge + misc-tools/configure-domjudge -to use the CLI. +to use the CLI. In this case you must run it from the DOMserver. .. _CCS specification: https://ccs-specs.icpc.io/2022-07/ccs_system_requirements#appendix-file-formats .. _.netrc: https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html diff --git a/misc-tools/configure-domjudge.in b/misc-tools/configure-domjudge.in index b7f1e43e73..cc2078acd1 100755 --- a/misc-tools/configure-domjudge.in +++ b/misc-tools/configure-domjudge.in @@ -3,7 +3,7 @@ ''' configure-domjudge -- Convenience script to update DOMjudge configuration. -Reads credentials from ~/.netrc. +Reads credentials from ~/.netrc when using the API. See also https://www.domjudge.org/docs/manual/main/import.html (replace main with the DOMjudge major.minor version if you are running a @@ -23,8 +23,10 @@ from typing import List, Set sys.path.append('@domserver_libdir@') import dj_utils +webappdir = '@domserver_webappdir@' + def usage(): - print(f'Usage {sys.argv[0]} ') + print(f'Usage: {sys.argv[0]} []') exit(1) @@ -40,7 +42,7 @@ def compare_configs(expected_config: Set, actual_config: Set, num_spaces=4) -> ( diffs.extend(d) else: diffs.append(f'{space_string}- {k}:\n {space_string}is: {actual_config[k]}\n {space_string}new: {expected_config[k]}') - + new_keys = set(expected_config.keys()).difference(set(actual_config.keys())) missing_keys = set(actual_config.keys()).difference(set(expected_config.keys())) return (diffs, new_keys, missing_keys) @@ -50,11 +52,13 @@ def _keyify_list(l: List) -> Set: return { elem['id']: elem for elem in l } -if len(sys.argv) < 2: +if len(sys.argv) == 1: + dj_utils.domjudge_webapp_folder_or_api_url = webappdir +elif len(sys.argv) == 2: + dj_utils.domjudge_webapp_folder_or_api_url = sys.argv[1] +else: usage() -dj_utils.domjudge_webapp_folder_or_api_url = sys.argv[1] - user_data = dj_utils.do_api_request('user') if 'admin' not in user_data['roles']: print('Your user does not have the \'admin\' role, can not import.') diff --git a/misc-tools/import-contest.in b/misc-tools/import-contest.in index dcc4aa3e0a..13e07ff61a 100755 --- a/misc-tools/import-contest.in +++ b/misc-tools/import-contest.in @@ -2,8 +2,8 @@ ''' import-contest -- Convenience script to import a contest (including metadata, -teams and problems) via the command line to the DOMjudge API or to a DOMjudge -installation using the CLI. +teams and problems) from the command line. Defaults to using the CLI interface; +Specify a DOMjudge API URL as to use that. Reads credentials from ~/.netrc when using the API. @@ -27,10 +27,11 @@ sys.path.append('@domserver_libdir@') import dj_utils cid = None +webappdir = '@domserver_webappdir@' def usage(): - print(f'Usage {sys.argv[0]} ') + print(f'Usage: {sys.argv[0]} []') exit(1) @@ -92,12 +93,13 @@ def import_images(entity: str, property: str, filename_regexes: List[str]): else: print(f'Skipping {entity} {property} import.') - -if len(sys.argv) < 2: +if len(sys.argv) == 1: + dj_utils.domjudge_webapp_folder_or_api_url = webappdir +elif len(sys.argv) == 2: + dj_utils.domjudge_webapp_folder_or_api_url = sys.argv[1] +else: usage() -dj_utils.domjudge_webapp_folder_or_api_url = sys.argv[1] - user_data = dj_utils.do_api_request('user') if 'admin' not in user_data['roles']: print('Your user does not have the \'admin\' role, can not import.') From 8910370d6aaae4d9898a1933550aaba31713a204 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 12 Mar 2023 15:45:30 +0100 Subject: [PATCH 07/80] Factor out code to install examples and drop WEBAPPDIR argument. (cherry picked from commit 8901aee21532ee517646e9b57f899e9496b4a683) --- sql/dj_setup_database.in | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sql/dj_setup_database.in b/sql/dj_setup_database.in index 5d6c11e606..4f085d12e3 100755 --- a/sql/dj_setup_database.in +++ b/sql/dj_setup_database.in @@ -224,6 +224,13 @@ remove_db_users() verbose "DOMjudge database and user(s) removed." } +install_examples() +{ + DBUSER=$domjudge_DBUSER PASSWD=$domjudge_PASSWD symfony_console domjudge:load-example-data + "$EXAMPLEPROBDIR"/generate-contest-yaml + ( cd "$EXAMPLEPROBDIR" && yes y | "$BINDIR"/import-contest ) +} + ### Script starts here ### # Parse command-line options: @@ -286,10 +293,7 @@ uninstall) install-examples) read_dbpasswords - - DBUSER=$domjudge_DBUSER PASSWD=$domjudge_PASSWD symfony_console domjudge:load-example-data - "$EXAMPLEPROBDIR"/generate-contest-yaml - ( cd "$EXAMPLEPROBDIR" && yes y | "$BINDIR"/import-contest "${WEBAPPDIR}" ) + install_examples ;; install-loadtest) @@ -316,11 +320,7 @@ bare-install|install) unset DB_FIRST_INSTALL DBUSER=$domjudge_DBUSER PASSWD=$domjudge_PASSWD symfony_console domjudge:load-default-data if [ "$1" = "install" ]; then - DBUSER=$domjudge_DBUSER PASSWD=$domjudge_PASSWD symfony_console domjudge:load-example-data - "$EXAMPLEPROBDIR"/generate-contest-yaml - ( cd "$EXAMPLEPROBDIR" && yes y | "$BINDIR"/import-contest "${WEBAPPDIR}" ) - fi - if [ "$1" = "install" ]; then + install_examples verbose "SQL structure and default/example data installed." else verbose "SQL structure and defaults installed (no sample data)." From f2151e713ae3e40f8d71917844b607f8251fb916 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 18 Mar 2023 16:51:32 +0100 Subject: [PATCH 08/80] Use correct variable in API error. (cherry picked from commit 7b7b24fc3a3f617c1895f97eba6055e06c74076e) --- webapp/src/Controller/API/ContestController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/API/ContestController.php b/webapp/src/Controller/API/ContestController.php index 2f12401f91..e77056ae41 100644 --- a/webapp/src/Controller/API/ContestController.php +++ b/webapp/src/Controller/API/ContestController.php @@ -763,7 +763,7 @@ public function samplesDataZipAction(Request $request): Response ->getOneOrNullResult(); if ($contest === null) { - throw new NotFoundHttpException(sprintf('Object with ID \'%s\' not found', $id)); + throw new NotFoundHttpException(sprintf('Object with ID \'%s\' not found', $request->attributes->get('cid'))); } return $this->dj->getSamplesZipForContest($contest); From 9f40590d0271d5e972e1e759201cfed9cbdd8e36 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 19 Mar 2023 14:26:46 +0100 Subject: [PATCH 09/80] The API was throwing a 500 on aborted judgings. (cherry picked from commit b110b6e8601a9a96bbf8b9556e77d99161383593) --- webapp/src/Controller/API/JudgementController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/src/Controller/API/JudgementController.php b/webapp/src/Controller/API/JudgementController.php index 55bf7e9ab5..9a587aa68a 100644 --- a/webapp/src/Controller/API/JudgementController.php +++ b/webapp/src/Controller/API/JudgementController.php @@ -44,6 +44,7 @@ public function __construct( $verdictsConfig = $this->dj->getDomjudgeEtcDir() . '/verdicts.php'; $this->verdicts = include $verdictsConfig; + $this->verdicts['aborted'] = 'JE'; /* happens for aborted judgings */ } /** From ae45be579c6e035cb361e223529279925779d290 Mon Sep 17 00:00:00 2001 From: Thijs Kinkhorst Date: Tue, 28 Mar 2023 12:58:36 +0000 Subject: [PATCH 10/80] Use our own specialchars wrapper (cherry picked from commit 446697577d23969e6293aaba908be8ec333e3a36) --- webapp/src/Twig/TwigExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index 8447ab5fb4..217b555ab4 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -776,7 +776,7 @@ public function interactiveLog(string $log, bool $forTeam = false): string if (empty($content)) { break; } - $content = htmlspecialchars($content); + $content = Utils::specialchars($content); $content = '' . str_replace("\n", "\u{21B5}
", $content) . ''; From beb12b0dd4140aefd24a80c67852d120c822a74a Mon Sep 17 00:00:00 2001 From: forward0606 <73343386+forward0606@users.noreply.github.com> Date: Mon, 3 Apr 2023 22:23:16 +0800 Subject: [PATCH 11/80] Fixed broken links in CONTRIBUTING.md (#1975) (cherry picked from commit 7d7b3c61c6c7956cc764d22ed1368ad3d239b42a) --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2e4844362a..0b6b402ea6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ contributors. We use the [GitHub issue tracker](https://github.com/DOMjudge/domjudge/issues) for bug reports, feature requests and anything in between. Try to provide a clear story, and fill in as much information as possible in our -[GitHub issue template](https://github.com/DOMjudge/domjudge/blob/master/ISSUE_TEMPLATE.md). +[GitHub issue template](https://github.com/DOMjudge/domjudge/tree/main/.github/ISSUE_TEMPLATE). Providing accurate and relevant details will typically speed up the triaging and debugging process. @@ -51,8 +51,8 @@ If you are interested in starting to contribute to DOMjudge, you are most welcome. The following are some pointers. First, install and configure the development version of DOMjudge. -Either directly from the git repository, see the [developer information](https://www.domjudge.org/docs/manual/master/develop.html) -section in the admin manual, or via the [contributor docker image](https://github.com/DOMjudge/domjudge-packaging/tree/master/docker-contributor). +Either directly from the git repository, see the [developer information](https://www.domjudge.org/snapshot/manual/develop.html) +section in the admin manual, or via the [contributor docker image](https://github.com/DOMjudge/domjudge-packaging/tree/main/docker-contributor). If you follow the admin manual for installation, this is also a great way to verify that the documentation is clear and complete, and to report anything that is not. From 4dcf1891364e261fc1871688143de701b87567fc Mon Sep 17 00:00:00 2001 From: MCJ Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 3 Apr 2023 20:08:07 +0200 Subject: [PATCH 12/80] Link to main documentation Snapshot is less often in sync than the main documentation. (cherry picked from commit 526952b0bdb4b55ad6edd6c42355cd23a5352000) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0b6b402ea6..9e4b2665b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ If you are interested in starting to contribute to DOMjudge, you are most welcome. The following are some pointers. First, install and configure the development version of DOMjudge. -Either directly from the git repository, see the [developer information](https://www.domjudge.org/snapshot/manual/develop.html) +Either directly from the git repository, see the [developer information](https://www.domjudge.org/docs/manual/main/develop.html) section in the admin manual, or via the [contributor docker image](https://github.com/DOMjudge/domjudge-packaging/tree/main/docker-contributor). If you follow the admin manual for installation, this is also a great way to verify that the documentation is clear and complete, and to From d8601fb7adf3e66eb0bb21ba4469855fd81561d1 Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sun, 30 Apr 2023 12:53:50 +0200 Subject: [PATCH 13/80] Properly quote dirs in shell script. (#1997) (cherry picked from commit 9b4d4b5dbd296f87acafbdbafb7a5f3c55444407) --- judge/build_executable.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/judge/build_executable.sh b/judge/build_executable.sh index bc10ac2903..d5f77684c3 100755 --- a/judge/build_executable.sh +++ b/judge/build_executable.sh @@ -13,14 +13,14 @@ trap 'cleanup ; error' EXIT cleanup () { - $DJ_LIBJUDGEDIR/chroot-startstop.sh stop + "${DJ_LIBJUDGEDIR}/chroot-startstop.sh" stop # Make sure that all files are owned by the current user/group, so # that we can delete the judging output tree without root access. # We also remove group RUNGROUP so that this can safely be shared # across multiple judgedaemons, and remove write permissions. - $GAINROOT chown -R "$(id -un):" $WORKDIR - chmod -R go-w $WORKDIR + $GAINROOT chown -R "$(id -un):" "$WORKDIR" + chmod -R go-w "$WORKDIR" } cleanexit () @@ -66,10 +66,9 @@ if [ ! -d "$WORKDIR" ] || [ ! -w "$WORKDIR" ] || [ ! -x "$WORKDIR" ]; then fi [ -x "$RUNGUARD" ] || error "runguard not found or not executable: $RUNGUARD" -OLDDIR="$PWD" cd "$CHROOTDIR" -$DJ_LIBJUDGEDIR/chroot-startstop.sh start +"${DJ_LIBJUDGEDIR}/chroot-startstop.sh" start chmod a+rwx "$WORKDIR" From a80fe49426eb4fc5398d1fb51b4f3a793d50e497 Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sun, 30 Apr 2023 12:54:00 +0200 Subject: [PATCH 14/80] Properly quote dirs in compile.sh. (#1998) (cherry picked from commit f8f68a174996702c1f1d42b513f7544166118483) --- judge/compile.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/judge/compile.sh b/judge/compile.sh index 2c91417a7e..7b2b005318 100755 --- a/judge/compile.sh +++ b/judge/compile.sh @@ -124,7 +124,7 @@ touch compile.out compile.meta # Copy compile script into chroot # shellcheck disable=SC2174 mkdir -m 0777 -p "$WORKDIR/compile-script" -cp -a $(dirname $COMPILE_SCRIPT)/* $PWD/compile-script +cp -a "$(dirname "$COMPILE_SCRIPT")"/* "$WORKDIR/compile-script/" cd "$WORKDIR/compile" @@ -152,7 +152,7 @@ $GAINROOT "$RUNGUARD" ${DEBUG:+-v} $CPUSET_OPT -u "$RUNUSER" -g "$RUNGROUP" \ -r "$PWD/.." -d "/compile" \ -m $SCRIPTMEMLIMIT -t $SCRIPTTIMELIMIT -c -f $SCRIPTFILELIMIT -s $SCRIPTFILELIMIT \ -M "$WORKDIR/compile.meta" $ENVIRONMENT_VARS -- \ - "/compile-script/$(basename $COMPILE_SCRIPT)" program "$MEMLIMIT" "$@" >"$WORKDIR/compile.tmp" 2>&1 || \ + "/compile-script/$(basename "$COMPILE_SCRIPT")" program "$MEMLIMIT" "$@" >"$WORKDIR/compile.tmp" 2>&1 || \ exitcode=$? # Make sure that all files are owned by the current user/group, so From 05c67cde9b30b019b0f1ee343ea8f57ba2caba96 Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sun, 30 Apr 2023 13:28:02 +0200 Subject: [PATCH 15/80] Remove scope attribute for `td`. (#2000) It only applies for `th`, see https://www.w3schools.com/tags/att_scope.asp (cherry picked from commit 3572a8aba8220a1051c9a87092daeea1b54e793f) --- webapp/templates/jury/analysis/contest_overview.html.twig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webapp/templates/jury/analysis/contest_overview.html.twig b/webapp/templates/jury/analysis/contest_overview.html.twig index 05ce5a47c0..fbe6eeaf5d 100644 --- a/webapp/templates/jury/analysis/contest_overview.html.twig +++ b/webapp/templates/jury/analysis/contest_overview.html.twig @@ -205,10 +205,10 @@ $(function() { {% set id=j.submitid %} {{ id }} - {{ j.judgingid }} - {{ j.submittime | printtime }} - {{ j.num_judgings }} - {{ j.timediff | number_format(2) }}s + {{ j.judgingid }} + {{ j.submittime | printtime }} + {{ j.num_judgings }} + {{ j.timediff | number_format(2) }}s {% endfor %} From 95a8253749f008f5b66642f425fda00c1a05c89b Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sun, 30 Apr 2023 17:33:28 +0200 Subject: [PATCH 16/80] Repeat the cgroupv2 warning message as it would helped a user recently. (cherry picked from commit 60efd81557652ec05cebc4adbf76499af6917554) --- judge/create_cgroups.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/judge/create_cgroups.in b/judge/create_cgroups.in index 9be667510c..11f2855ac2 100755 --- a/judge/create_cgroups.in +++ b/judge/create_cgroups.in @@ -17,6 +17,8 @@ for i in cpuset memory; do To fix this, please make the following changes: 1. In /etc/default/grub, add 'cgroup_enable=memory swapaccount=1' to GRUB_CMDLINE_LINUX_DEFAULT + On modern distros (e.g. Debian bullseye and Ubuntu Jammy Jellyfish) which have cgroup v2 enabled by default, + you need to add 'systemd.unified_cgroup_hierarchy=0' as well. 2. Run update-grub 3. Reboot" >&2 exit 1 From 8c4ce131644765c6ac4a46fabae07be1c4ba799e Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 1 May 2023 12:20:46 +0200 Subject: [PATCH 17/80] Remove duplicate code for cgroup/grub instruction (cherry picked from commit f6f57362019b22f349fbd2cce3146f15bfdac0a7) --- judge/create_cgroups.in | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/judge/create_cgroups.in b/judge/create_cgroups.in index 11f2855ac2..1f9471d284 100755 --- a/judge/create_cgroups.in +++ b/judge/create_cgroups.in @@ -9,34 +9,31 @@ JUDGEHOSTUSER=@DOMJUDGE_USER@ CGROUPBASE=@judgehost_cgroupdir@ +print_cgroup_instruction () { + echo "" + echo "To fix this, please make the following changes: + 1. In /etc/default/grub, add 'cgroup_enable=memory swapaccount=1' to GRUB_CMDLINE_LINUX_DEFAULT. + On modern distros (e.g. Debian bullseye and Ubuntu Jammy Jellyfish) which have cgroup v2 enabled by default, + you need to add 'systemd.unified_cgroup_hierarchy=0' as well. + 2. Run update-grub + 3. Reboot" >&2 + exit 1 +} + for i in cpuset memory; do mkdir -p $CGROUPBASE/$i if [ ! -d $CGROUPBASE/$i/ ]; then if ! mount -t cgroup -o$i $i $CGROUPBASE/$i/; then - echo "Error: Can not mount $i cgroup. Probably cgroup support is missing from running kernel. Unable to continue. - - To fix this, please make the following changes: - 1. In /etc/default/grub, add 'cgroup_enable=memory swapaccount=1' to GRUB_CMDLINE_LINUX_DEFAULT - On modern distros (e.g. Debian bullseye and Ubuntu Jammy Jellyfish) which have cgroup v2 enabled by default, - you need to add 'systemd.unified_cgroup_hierarchy=0' as well. - 2. Run update-grub - 3. Reboot" >&2 - exit 1 + echo "Error: Can not mount $i cgroup. Probably cgroup support is missing from running kernel. Unable to continue." + print_cgroup_instruction fi fi mkdir -p $CGROUPBASE/$i/domjudge done if [ ! -f $CGROUPBASE/memory/memory.limit_in_bytes ] || [ ! -f $CGROUPBASE/memory/memory.memsw.limit_in_bytes ]; then - echo "Error: cgroup support missing memory features in running kernel. Unable to continue. - - To fix this, please make the following changes: - 1. In /etc/default/grub, add 'cgroup_enable=memory swapaccount=1' to GRUB_CMDLINE_LINUX_DEFAULT. - On modern distros (e.g. Debian bullseye and Ubuntu Jammy Jellyfish) which have cgroup v2 enabled by default, - you need to add 'systemd.unified_cgroup_hierarchy=0' as well. - 2. Run update-grub - 3. Reboot" >&2 - exit 1 + echo "Error: cgroup support missing memory features in running kernel. Unable to continue." + print_cgroup_instruction fi chown -R $JUDGEHOSTUSER $CGROUPBASE/*/domjudge From b8f47e4ae1d5953d1b04a887d191229454f1f50f Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sat, 6 May 2023 10:18:44 +0200 Subject: [PATCH 18/80] Clean up the cleanup (#2009) * Fix typo in judgehost cleanup usage. * Allow `pkill` to fail in judgehost cleanup. If you run the cleanup with `all` and there is no process to cleanup it would otherwise stop the cleanup here. (cherry picked from commit c9c2a8d8ceaa525dbb4928879b08caa243033e85) --- misc-tools/dj_judgehost_cleanup.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc-tools/dj_judgehost_cleanup.in b/misc-tools/dj_judgehost_cleanup.in index 06e5b61477..39ceebc7e6 100755 --- a/misc-tools/dj_judgehost_cleanup.in +++ b/misc-tools/dj_judgehost_cleanup.in @@ -40,7 +40,7 @@ EOF kill_processes() { echo "Killing remaining processes..." - pkill -G @RUNGROUP@ + pkill -G @RUNGROUP@ || true echo "Done." } @@ -76,7 +76,7 @@ cleanup_judgings() { if cut -d ' ' -f 2 /proc/mounts | grep -E "^$JUDGINGDIR/" >/dev/null 2>&1; then echo "There are (stale) bind mounts under $JUDGINGDIR/." echo "Make sure that all judgedaemons on this host are stopped, and then" - echo "run '$PROGNAME mount' to clean up any stale bind mounts." + echo "run '$PROGNAME mounts' to clean up any stale bind mounts." exit 1 fi echo "Cleaning up judging data..." From dd8ab3aa33900b4e40629a90742f7d56188bce3b Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Wed, 12 Apr 2023 08:43:47 +0200 Subject: [PATCH 19/80] Fix medal awards when skipping categories. Fixes #1982. (cherry picked from commit e47d33f2151466eb8165a346ad2a2fea6d4dc264) --- webapp/src/Service/AwardService.php | 31 +++-- .../tests/Unit/Service/AwardServiceTest.php | 117 +++++++++++++----- 2 files changed, 106 insertions(+), 42 deletions(-) diff --git a/webapp/src/Service/AwardService.php b/webapp/src/Service/AwardService.php index 6863109b84..57281ff4f8 100644 --- a/webapp/src/Service/AwardService.php +++ b/webapp/src/Service/AwardService.php @@ -60,8 +60,19 @@ protected function loadAwards(Contest $contest, Scoreboard $scoreboard): void $additionalBronzeMedals = $contest->getB() ?? 0; - // Can we assume this is ordered just walk the first 12+B entries? + $currentSortOrder = -1; + + // For every team that we skip because it is not in a medal category, we need to include one + // additional rank. So keep track of the number of skipped teams + $skippedTeams = 0; + foreach ($scoreboard->getScores() as $teamScore) { + // If we are checking a new sort order, reset the number of skipped teams + if ($teamScore->team->getCategory()->getSortorder() !== $currentSortOrder) { + $currentSortOrder = $teamScore->team->getCategory()->getSortorder(); + $skippedTeams = 0; + } + if ($teamScore->numPoints == 0) { continue; } @@ -70,13 +81,17 @@ protected function loadAwards(Contest $contest, Scoreboard $scoreboard): void if ($rank === 1) { $overall_winners[] = $teamid; } - if ($contest->getMedalsEnabled() && $contest->getMedalCategories()->contains($teamScore->team->getCategory())) { - if ($rank <= $contest->getGoldMedals()) { - $medal_winners['gold'][] = $teamid; - } elseif ($rank <= $contest->getGoldMedals() + $contest->getSilverMedals()) { - $medal_winners['silver'][] = $teamid; - } elseif ($rank <= $contest->getGoldMedals() + $contest->getSilverMedals() + $contest->getBronzeMedals() + $additionalBronzeMedals) { - $medal_winners['bronze'][] = $teamid; + if ($contest->getMedalsEnabled()) { + if ($contest->getMedalCategories()->contains($teamScore->team->getCategory())) { + if ($rank - $skippedTeams <= $contest->getGoldMedals()) { + $medal_winners['gold'][] = $teamid; + } elseif ($rank - $skippedTeams <= $contest->getGoldMedals() + $contest->getSilverMedals()) { + $medal_winners['silver'][] = $teamid; + } elseif ($rank - $skippedTeams <= $contest->getGoldMedals() + $contest->getSilverMedals() + $contest->getBronzeMedals() + $additionalBronzeMedals) { + $medal_winners['bronze'][] = $teamid; + } + } else { + $skippedTeams++; } } } diff --git a/webapp/tests/Unit/Service/AwardServiceTest.php b/webapp/tests/Unit/Service/AwardServiceTest.php index dbf833d303..2a871e0c1f 100644 --- a/webapp/tests/Unit/Service/AwardServiceTest.php +++ b/webapp/tests/Unit/Service/AwardServiceTest.php @@ -21,10 +21,10 @@ class AwardServiceTest extends KernelTestCase protected function setUp(): void { - // The contest will have 1 gold, 1 silver and 2 bronze medals + // The contest will have 2 gold, 2 silver and 2 bronze medals, awarded only to category A and C $this->contest = (new Contest()) ->setMedalsEnabled(true) - ->setGoldMedals(1) + ->setGoldMedals(2) ->setSilverMedals(1) ->setBronzeMedals(1); $categoryA = (new TeamCategory()) @@ -33,22 +33,33 @@ protected function setUp(): void $categoryB = (new TeamCategory()) ->setName('Category B') ->setExternalid('cat_B'); + $categoryC = (new TeamCategory()) + ->setName('Category C') + ->setExternalid('cat_C'); $this->contest ->addMedalCategory($categoryA) - ->addMedalCategory($categoryB); + ->addMedalCategory($categoryC); $reflectedProblem = new ReflectionClass(TeamCategory::class); - $teamIdProperty = $reflectedProblem->getProperty('categoryid'); - $teamIdProperty->setAccessible(true); - $teamIdProperty->setValue($categoryA, 1); - $teamIdProperty->setValue($categoryB, 2); + $categoryIdProperty = $reflectedProblem->getProperty('categoryid'); + $categoryIdProperty->setAccessible(true); + $categoryIdProperty->setValue($categoryA, 1); + $categoryIdProperty->setValue($categoryB, 2); + $categoryIdProperty->setValue($categoryC, 3); $categories = [$categoryA, $categoryB]; - // Create 4 teams, each belonging to a category + // Create 9 teams, each belonging to a different category $teams = []; - foreach (['A', 'B', 'C', 'D'] as $teamLetter) { + foreach (['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] as $teamLetter) { + $category = $categoryC; + if (in_array($teamLetter, ['A', 'B', 'C'])) { + $category = $categoryA; + } + if (in_array($teamLetter, ['D', 'E', 'F'])) { + $category = $categoryB; + } $team = (new Team()) ->setName('Team ' . $teamLetter) ->setExternalid('team_' . $teamLetter) - ->setCategory(in_array($teamLetter, ['A', 'B']) ? $categoryA : $categoryB) + ->setCategory($category) ->setAffiliation(); // No affiliation needed $reflectedProblem = new ReflectionClass(Team::class); $teamIdProperty = $reflectedProblem->getProperty('teamid'); @@ -81,16 +92,25 @@ protected function setUp(): void // -----+----------- // A | 1 5 10 20 // B | x 2 3 x - // C | x x x 4 - // D | x x x x + // C | x 2 3 x + // D | x x x 12 + // E | x x x 13 + // F | x x x 14 + // G | x x x 15 + // H | x x x x + // I | x x x x // // THis means A is the overall winner, will get a gold medal and is the winner // of category A. It is also first to solve problem A. - // B is second, so it gets a silver medal. It is also first to solve problem B and C - // C is the first to solve problem D, gets a bronze medal and is winner of category B. - // D didn't solve anything, so it will not get any medals at all + // B is second, so it also gets a gold medal. It is also first to solve problem B and C + // C scored the exact same as B, so it also gets the same medals + // D is the first to solve problem D and is the winner of category B. But will not get any medal. + // E and F will get no awards at all. + // G is the winner of category C and will get a bronze medal. + // The reason G doesn't get silver is that C would get silver if it was ranked differently, + // but it is not. + // H and I didn't solve anything, so it will not get any medals at all - $minute = 60; // Indexed first by team, then by problem $scores = [ 'A' => [ @@ -104,7 +124,20 @@ protected function setUp(): void 'C' => 3, ], 'C' => [ - 'D' => 4, + 'B' => 2, + 'C' => 3, + ], + 'D' => [ + 'D' => 12, + ], + 'E' => [ + 'D' => 13, + ], + 'F' => [ + 'D' => 14, + ], + 'G' => [ + 'D' => 15, ], ]; $scoreCache = []; @@ -112,7 +145,7 @@ protected function setUp(): void foreach ($scoresForTeam as $problemLabel => $minute) { $firstToSolve = in_array( $teamLabel . $problemLabel, - ['AA', 'BB', 'BC', 'CD'] + ['AA', 'BB', 'BC', 'CB', 'CC', 'DD'] ); $scoreCache[] = (new ScoreCache()) ->setContest($this->contest) @@ -164,15 +197,19 @@ public function testWinner(): void public function testMedals(): void { $medals = [ - 'gold' => 'team_A', - 'silver' => 'team_B', - 'bronze' => 'team_C', + 'gold' => ['team_A', 'team_B', 'team_C'], + 'silver' => [], + 'bronze' => ['team_G'], ]; - foreach ($medals as $medal => $team) { + foreach ($medals as $medal => $teams) { $medalAward = $this->getAward($medal . '-medal'); - static::assertNotNull($medalAward); - static::assertEquals(ucfirst($medal) . ' medal winner', $medalAward['citation']); - static::assertEquals([$team], $medalAward['team_ids']); + if (empty($teams)) { + static::assertNull($medalAward); + } else { + static::assertNotNull($medalAward); + static::assertEquals(ucfirst($medal) . ' medal winner', $medalAward['citation']); + static::assertEquals($teams, $medalAward['team_ids']); + } } } @@ -187,22 +224,29 @@ public function testGroupWinners(): void $groupBWinner = $this->getAward('group-winner-cat_B'); static::assertNotNull($groupBWinner); static::assertEquals('Winner(s) of group Category B', $groupBWinner['citation']); - static::assertEquals(['team_C'], $groupBWinner['team_ids']); + static::assertEquals(['team_D'], $groupBWinner['team_ids']); + + $a = $this->getAwardService()->getAwards($this->contest, $this->scoreboard); + $groupBWinner = $this->getAward('group-winner-cat_C'); + static::assertNotNull($groupBWinner); + static::assertEquals('Winner(s) of group Category C', $groupBWinner['citation']); + static::assertEquals(['team_G'], $groupBWinner['team_ids']); } public function testFirstToSolve(): void { $fts = [ - 'A' => 'A', - 'B' => 'B', - 'C' => 'B', - 'D' => 'C', + 'A' => ['A'], + 'B' => ['B', 'C'], + 'C' => ['B', 'C'], + 'D' => ['D'], ]; - foreach ($fts as $problem => $team) { + foreach ($fts as $problem => $teams) { $firstToSolve = $this->getAward('first-to-solve-problem_' . $problem); static::assertNotNull($firstToSolve); static::assertEquals('First to solve problem ' . $problem, $firstToSolve['citation']); - static::assertEquals(['team_' . $team], $firstToSolve['team_ids']); + $teamIds = array_map(static fn(string $team) => 'team_' . $team, $teams); + static::assertEquals($teamIds, $firstToSolve['team_ids']); } } @@ -219,8 +263,13 @@ public function testMedalType(int $teamIndex, ?string $expectedMedalType) public function provideMedalType(): \Generator { yield [0, 'gold-medal']; - yield [1, 'silver-medal']; - yield [2, 'bronze-medal']; + yield [1, 'gold-medal']; + yield [2, 'gold-medal']; yield [3, null]; + yield [4, null]; + yield [5, null]; + yield [6, 'bronze-medal']; + yield [7, null]; + yield [8, null]; } } From 238fb2f7fdc75e5722aabafe9f9b0eb988529ec7 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Wed, 3 May 2023 10:21:57 +0200 Subject: [PATCH 20/80] Add forgotten compiled file We ignore this in the .gitignore but the submission needs this to test if we can submit compiled code and have a working submission. (cherry picked from commit 41180b94c5cb040261d0e717367363ab641e27c5) --- .../compiler_error/objectcode/message.o | Bin 0 -> 4000 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 example_problems/hello/submissions/compiler_error/objectcode/message.o diff --git a/example_problems/hello/submissions/compiler_error/objectcode/message.o b/example_problems/hello/submissions/compiler_error/objectcode/message.o new file mode 100644 index 0000000000000000000000000000000000000000..9f8a565eac2982dddac9adbc77c717f48be7080f GIT binary patch literal 4000 zcmbVOPiz!b7=PQP{820gK~V%3L$oG#)5Sv3C@GYoyJ=IKPWOV6$8>h=4s3Utnc1>! z(x7Q#*cc)=qg=RXNW6G79)P3-|HOmgpd3kz2@w{p^Tk+yrmBcb&zdkU96aI{A%Wxe(%XQ7H{W2G;Ze` z-`vG|{(^D8r5Ep$ednrJPy~=K6z}94Kec!UnQQ&;4dffk2%r}4r6Zt~LC@T16|r=q z=k1fr7f~e@*-b^RP?0P7#?5P}MO3<~s_&K+x3T!3QCnGBe2}WW^#0;Xv&mR(Ps{6T z_zTw-7CB!9^%`#C-7lNX=E-F+^G>DWWzKqjrL-5el4ditV|yoK2RiF4-#N`DY5pWd zKwO50hF;I~9CM~ztD5Q0zLwqJo9lZy(un(<*@zr8_PWk)Z9sNm2_UN=o@7zRK|m2+DUl^26F2z)9Z3MXlFc z>+b+3*@25%ACJ~qHkh9YttpyAKbp%*^PP&74V`+(vL!3DSavE1SXQ9E7a`NO&7HdK z%!ZttD~?=tt8U0G-?!#j*7jy*oGQhrdZCjY9xL_+p=F^{p8Pr9Dcpt?SsI zw8Lv9o%rU^CeSZQ($OxgTG~ujO2d&)Ntz`*7qpmW8x-Z?yonqtcN3n}SFglBr#ukxF426XO`MT7_{VMVTW#=P+Ti~J z?+~S|x@;sYsozW+yqECIstD4Uae}~_cCxn3_z5!{J;b@|;k_iYKgT(}grRG5Ag)z$ z7s&Fe+^Uv%$)N+FW(&K|br~NXee39vQF5tG@dD>3#s*~Yq5Z}jg*!2tqv+FN*>|iG zx5#tO;j?qb{=T(n=#xV%0H3bc`K;pyUX>~d=lNV8NMii66ktry!mCqOKzGxlJLgz4g-Jfy#|?9UQ&Cd|v!9y>_+*Y7B38dsEme}j zJtERUE?V;{fiZr3!t_iLYs?G}xn962xzk^uos8}gF9jYi(^k@XjQbcPMR$bTb&Fec zy5ou9vvTv!IP=`57D9C(t8)sE>Q)*L=*tS(D<3o9+cZ2Yahy2orH<*K)WLs}hKf_r zaC`$5Ues{Zpm0mWpVDw&!*%|WhU@%~G+gI@s^L$QuJVe%9b}`gXC()d_!B}i`oh_- z_%}$0fUmyauz$dX1pM7J6#ox^B;bqx2*P6QFFAw1hlb++BXRJbmpUf(fsDslN9PR$ zcm|4;O%g}^y);yObp~Pi1 zeo^A_e=wz3UP%`*l#UtSH^gk`9}g3^@xB6!_f?ieRVPt|sQQ(S{Y~osGB%t<`J;dQ zyHfrNKTKFs{`X}5XJ}m)2|t92q;=7V_kURuRX*hqx5sHAss67L>W8oLSM^(jAypp@ zU9QOdc$amNuezY&@(hC literal 0 HcmV?d00001 From dd34430d51efe4e3ec252053a5ca50d1df7ab0b1 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Tue, 2 May 2023 20:51:55 +0200 Subject: [PATCH 21/80] The tags would be ignored in the original directory (cherry picked from commit 0bae64b8c4c52cc29c00dc137a796d6ae9914b77) --- .../hello/submissions/{accepted => multiple}/test-hello-space.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename example_problems/hello/submissions/{accepted => multiple}/test-hello-space.c (100%) diff --git a/example_problems/hello/submissions/accepted/test-hello-space.c b/example_problems/hello/submissions/multiple/test-hello-space.c similarity index 100% rename from example_problems/hello/submissions/accepted/test-hello-space.c rename to example_problems/hello/submissions/multiple/test-hello-space.c From 55865dfeb58917578ee8a3ddb33d61be4b4dae13 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sat, 6 May 2023 13:42:48 +0200 Subject: [PATCH 22/80] Fix typo (cherry picked from commit bca3b033b003b30cbdb5deface7f2f8870086189) --- webapp/tests/Unit/Service/AwardServiceTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/tests/Unit/Service/AwardServiceTest.php b/webapp/tests/Unit/Service/AwardServiceTest.php index 2a871e0c1f..7baf6982aa 100644 --- a/webapp/tests/Unit/Service/AwardServiceTest.php +++ b/webapp/tests/Unit/Service/AwardServiceTest.php @@ -100,7 +100,7 @@ protected function setUp(): void // H | x x x x // I | x x x x // - // THis means A is the overall winner, will get a gold medal and is the winner + // This means A is the overall winner, will get a gold medal and is the winner // of category A. It is also first to solve problem A. // B is second, so it also gets a gold medal. It is also first to solve problem B and C // C scored the exact same as B, so it also gets the same medals From 41a958f1d6f9250b52dbc7e57e0d8c4de57e07fe Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 6 May 2023 14:11:26 +0200 Subject: [PATCH 23/80] Set the default domjudge_user to the current user at configure time. Before, the use of `m4_esyscmd` would set the default to the current user at the time configure is generated, which typically happens when we create a release (or snapshot). The `id` command used should be POSIX portable. Closes #1980 (cherry picked from commit 6450b8192a74c32a46abf35def5c938f408bf948) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 41d005b8a0..dcb28637e7 100644 --- a/configure.ac +++ b/configure.ac @@ -65,7 +65,7 @@ AC_ARG_WITH([domjudge-user], [AS_HELP_STRING([--with-domjudge-user=USER], [User that owns password files (default: current user).])], [], []) if test "x$with_domjudge_user" = x; then - user=m4_esyscmd([id -un]) + user="$(id -un)" # Check and warn if running as root (without explicitly setting it): if test "x$user" = xroot; then AC_MSG_ERROR([installing/running as root is STRONGLY DISCOURAGED, use --with-domjudge-user=root to override.]) From 53ab6cfa294521b7e7a338db1e435c6610f7043f Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 6 May 2023 14:13:07 +0200 Subject: [PATCH 24/80] Add some checks on domjudge_user and runuser. They should not be the same, and neither should be equal to root, but definitely runuser should not be as it is the unprivileged user that submissions are run as. For domjudge_user there is already a (overridable) check that it is not root. (cherry picked from commit d9c298f2d168926ed4adb9cde24413654dc23804) --- configure.ac | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configure.ac b/configure.ac index dcb28637e7..b1cd8bbff2 100644 --- a/configure.ac +++ b/configure.ac @@ -117,6 +117,13 @@ else AC_MSG_RESULT($RUNUSER) fi +if test "x${DOMJUDGE_USER#"$RUNUSER"}" != "x$DOMJUDGE_USER" ; then + AC_MSG_ERROR([domjudge_user '$DOMJUDGE_USER' cannot match runuser '$RUNUSER'.]) +fi +if test "x$RUNUSER" = "xroot" ; then + AC_MSG_ERROR([runuser cannot be root.]) +fi + AC_MSG_CHECKING([rungroup]) AC_ARG_WITH([rungroup], [AS_HELP_STRING([--with-rungroup=GROUP], [Unprivileged group under which to run submissions (default: same as runuser).])], [], []) From 6d4927fafdecb8572758c678498672d05cc34af2 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 6 May 2023 17:42:11 +0200 Subject: [PATCH 25/80] Use correct variable for uploading JSON to API in Python helper. (cherry picked from commit 438f6bb1ce1590e2376c2fedc83a863db6b21f72) --- misc-tools/dj_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-tools/dj_utils.py b/misc-tools/dj_utils.py index 17956a469b..497f1edcc0 100644 --- a/misc-tools/dj_utils.py +++ b/misc-tools/dj_utils.py @@ -75,7 +75,7 @@ def do_api_request(name: str, method: str = 'GET', jsonData: dict = {}): if method == 'GET': response = requests.get(url, headers=headers, verify=ca_check) elif method == 'PUT': - response = requests.put(url, headers=headers, verify=ca_check, json=json) + response = requests.put(url, headers=headers, verify=ca_check, json=jsonData) except requests.exceptions.SSLError as e: ca_check = not confirm( "Can not verify certificate, ignore certificate check?", False) From d093f90ffd800dea3e4c4c9109bf6bacf487ff9d Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sun, 7 May 2023 12:54:41 +0200 Subject: [PATCH 26/80] Use correct check for handled clarification filtering. (cherry picked from commit 8afedccb540fef1c5a8ada49e88eb80a37fd8d7e) --- webapp/templates/jury/clarifications.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/templates/jury/clarifications.html.twig b/webapp/templates/jury/clarifications.html.twig index d06d57ef57..c8c1eded26 100644 --- a/webapp/templates/jury/clarifications.html.twig +++ b/webapp/templates/jury/clarifications.html.twig @@ -81,7 +81,7 @@ {%- endif %} {% endif %} - {% if currentFilter is null or currentFilter == 'old' %} + {% if currentFilter is null or currentFilter == 'handled' %}

Handled requests

{%- if oldClarifications | length == 0 %}

No old clarification requests.

From 0cf958b82fe3d10e2231a80718d40bfc9e3249c5 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sun, 7 May 2023 10:57:51 +0200 Subject: [PATCH 27/80] Do not allow to delete problems from a locked contest in the UI. Fixes #2017 (cherry picked from commit 8110fa84e0d902df85102f4778af9d460d29c057) --- webapp/src/Controller/Jury/ProblemController.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index fb345628ec..536c6fb928 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -158,7 +158,15 @@ public function indexAction(): Response 'probId' => $p->getProbid(), ]) ]; - $problemactions[] = [ + + $problemIsLocked = false; + foreach ($p->getContestProblems() as $contestProblem) { + if ($contestProblem->getContest()->isLocked()) { + $problemIsLocked = true; + } + } + + $deleteAction = [ 'icon' => 'trash-alt', 'title' => 'delete this problem', 'link' => $this->generateUrl('jury_problem_delete', [ @@ -166,6 +174,12 @@ public function indexAction(): Response ]), 'ajaxModal' => true, ]; + if ($problemIsLocked) { + $deleteAction['title'] .= ' - problem belongs to a locked contest'; + $deleteAction['disabled'] = true; + unset($deleteAction['link']); + } + $problemactions[] = $deleteAction; } // Add formatted {mem,output}limit row data for the table. From db318fb235a08601c00fd356b74527771bd748e1 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sun, 7 May 2023 18:21:05 +0200 Subject: [PATCH 28/80] When a contest is locked, it doesn't have any actions. (cherry picked from commit ea714595eb5ddce51e312c21143bdef791e604e7) --- webapp/src/Controller/Jury/ContestController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/ContestController.php b/webapp/src/Controller/Jury/ContestController.php index 12ef2dab07..0bfe46e49b 100644 --- a/webapp/src/Controller/Jury/ContestController.php +++ b/webapp/src/Controller/Jury/ContestController.php @@ -379,7 +379,7 @@ public function indexAction(Request $request): Response 'upcoming_contest' => $upcomingContest, 'contests_table' => $contests_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 2 : 0, + 'num_actions' => $this->isGranted('ROLE_ADMIN') && !$contest->isLocked() ? 2 : 0, ]); } From 934a5917140bf0ce52a66b40e28b6615530df704 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 6 May 2023 23:19:17 +0200 Subject: [PATCH 29/80] Bugfix: add an error message level. This way the error coming from the exception is actually displayed. (cherry picked from commit 456afe63dcc6f2dd507d7a6493a604f29b2504eb) --- webapp/src/Controller/Jury/ImportExportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/ImportExportController.php b/webapp/src/Controller/Jury/ImportExportController.php index 8d5629b01c..f1fa4f9b8f 100644 --- a/webapp/src/Controller/Jury/ImportExportController.php +++ b/webapp/src/Controller/Jury/ImportExportController.php @@ -188,7 +188,7 @@ public function indexAction(Request $request): Response return $this->redirectToRoute('jury_problems'); } } catch (Exception $e) { - $allMessages[] = $e->getMessage(); + $allMessages['danger'][] = $e->getMessage(); } finally { if (isset($zip)) { $zip->close(); From fc3e341ec39b9d9fc3b4358f10ecf71432c38e5c Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 7 May 2023 10:37:46 +0200 Subject: [PATCH 30/80] Disallow submitting to a problem when it does not have testcases at import. Closes #1777 (cherry picked from commit ecb2204994a9c8a8b0404339fe3f50cf31c87bde) --- webapp/src/Service/ImportProblemService.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/webapp/src/Service/ImportProblemService.php b/webapp/src/Service/ImportProblemService.php index 0569d5204a..01b845faa0 100644 --- a/webapp/src/Service/ImportProblemService.php +++ b/webapp/src/Service/ImportProblemService.php @@ -818,6 +818,20 @@ public function importZippedProblem( $messages['info'][] = sprintf('Saved problem %d', $problem->getProbid()); + // Only here disable problem submit to make sure the jury submissions + // do get added above. + if ($contestProblem) { + $this->em->flush(); + $testcases = $problem->getTestcases()->toArray(); + if (count(array_filter($testcases, function($t) { return !$t->getDeleted(); }))==0) { + $messages['danger'][] = 'No testcases present, disabling submitting for this problem'; + $contestProblem->setAllowSubmit(false); + } + } + + // Make sure we persisted all changes to DB + $this->em->flush(); + return $problem; } From 1ab0b57963ec498a828d30fa5d23cbf3c81a326d Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Mon, 8 May 2023 11:12:26 +0200 Subject: [PATCH 31/80] Also force removing lib/judge as directory. With a maintainer/inplace install, this should normally be a symlink, but if the inplace-install rule failed halfway, then the directory would have been created by the judgehost-create-dirs rule, but not been replaced by the inplace-install-l rule afterwards. (cherry picked from commit 9153aca09b186bce25264b418d6df6b3f56c31fe) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 75abd7d29f..4c4eacf293 100644 --- a/Makefile +++ b/Makefile @@ -285,7 +285,7 @@ inplace-postinstall-nginx: inplace-postinstall-permissions # Removes created symlinks; generated logs, submissions, etc. remain in output subdir. inplace-uninstall-l: - rm -f $(judgehost_libjudgedir) + rm -rf $(judgehost_libjudgedir) rm -rf $(judgehost_bindir) # Rules to configure and build for a Coverity scan. From dbc1128c3f420545c84907392aae963ee8db38af Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Mon, 8 May 2023 18:17:09 +0200 Subject: [PATCH 32/80] Fix handling of binary files when editing executables. (#2043) Fixes https://github.com/DOMjudge/domjudge/issues/1841. (cherry picked from commit 6e099ab99f7cef06ed27530d6fb27db90861901f) --- .../Controller/Jury/ExecutableController.php | 17 ++++++++++++++++- webapp/templates/jury/executable.html.twig | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/webapp/src/Controller/Jury/ExecutableController.php b/webapp/src/Controller/Jury/ExecutableController.php index 676073187f..97b0b31592 100644 --- a/webapp/src/Controller/Jury/ExecutableController.php +++ b/webapp/src/Controller/Jury/ExecutableController.php @@ -241,6 +241,18 @@ public function viewAction(Request $request, string $execId): Response $this->em->persist($executableFile); $files[] = $executableFile; } + $offset = count($files); + foreach ($editorData['skippedBinary'] as $idx => $skippedBinaryData) { + $origExecutableFile = $this->em->getRepository(ExecutableFile::class)->find($skippedBinaryData['execfileid']); + $executableFile = new ExecutableFile(); + $executableFile + ->setRank($idx + $offset) + ->setIsExecutable($origExecutableFile->isExecutable()) + ->setFilename($origExecutableFile->getFilename()) + ->setFileContent($origExecutableFile->getFileContent()); + $this->em->persist($executableFile); + $files[] = $executableFile; + } $immutableExecutable = new ImmutableExecutable($files); $this->em->persist($immutableExecutable); @@ -436,7 +448,10 @@ protected function dataForEditor(Executable $executable): array $content = $file->getFileContent(); $rank = $file->getRank(); if (!mb_detect_encoding($content, null, true)) { - $skippedBinary[] = $filename; + $skippedBinary[] = [ + 'filename' => $filename, + 'execfileid' => $file->getExecFileId(), + ]; continue; // Skip binary files. } $filenames[] = $filename; diff --git a/webapp/templates/jury/executable.html.twig b/webapp/templates/jury/executable.html.twig index a5f041b8a9..15a07a295f 100644 --- a/webapp/templates/jury/executable.html.twig +++ b/webapp/templates/jury/executable.html.twig @@ -82,8 +82,8 @@
We exclude these files from editing since we could not detect their encoding (e.g. they are binary files):
    - {% for file in skippedBinary %} -
  • {{ file }}
  • + {% for data in skippedBinary %} +
  • {{ data.filename }}
  • {% endfor %}
From 646b7bfd005fe36b664f7161e29247a6471b4d01 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Mon, 8 May 2023 18:48:12 +0200 Subject: [PATCH 33/80] Show the raw response if JSON decoding fails. This may happen for example when PHP runs out of memory. (cherry picked from commit 1c297a587291ae3f511390e7e9d88308b06ed46b) --- misc-tools/dj_utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/misc-tools/dj_utils.py b/misc-tools/dj_utils.py index 497f1edcc0..0d63cbd714 100644 --- a/misc-tools/dj_utils.py +++ b/misc-tools/dj_utils.py @@ -44,7 +44,13 @@ def parse_api_response(name: str, response: requests.Response): return None # We got a successful HTTP response. It worked. Return the full response - return json.loads(response.text) + try: + result = json.loads(response.text) + except json.decoder.JSONDecodeError as e: + print(response.text) + raise RuntimeError(f'Failed to JSON decode the response for API request {name}') + + return result def do_api_request(name: str, method: str = 'GET', jsonData: dict = {}): From b61294fbf71fcfcc0d2a532d06a1c21449c8dd8d Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Mon, 8 May 2023 18:40:07 +0200 Subject: [PATCH 34/80] Recalculate all immutable hashes since the algorithm changed in the past. Fixes #1826 (cherry picked from commit c920919ba780f00aca739ef9905162de01b5ec6b) --- webapp/migrations/Version20230508163415.php | 51 +++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 webapp/migrations/Version20230508163415.php diff --git a/webapp/migrations/Version20230508163415.php b/webapp/migrations/Version20230508163415.php new file mode 100644 index 0000000000..9cef0b66ba --- /dev/null +++ b/webapp/migrations/Version20230508163415.php @@ -0,0 +1,51 @@ +connection->fetchAllAssociative('SELECT immutable_execid FROM immutable_executable'); + foreach ($immutableExecutables as $immutableExecutable) { + $files = $this->connection->fetchAllAssociative('SELECT hash, filename, is_executable FROM executable_file WHERE immutable_execid = :id', ['id' => $immutableExecutable['immutable_execid']]); + uasort($files, fn(array $a, array $b) => strcmp($a['filename'], $b['filename'])); + $newHash = md5( + join( + array_map( + fn(array $file) => $file['hash'] . $file['filename'] . (bool)$file['is_executable'], + $files + ) + ) + ); + $this->connection->executeQuery('UPDATE immutable_executable SET hash = :hash WHERE immutable_execid = :id', [ + 'hash' => $newHash, + 'id' => $immutableExecutable['immutable_execid'], + ]); + } + } + + public function down(Schema $schema): void + { + // We don't handle this case + } + + public function isTransactional(): bool + { + return false; + } +} From fd8506d30293b6635ff1d68c3e4f2042d5fff1c3 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Mon, 8 May 2023 17:55:09 +0200 Subject: [PATCH 35/80] Make problem.externalid a unique key. This was only meant to be unique per contest, but this caused subtle issues with the POST /api/problems endpoint. In that case, there might be multiple problems with the given externalid and if this is used as external problem ID, then that would fail. Note that removing the UniqueEntity message just means that a default message about duplicate keys will be shown e.g. in forms when you try to add one. This is consistent with the settings we have for other entities. In more detail: If there is already a problem with externalid `foo`, but not associated to any contest, and you try to add a contest that also contains a problem with externalid `foo`, then first that problem gets created (which works), but after that when data is loaded at https://github.com/DOMjudge/domjudge/blob/8231f1291effadb328161462dd86a9f5223fc025/webapp/src/Service/ImportProblemService.php#L856-L859 if `externalIdFieldForEntity` is `externalid`, `getOneOrNullResult` throws an exception. I tried fixing this case by adding a check on the same contest, but this code is also called from POST /api/problems without the context of a contest. In that case it becomes unclear how to handle this, especially if there are already multiple problems with that externalid: should it create a new one or edit (which?) one of the existing ones? To avoid this complication I decided it is easier to just have a unique external ID across problems globally. (cherry picked from commit 6ace309422f5e9e7e65469a3048146218f52224e) --- webapp/migrations/Version20230508153514.php | 38 +++++++++++++++++++++ webapp/src/Entity/Problem.php | 6 ++++ 2 files changed, 44 insertions(+) create mode 100644 webapp/migrations/Version20230508153514.php diff --git a/webapp/migrations/Version20230508153514.php b/webapp/migrations/Version20230508153514.php new file mode 100644 index 0000000000..34e0edee79 --- /dev/null +++ b/webapp/migrations/Version20230508153514.php @@ -0,0 +1,38 @@ +addSql('DROP INDEX externalid ON problem'); + $this->addSql('CREATE UNIQUE INDEX externalid ON problem (externalid(190))'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX externalid ON problem'); + $this->addSql('CREATE INDEX externalid ON problem (externalid(190))'); + } + + public function isTransactional(): bool + { + return false; + } +} diff --git a/webapp/src/Entity/Problem.php b/webapp/src/Entity/Problem.php index d3364e3e2b..15fcc9edac 100644 --- a/webapp/src/Entity/Problem.php +++ b/webapp/src/Entity/Problem.php @@ -20,6 +20,12 @@ * @ORM\Entity() * @ORM\Table( * name="problem", + * uniqueConstraints={ + * @ORM\UniqueConstraint( + * name="externalid", + * columns={"externalid"} + * ) + * }, * options={"collation"="utf8mb4_unicode_ci", "charset"="utf8mb4","comment"="Problems the teams can submit solutions for"}, * indexes={ * @ORM\Index(name="externalid", columns={"externalid"}, options={"lengths": {190}}), From c2b36f516abd8634fa32c24bdc5544be368809c3 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sat, 13 May 2023 14:42:11 +0200 Subject: [PATCH 36/80] Recreate cache for branch --- gitlab/ci/template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitlab/ci/template.yml b/gitlab/ci/template.yml index 242395d1c4..f59cd5ec41 100644 --- a/gitlab/ci/template.yml +++ b/gitlab/ci/template.yml @@ -27,7 +27,7 @@ .cached_vendor: extends: [.clean_ordering] cache: - key: libvendor-260522 + key: libvendor-82 paths: - lib/vendor/ From 285ec9f98cad054e28f6723e3574c0db13d211e5 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 8 Apr 2023 11:56:21 +0200 Subject: [PATCH 37/80] Only set internal error on judging if we have one. Diskspace errors are not linked to any judging. (cherry picked from commit ab07c2b617730ad81415a56692f24ff6ebd105d6) --- webapp/src/Controller/API/JudgehostController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/src/Controller/API/JudgehostController.php b/webapp/src/Controller/API/JudgehostController.php index a2303a6d90..a9c4a5e0a2 100644 --- a/webapp/src/Controller/API/JudgehostController.php +++ b/webapp/src/Controller/API/JudgehostController.php @@ -820,7 +820,9 @@ public function internalErrorAction(Request $request): ?int $this->em->persist($error); // Even if there are no remaining judge tasks for this judging open (which is covered by the transaction below), // we need to mark this judging as internal error. - $judging->setInternalError($error); + if ($judging) { + $judging->setInternalError($error); + } $this->em->flush(); if ($field_name !== null) { From 675db71f36963b42e28bde0f74ec4cbcb202e134 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 8 Apr 2023 11:58:10 +0200 Subject: [PATCH 38/80] Use left join for affected judgings since they might not exist. (cherry picked from commit 7c169ae5f66c59f98fa7ec0cb1a4faf496cfac96) --- webapp/src/Controller/Jury/InternalErrorController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/InternalErrorController.php b/webapp/src/Controller/Jury/InternalErrorController.php index 973fd6eed2..9324d324b7 100644 --- a/webapp/src/Controller/Jury/InternalErrorController.php +++ b/webapp/src/Controller/Jury/InternalErrorController.php @@ -153,7 +153,7 @@ public function handleAction(Request $request, ?Profiler $profiler, int $errorId /** @var InternalError $internalError */ $internalError = $this->em->createQueryBuilder() ->from(InternalError::class, 'e') - ->join('e.affectedJudgings', 'j') + ->leftJoin('e.affectedJudgings', 'j') ->join('j.submission', 's') ->join('j.contest', 'c') ->join('s.team', 't') From 96a15ab78dae52a4026c46a087d0707a16c864b9 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 8 Apr 2023 12:10:35 +0200 Subject: [PATCH 39/80] Add more left joins for internal error judging tables since they all depend on judgings. Also fix logic when we have no affected judgings. (cherry picked from commit 9a05f117ddd8714887b393cb97541c2b6ca3a242) --- webapp/src/Controller/Jury/InternalErrorController.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/webapp/src/Controller/Jury/InternalErrorController.php b/webapp/src/Controller/Jury/InternalErrorController.php index 9324d324b7..929af2f292 100644 --- a/webapp/src/Controller/Jury/InternalErrorController.php +++ b/webapp/src/Controller/Jury/InternalErrorController.php @@ -154,9 +154,9 @@ public function handleAction(Request $request, ?Profiler $profiler, int $errorId $internalError = $this->em->createQueryBuilder() ->from(InternalError::class, 'e') ->leftJoin('e.affectedJudgings', 'j') - ->join('j.submission', 's') - ->join('j.contest', 'c') - ->join('s.team', 't') + ->leftJoin('j.submission', 's') + ->leftJoin('j.contest', 'c') + ->leftJoin('s.team', 't') ->leftJoin('s.rejudging', 'r') ->select('e, j, s, c, t, r') ->where('e.errorid = :id') @@ -195,7 +195,7 @@ public function handleAction(Request $request, ?Profiler $profiler, int $errorId sprintf('internal error: %s', InternalErrorStatusType::STATUS_RESOLVED)); $affectedJudgings = $internalError->getAffectedJudgings(); - if (!empty($affectedJudgings)) { + if (!$affectedJudgings->isEmpty()) { $skipped = []; $rejudging = $this->rejudgingService->createRejudging( 'Internal Error ' . $internalError->getErrorid() . ' resolved', @@ -220,6 +220,8 @@ public function handleAction(Request $request, ?Profiler $profiler, int $errorId ); $progressReporter(100, '', $message); } + } else { + $progressReporter(100, '', 'No affected judgings.'); } }); }); From a217393a552f59ca6725e3d43cb2edaefb39d529 Mon Sep 17 00:00:00 2001 From: Thijs Kinkhorst Date: Fri, 5 May 2023 13:11:24 +0000 Subject: [PATCH 40/80] Fix executions table th mismatch (cherry picked from commit 7727c930cb8df76615867af563453c685bcf1d8b) --- webapp/src/Controller/Jury/ExecutableController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/ExecutableController.php b/webapp/src/Controller/Jury/ExecutableController.php index 97b0b31592..f80f732a65 100644 --- a/webapp/src/Controller/Jury/ExecutableController.php +++ b/webapp/src/Controller/Jury/ExecutableController.php @@ -116,7 +116,7 @@ public function indexAction(Request $request): Response return $this->render('jury/executables.html.twig', [ 'executables' => $executables_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 3 : 0, + 'num_actions' => count($execactions), 'form' => $form->createView(), ]); } From 57bbb13975df59fc66868f538aa2a0ca405f3750 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Mon, 6 Mar 2023 23:22:45 +0100 Subject: [PATCH 41/80] Fix logic error and update the comment. This formulation requires less negations, which tends to be a source of mistakes interpreting logical expressions. (cherry picked from commit 46449e88870e2212f9bef00284192b2b763714bc) --- webapp/src/Controller/API/JudgementController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/Controller/API/JudgementController.php b/webapp/src/Controller/API/JudgementController.php index 9a587aa68a..462bd7a135 100644 --- a/webapp/src/Controller/API/JudgementController.php +++ b/webapp/src/Controller/API/JudgementController.php @@ -150,9 +150,9 @@ protected function getQueryBuilder(Request $request): QueryBuilder $specificJudgingRequested = $request->attributes->has('id') || $request->query->has('ids'); - // If we don't have correct permissions or didn't request a specific - // judging (necessary for the event log), then exclude some judgings: - if (!$roleAllowsVisibility && !$specificJudgingRequested) { + // Only include invalid or too late submissions if the role allows it + // and we request these specific submissions. + if (!($roleAllowsVisibility && $specificJudgingRequested)) { $queryBuilder ->andWhere('s.submittime < c.endtime') ->andWhere('j.valid = 1'); From dad9dc7f6803b59643ccf0170f802ca3f9bb9953 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 7 May 2023 20:52:25 +0200 Subject: [PATCH 42/80] Do display time wrapping in the template, not in the controller. This fixes #1786 because now the text that gets quoted is not wrapped yet, so it only gets wrapped once, at the time it is made quoted. (cherry picked from commit d0c2487095d69a4c944c9cd965a4ba20beb3eb96) --- webapp/src/Controller/Jury/ClarificationController.php | 2 +- webapp/templates/jury/clarification.html.twig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/Controller/Jury/ClarificationController.php b/webapp/src/Controller/Jury/ClarificationController.php index 3ae7f8c620..b4734dc2fd 100644 --- a/webapp/src/Controller/Jury/ClarificationController.php +++ b/webapp/src/Controller/Jury/ClarificationController.php @@ -202,7 +202,7 @@ public function viewAction(int $id): Response $data['answered'] = $clar->getAnswered(); - $data['body'] = Utils::wrapUnquoted($clar->getBody(), 78); + $data['body'] = $clar->getBody(); $clardata['list'][] = $data; } diff --git a/webapp/templates/jury/clarification.html.twig b/webapp/templates/jury/clarification.html.twig index 5ab9ece9a6..9d8d8c83a2 100644 --- a/webapp/templates/jury/clarification.html.twig +++ b/webapp/templates/jury/clarification.html.twig @@ -110,7 +110,7 @@ Jury -
{{ clar.body }}
+
{{ clar.body|wrapUnquoted(78) }}
From b79eb7c10a324db5433608e48ea717061ffb5fa1 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 6 May 2023 18:27:09 +0200 Subject: [PATCH 43/80] Document -q option. (cherry picked from commit 5cd488cde1b2a2f62f6e27bc66d539dd200aa5ca) --- sql/dj_setup_database.in | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/dj_setup_database.in b/sql/dj_setup_database.in index 4f085d12e3..af84c47d12 100755 --- a/sql/dj_setup_database.in +++ b/sql/dj_setup_database.in @@ -38,6 +38,7 @@ Commands: Options: -u connect to MySQL with DB admin -p use password for DB admin user + -q be (mostly) quiet -r read DB admin password from prompt -s connect via local socket (do not specify port) From 30a7d295151956ed4bd3292493512731b857f644 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 6 May 2023 18:28:02 +0200 Subject: [PATCH 44/80] Declare variables local. This makes sure they're not set from a previous call to the function, which happened in my case and led to weird buggy behaviour. (cherry picked from commit 5dd35383dc8ed495a5a0ef14065e4a7fa046fc30) --- sql/dj_setup_database.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/dj_setup_database.in b/sql/dj_setup_database.in index af84c47d12..b04f62e7d0 100755 --- a/sql/dj_setup_database.in +++ b/sql/dj_setup_database.in @@ -51,6 +51,8 @@ EOF # Wrapper around mysql command to allow setting options, user, etc. mysql() { + local user pass + # shellcheck disable=SC2153 if [ -n "$DBUSER" ]; then user="-u $DBUSER" From e0d02c626adb56b9a91fa908d5f5a9644251619a Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 6 May 2023 10:16:04 +0200 Subject: [PATCH 45/80] Add missing table header labels for contest problems and judgehosts. Fixes #1966. (cherry picked from commit d02a07e8d86da0b8bafc383382b87ae09dfc648b) --- webapp/src/Form/Type/ContestProblemType.php | 6 +++++- webapp/src/Form/Type/JudgehostType.php | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/webapp/src/Form/Type/ContestProblemType.php b/webapp/src/Form/Type/ContestProblemType.php index 18bdee292f..b4068abf3b 100644 --- a/webapp/src/Form/Type/ContestProblemType.php +++ b/webapp/src/Form/Type/ContestProblemType.php @@ -30,14 +30,18 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('shortname', TextType::class, [ 'label' => 'Short name', ]); - $builder->add('points', IntegerType::class); + $builder->add('points', IntegerType::class,[ + 'label' => 'Points', + ]); $builder->add('allowSubmit', ChoiceType::class, [ + 'label' => 'Allow submit', 'choices' => [ 'Yes' => true, 'No' => false, ], ]); $builder->add('allowJudge', ChoiceType::class, [ + 'label' => 'Allow judge', 'choices' => [ 'Yes' => true, 'No' => false, diff --git a/webapp/src/Form/Type/JudgehostType.php b/webapp/src/Form/Type/JudgehostType.php index 5986f8682f..ebaa87d233 100644 --- a/webapp/src/Form/Type/JudgehostType.php +++ b/webapp/src/Form/Type/JudgehostType.php @@ -14,15 +14,18 @@ class JudgehostType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('hostname', TextType::class, [ + 'label' => 'Hostname', 'attr' => ['readonly' => true], ]); $builder->add('enabled', ChoiceType::class, [ + 'label' => 'Enabled', 'choices' => [ 'yes' => true, 'no' => false, ], ]); $builder->add('hidden', ChoiceType::class, [ + 'label' => 'Hidden', 'choices' => [ 'yes' => true, 'no' => false, From 4889088a0c7f56a93b07611e42ea8ca481ebe24f Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 6 May 2023 17:35:05 +0200 Subject: [PATCH 46/80] Do not use Doctrine in the migrations. This would break when adding fields. (cherry picked from commit 9cc324e9c6bb12d90e162d3e52914b9bd0d40aaf) --- webapp/migrations/Version20191031203138.php | 39 +++++++++------------ webapp/migrations/Version20200131064449.php | 15 +++----- 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/webapp/migrations/Version20191031203138.php b/webapp/migrations/Version20191031203138.php index c2a3790c5b..00cebcd6d3 100644 --- a/webapp/migrations/Version20191031203138.php +++ b/webapp/migrations/Version20191031203138.php @@ -29,17 +29,14 @@ public function getDescription(): string public function up(Schema $schema): void { - $em = $this->container->get('doctrine')->getManager(); - /** @var Language $python2 */ - $python2 = $em->getRepository(Language::class)->find('py2'); - /** @var Language $python3 */ - $python3 = $em->getRepository(Language::class)->find('py3'); - if ($python2 === null || - $python3 === null || - $python2->getAllowSubmit() || - $python3->getAllowSubmit() || - $python2->getExtensions() !== ['py2', 'py'] || - $python3->getExtensions() !== ['py3']) { + $python2 = $this->connection->fetchAssociative('SELECT * FROM language WHERE langid = :py2', ['py2' => 'py2']); + $python3 = $this->connection->fetchAssociative('SELECT * FROM language WHERE langid = :py3', ['py3' => 'py3']); + if ($python2 === false || + $python3 === false || + $python2['allow_submit'] || + $python3['allow_submit'] || + json_decode($python2['extensions'], true) !== ['py2', 'py'] || + json_decode($python3['extensions'], true) !== ['py3']) { return; } @@ -49,19 +46,15 @@ public function up(Schema $schema): void public function down(Schema $schema): void { - // this down() migration is auto-generated, please modify it to your needs - $em = $this->container->get('doctrine')->getManager(); - /** @var Language $python2 */ - $python2 = $em->getRepository(Language::class)->find('py2'); - /** @var Language $python3 */ - $python3 = $em->getRepository(Language::class)->find('py3'); + $python2 = $this->connection->fetchAssociative('SELECT * FROM language WHERE langid = :py2', ['py2' => 'py2']); + $python3 = $this->connection->fetchAssociative('SELECT * FROM language WHERE langid = :py3', ['py3' => 'py3']); - if ($python2 === null || - $python3 === null || - $python2->getAllowSubmit() || - $python3->getAllowSubmit() || - $python2->getExtensions() !== ['py2', 'py'] || - $python3->getExtensions() !== ['py3']) { + if ($python2 === false || + $python3 === false || + $python2['allow_submit'] || + $python3['allow_submit'] || + json_decode($python2['extensions'], true) !== ['py2'] || + json_decode($python3['extensions'], true) !== ['py3', 'py']) { return; } diff --git a/webapp/migrations/Version20200131064449.php b/webapp/migrations/Version20200131064449.php index de7c3e7f8d..47b18d3be4 100644 --- a/webapp/migrations/Version20200131064449.php +++ b/webapp/migrations/Version20200131064449.php @@ -30,10 +30,9 @@ public function up(Schema $schema) : void $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); // Note: can't use ConfigurationService::get on 'registration_category_name' because the specification has been removed from db-config.yaml - $em = $this->container->get('doctrine')->getManager(); - $registrationCategoryNameConfig = $em->getRepository(Configuration::class)->findOneBy(['name' => 'registration_category_name']); + $registrationCategoryNameConfig = $this->connection->fetchAssociative('SELECT * FROM configuration WHERE name = :registration_category_name', ['registration_category_name' => 'registration_category_name']); if ($registrationCategoryNameConfig) { - $registrationCategoryName = $registrationCategoryNameConfig->getValue(); + $registrationCategoryName = $registrationCategoryNameConfig['value']; } else { $registrationCategoryName = ''; } @@ -53,23 +52,19 @@ public function down(Schema $schema) : void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); - $em = $this->container->get('doctrine')->getManager(); - $selfRegistrationCategories = $em->getRepository(TeamCategory::class)->findBy( - ['allow_self_registration' => 1], - ['sortorder' => 'ASC'] - ); + $selfRegistrationCategories = $this->connection->fetchAllAssociative('SELECT * FROM team_category WHERE allow_self_registration = 1 ORDER BY sortorder'); $this->warnIf( count($selfRegistrationCategories) > 1, sprintf('Team categories for self-registered teams were %s. Only first will be kept.', implode(', ', array_map(function($category) { - return $category->getName(); + return $category['name']; }, $selfRegistrationCategories))) ); $this->addSql( "INSERT INTO configuration (name, value) VALUES ('registration_category_name', :value)", - ['value' => empty($selfRegistrationCategories) ? '""' : json_encode($selfRegistrationCategories[0]->getName())] + ['value' => empty($selfRegistrationCategories) ? '""' : json_encode($selfRegistrationCategories[0]['name'])] ); $this->addSql('ALTER TABLE team_category DROP allow_self_registration'); From 9457175fef17cd9ddb8a6e58ce49e9d127a2df3b Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 29 May 2023 10:52:15 +0200 Subject: [PATCH 47/80] Update changelog for new release. --- ChangeLog | 14 ++++++++++++++ README.md | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2b0b2e7924..671ac92566 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ DOMjudge Programming Contest Judging System +Version 8.2.1 - 29 May 2023 +--------------------------- + - Set the default domjudge_user to the current user at configure time. + - Various bugfixes. + - Adhere to CLICS 2022-07 again. + - Prevent overwriting of local .netrc when installing examples. + - Fixed some w3c html violations. + - Clarify the need for cgroupv1 when chroot creating fails. + - Fix medal awards when skipping categories. + - Do not allow to delete problems from a locked contest in the UI. + - Disallow submitting to a problem when it does not have testcases at import. + - Fix handling of binary files when editing executables. + - Recalculate all immutable hashes since the algorithm changed in the past. + Version 8.2.0 - 6 March 2023 ---------------------------- - Various bugfixes & UI improvements. diff --git a/README.md b/README.md index 5a34e620b7..d71a3e054b 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) [![LGTM alerts](https://img.shields.io/lgtm/alerts/g/DOMjudge/domjudge.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/DOMjudge/domjudge/alerts/) -This is the Programming Contest Jury System "DOMjudge" version 8.2.1DEV +This is the Programming Contest Jury System "DOMjudge" version 8.2.1 DOMjudge is a system for running a programming contest, like the ICPC regional and world championship programming contests. From 8f523aef6d690d63f619fe5a10e9961bb7558f57 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sun, 7 May 2023 18:35:12 +0200 Subject: [PATCH 48/80] Auto calculate num actions for jury tables. (cherry picked from commit 1294b6e0306cc993bd950a56b5432fcc33d87237) # Conflicts: # webapp/src/Controller/Jury/ExecutableController.php # webapp/src/Twig/TwigExtension.php --- webapp/src/Controller/Jury/ContestController.php | 1 - webapp/src/Controller/Jury/ExecutableController.php | 1 - webapp/src/Controller/Jury/JudgehostController.php | 1 - webapp/src/Controller/Jury/LanguageController.php | 1 - webapp/src/Controller/Jury/ProblemController.php | 1 - .../src/Controller/Jury/TeamAffiliationController.php | 1 - webapp/src/Controller/Jury/TeamCategoryController.php | 1 - webapp/src/Controller/Jury/TeamController.php | 1 - webapp/src/Controller/Jury/UserController.php | 1 - webapp/src/Twig/TwigExtension.php | 10 ++++++++++ webapp/templates/jury/contests.html.twig | 2 +- webapp/templates/jury/executables.html.twig | 2 +- webapp/templates/jury/jury_macros.twig | 3 ++- webapp/templates/jury/languages.html.twig | 4 ++-- .../templates/jury/partials/judgehost_list.html.twig | 2 +- webapp/templates/jury/problems.html.twig | 2 +- webapp/templates/jury/team_affiliations.html.twig | 2 +- webapp/templates/jury/team_categories.html.twig | 2 +- webapp/templates/jury/teams.html.twig | 2 +- webapp/templates/jury/users.html.twig | 2 +- 20 files changed, 22 insertions(+), 20 deletions(-) diff --git a/webapp/src/Controller/Jury/ContestController.php b/webapp/src/Controller/Jury/ContestController.php index 0bfe46e49b..987d05e18e 100644 --- a/webapp/src/Controller/Jury/ContestController.php +++ b/webapp/src/Controller/Jury/ContestController.php @@ -379,7 +379,6 @@ public function indexAction(Request $request): Response 'upcoming_contest' => $upcomingContest, 'contests_table' => $contests_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') && !$contest->isLocked() ? 2 : 0, ]); } diff --git a/webapp/src/Controller/Jury/ExecutableController.php b/webapp/src/Controller/Jury/ExecutableController.php index f80f732a65..9cbb7afec1 100644 --- a/webapp/src/Controller/Jury/ExecutableController.php +++ b/webapp/src/Controller/Jury/ExecutableController.php @@ -116,7 +116,6 @@ public function indexAction(Request $request): Response return $this->render('jury/executables.html.twig', [ 'executables' => $executables_table, 'table_fields' => $table_fields, - 'num_actions' => count($execactions), 'form' => $form->createView(), ]); } diff --git a/webapp/src/Controller/Jury/JudgehostController.php b/webapp/src/Controller/Jury/JudgehostController.php index d4b0cdc807..afd7a024bc 100644 --- a/webapp/src/Controller/Jury/JudgehostController.php +++ b/webapp/src/Controller/Jury/JudgehostController.php @@ -184,7 +184,6 @@ public function indexAction(Request $request): Response $data = [ 'judgehosts' => $judgehosts_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 2 : 0, 'all_checked_in_recently' => $all_checked_in_recently, 'refresh' => [ 'after' => 5, diff --git a/webapp/src/Controller/Jury/LanguageController.php b/webapp/src/Controller/Jury/LanguageController.php index f5f6c1683c..fb3c5e0020 100644 --- a/webapp/src/Controller/Jury/LanguageController.php +++ b/webapp/src/Controller/Jury/LanguageController.php @@ -146,7 +146,6 @@ public function indexAction(): Response 'enabled_languages' => $enabled_languages, 'disabled_languages' => $disabled_languages, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 2 : 0, ]); } diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index 536c6fb928..62502bd74b 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -214,7 +214,6 @@ public function indexAction(): Response $data = [ 'problems' => $problems_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 4 : 2, ]; return $this->render('jury/problems.html.twig', $data); diff --git a/webapp/src/Controller/Jury/TeamAffiliationController.php b/webapp/src/Controller/Jury/TeamAffiliationController.php index 62c12c5750..02436c76d5 100644 --- a/webapp/src/Controller/Jury/TeamAffiliationController.php +++ b/webapp/src/Controller/Jury/TeamAffiliationController.php @@ -143,7 +143,6 @@ public function indexAction(string $projectDir): Response return $this->render('jury/team_affiliations.html.twig', [ 'team_affiliations' => $team_affiliations_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 2 : 0, ]); } diff --git a/webapp/src/Controller/Jury/TeamCategoryController.php b/webapp/src/Controller/Jury/TeamCategoryController.php index 9c0eecd9e6..789c12db82 100644 --- a/webapp/src/Controller/Jury/TeamCategoryController.php +++ b/webapp/src/Controller/Jury/TeamCategoryController.php @@ -127,7 +127,6 @@ public function indexAction(): Response return $this->render('jury/team_categories.html.twig', [ 'team_categories' => $team_categories_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 2 : 0, ]); } diff --git a/webapp/src/Controller/Jury/TeamController.php b/webapp/src/Controller/Jury/TeamController.php index f4056c460d..500badb58e 100644 --- a/webapp/src/Controller/Jury/TeamController.php +++ b/webapp/src/Controller/Jury/TeamController.php @@ -239,7 +239,6 @@ public function indexAction(): Response return $this->render('jury/teams.html.twig', [ 'teams' => $teams_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 3 : 1, ]); } diff --git a/webapp/src/Controller/Jury/UserController.php b/webapp/src/Controller/Jury/UserController.php index 7aed63c520..f69387ea69 100644 --- a/webapp/src/Controller/Jury/UserController.php +++ b/webapp/src/Controller/Jury/UserController.php @@ -184,7 +184,6 @@ public function indexAction(): Response return $this->render('jury/users.html.twig', [ 'users' => $users_table, 'table_fields' => $table_fields, - 'num_actions' => $this->isGranted('ROLE_ADMIN') ? 2 : 0, ]); } diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index 217b555ab4..4e1470b1b9 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -128,6 +128,7 @@ public function getFilters(): array new TwigFilter('printWarningContent', [$this, 'printWarningContent'], ['is_safe' => ['html']]), new TwigFilter('entityIdBadge', [$this, 'entityIdBadge'], ['is_safe' => ['html']]), new TwigFilter('medalType', [$this->awards, 'medalType']), + new TwigFilter('numTableActions', [$this, 'numTableActions']), ]; } @@ -1207,4 +1208,13 @@ public function entityIdBadge(BaseApiEntity $entity, string $idPrefix = ''): str 'externalId' => $externalIdField ? $propertyAccessor->getValue($entity, $externalIdField) : null, ]); } + + public function numTableActions(array $tableData): int + { + $maxNumActions = 0; + foreach ($tableData as $item) { + $maxNumActions = max($maxNumActions, count($item['actions'] ?? [])); + } + return $maxNumActions; + } } diff --git a/webapp/templates/jury/contests.html.twig b/webapp/templates/jury/contests.html.twig index a9af41e1a4..04cc260fc8 100644 --- a/webapp/templates/jury/contests.html.twig +++ b/webapp/templates/jury/contests.html.twig @@ -87,7 +87,7 @@

All available contests

- {{ macros.table(contests_table, table_fields, num_actions) }} + {{ macros.table(contests_table, table_fields) }} {% if is_granted('ROLE_ADMIN') %}

diff --git a/webapp/templates/jury/executables.html.twig b/webapp/templates/jury/executables.html.twig index 94af4cae5b..cd5276371e 100644 --- a/webapp/templates/jury/executables.html.twig +++ b/webapp/templates/jury/executables.html.twig @@ -12,7 +12,7 @@

Executables

- {{ macros.table(executables, table_fields, num_actions, {'ordering': 'false'}) }} + {{ macros.table(executables, table_fields, {'ordering': 'false'}) }} {% if is_granted('ROLE_ADMIN') %}

diff --git a/webapp/templates/jury/jury_macros.twig b/webapp/templates/jury/jury_macros.twig index f86c3e08ac..ddb70eb30a 100644 --- a/webapp/templates/jury/jury_macros.twig +++ b/webapp/templates/jury/jury_macros.twig @@ -85,12 +85,13 @@ {% endmacro %} -{% macro table(data, fields, num_actions, options) %} +{% macro table(data, fields, options) %}

+ {%- set num_actions = data | numTableActions %} {%- set default_sort = 0 %} {%- set default_sort_order = 'asc' %} {%- for key,column in fields %} diff --git a/webapp/templates/jury/languages.html.twig b/webapp/templates/jury/languages.html.twig index 3a68e483b7..0df29e4c15 100644 --- a/webapp/templates/jury/languages.html.twig +++ b/webapp/templates/jury/languages.html.twig @@ -12,14 +12,14 @@

Enabled languages

- {{ macros.table(enabled_languages, table_fields, num_actions) }} + {{ macros.table(enabled_languages, table_fields) }}

Disabled languages

- {{ macros.table(disabled_languages, table_fields, num_actions) }} + {{ macros.table(disabled_languages, table_fields) }} {% if is_granted('ROLE_ADMIN') %}

diff --git a/webapp/templates/jury/partials/judgehost_list.html.twig b/webapp/templates/jury/partials/judgehost_list.html.twig index aa31d1bb6d..a317734554 100644 --- a/webapp/templates/jury/partials/judgehost_list.html.twig +++ b/webapp/templates/jury/partials/judgehost_list.html.twig @@ -1,2 +1,2 @@ {% import "jury/jury_macros.twig" as macros %} -{{ macros.table(judgehosts, table_fields, num_actions, {ordering: 'false'}) }} +{{ macros.table(judgehosts, table_fields, {ordering: 'false'}) }} diff --git a/webapp/templates/jury/problems.html.twig b/webapp/templates/jury/problems.html.twig index 727b515ab2..511fcc5cbb 100644 --- a/webapp/templates/jury/problems.html.twig +++ b/webapp/templates/jury/problems.html.twig @@ -12,7 +12,7 @@

Problems

- {{ macros.table(problems, table_fields, num_actions) }} + {{ macros.table(problems, table_fields) }} {% if is_granted('ROLE_ADMIN') %}

diff --git a/webapp/templates/jury/team_affiliations.html.twig b/webapp/templates/jury/team_affiliations.html.twig index 4c5503003a..0241c263b0 100644 --- a/webapp/templates/jury/team_affiliations.html.twig +++ b/webapp/templates/jury/team_affiliations.html.twig @@ -12,7 +12,7 @@

Affiliations

- {{ macros.table(team_affiliations, table_fields, num_actions) }} + {{ macros.table(team_affiliations, table_fields) }} {%- if is_granted('ROLE_ADMIN') %} diff --git a/webapp/templates/jury/team_categories.html.twig b/webapp/templates/jury/team_categories.html.twig index 9024a8bc79..91e7a95b96 100644 --- a/webapp/templates/jury/team_categories.html.twig +++ b/webapp/templates/jury/team_categories.html.twig @@ -12,7 +12,7 @@

Categories

- {{ macros.table(team_categories, table_fields, num_actions) }} + {{ macros.table(team_categories, table_fields) }} {% if is_granted('ROLE_ADMIN') %}

diff --git a/webapp/templates/jury/teams.html.twig b/webapp/templates/jury/teams.html.twig index 4d1eeb11be..b2501cf750 100644 --- a/webapp/templates/jury/teams.html.twig +++ b/webapp/templates/jury/teams.html.twig @@ -12,7 +12,7 @@

Teams

- {{ macros.table(teams, table_fields, num_actions) }} + {{ macros.table(teams, table_fields) }} {%- if is_granted('ROLE_ADMIN') %} diff --git a/webapp/templates/jury/users.html.twig b/webapp/templates/jury/users.html.twig index e629db218f..e5e291843d 100644 --- a/webapp/templates/jury/users.html.twig +++ b/webapp/templates/jury/users.html.twig @@ -12,7 +12,7 @@

Users

- {{ macros.table(users, table_fields, num_actions) }} + {{ macros.table(users, table_fields) }} {% if is_granted('ROLE_ADMIN') %}

From 4977390b44bfbb5edb6d5c7cf0786589d41b5988 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Fri, 20 Oct 2023 11:18:57 +0200 Subject: [PATCH 49/80] Release 8.2.2 --- ChangeLog | 5 +++++ README.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 671ac92566..89d9f56c7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ DOMjudge Programming Contest Judging System +Version 8.2.2 - 20 October 2023 +------------------------------- + - Bugfix to prevent errors when running a bare-install or deleting all + contests. + Version 8.2.1 - 29 May 2023 --------------------------- - Set the default domjudge_user to the current user at configure time. diff --git a/README.md b/README.md index d71a3e054b..f58a53792b 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) [![LGTM alerts](https://img.shields.io/lgtm/alerts/g/DOMjudge/domjudge.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/DOMjudge/domjudge/alerts/) -This is the Programming Contest Jury System "DOMjudge" version 8.2.1 +This is the Programming Contest Jury System "DOMjudge" version 8.2.2 DOMjudge is a system for running a programming contest, like the ICPC regional and world championship programming contests. From 882a674f14eb205121e24214d5a5da32f43e0d3a Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Wed, 24 Jan 2024 15:16:25 +0100 Subject: [PATCH 50/80] Update Debian debootstrap package to bookworm (current stable) --- misc-tools/dj_make_chroot.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc-tools/dj_make_chroot.in b/misc-tools/dj_make_chroot.in index a3006441b4..78f9cdf21f 100755 --- a/misc-tools/dj_make_chroot.in +++ b/misc-tools/dj_make_chroot.in @@ -67,7 +67,7 @@ Options: -i List of extra package names to install (comma separated). -r List of extra package names to remove (comma separated). -l List of local package files to install (comma separated). - -s List of apt repository .list files that exist outside the chroot + -s List of apt repository .list files that exist outside the chroot to add to the chroot (comma separated). Signing keys for the repository will be imported if they exist as .gpg, .asc or .arm. @@ -178,7 +178,7 @@ if [ "$DISTRO" = 'Debian' ]; then REMOVEDEBS="" # Which debootstrap package to install on non-Debian systems: - DEBOOTDEB="debootstrap_1.0.114_all.deb" + DEBOOTDEB="debootstrap_1.0.128+nmu2+deb12u1_all.deb" # The Debian mirror/proxy below can be passed as environment # variables; if none are given the following defaults are used. From ab51b4e29ef72e4f5d5f6c20b533eee9f6f33a93 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 11 Feb 2024 23:24:35 +0100 Subject: [PATCH 51/80] Close the metadata file in the child process This prevents the submission from writing to the metadata file, which allows it to e.g. override runtime and whether the time limit was hit. Thanks Atsutoshi Kikuchi for reporting. (cherry picked from commit 935bea5c922159ef04c594c43adaf1efef61191c) --- ChangeLog | 4 ++++ judge/runguard.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/ChangeLog b/ChangeLog index 89d9f56c7f..0979a02176 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ DOMjudge Programming Contest Judging System +Version 8.2.3DEV +---------------- + - [security] Close metadata file descriptor for the child in runguard. + Version 8.2.2 - 20 October 2023 ------------------------------- - Bugfix to prevent errors when running a bare-install or deleting all diff --git a/judge/runguard.c b/judge/runguard.c index 4304aca48d..fd3d7117b4 100644 --- a/judge/runguard.c +++ b/judge/runguard.c @@ -1242,6 +1242,13 @@ int main(int argc, char **argv) } verbose("pipes closed in child"); + if ( outputmeta ) { + if ( fclose(metafile)!=0 ) { + error(errno,"closing file `%s'",metafilename); + } + verbose("metafile closed in child"); + } + /* And execute child command. */ execvp(cmdname,cmdargs); error(errno,"cannot start `%s'",cmdname); From 5d1d97d3820f65c035af5fc3d88d387c99e5807d Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Tue, 13 Feb 2024 19:22:21 +0100 Subject: [PATCH 52/80] Export custom (interactive) compare scripts when downloading problem ZIP. Fixes #2327. (cherry picked from commit b67412e78ed573a3f3bf91b03e1216253fff9e8c) --- .../src/Controller/Jury/ProblemController.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index 62502bd74b..eae7954059 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -261,7 +261,10 @@ public function exportAction(int $problemId): StreamedResponse $yaml = ['name' => $problem->getName()]; if (!empty($problem->getCompareExecutable())) { $yaml['validation'] = 'custom'; + } elseif ($problem->getCombinedRunCompare() && !empty($problem->getRunExecutable())) { + $yaml['validation'] = 'custom interactive'; } + if (!empty($problem->getSpecialCompareArgs())) { $yaml['validator_flags'] = $problem->getSpecialCompareArgs(); } @@ -291,6 +294,27 @@ public function exportAction(int $problemId): StreamedResponse stream_get_contents($problem->getProblemtext())); } + $compareExecutable = null; + if ($problem->getCompareExecutable()) { + $compareExecutable = $problem->getCompareExecutable(); + } elseif ($problem->getCombinedRunCompare()) { + $compareExecutable = $problem->getRunExecutable(); + } + if ($compareExecutable) { + foreach ($compareExecutable->getImmutableExecutable()->getFiles() as $file) { + $filename = sprintf('output_validators/%s/%s', $compareExecutable->getExecid(), $file->getFilename()); + $zip->addFromString($filename, $file->getFileContent()); + if ($file->isExecutable()) { + // 100755 = regular file, executable + $zip->setExternalAttributesName( + $filename, + ZipArchive::OPSYS_UNIX, + octdec('100755') << 16 + ); + } + } + } + foreach ([true, false] as $isSample) { /** @var Testcase[] $testcases */ $testcases = $this->em->createQueryBuilder() From 58dbfcae81662f77577ccfa5e3fb7d0b68df77f7 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Sat, 21 Oct 2023 11:14:51 +0200 Subject: [PATCH 53/80] Do not crash when viewing an internal error for a deleted judgehost. Fixes #1809. (cherry picked from commit 7060197091ad13186aacfcbf5549a4ade9df1993) --- webapp/src/Controller/Jury/InternalErrorController.php | 6 +++++- webapp/templates/jury/internal_error.html.twig | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/webapp/src/Controller/Jury/InternalErrorController.php b/webapp/src/Controller/Jury/InternalErrorController.php index 929af2f292..99b46c978c 100644 --- a/webapp/src/Controller/Jury/InternalErrorController.php +++ b/webapp/src/Controller/Jury/InternalErrorController.php @@ -117,8 +117,12 @@ public function viewAction(int $errorId): Response case 'judgehost': // Judgehosts get disabled by their hostname, so we need to look it up here. $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $disabled['hostname']]); - $affectedLink = $this->generateUrl('jury_judgehost', ['judgehostid' => $judgehost->getJudgehostid()]); $affectedText = $disabled['hostname']; + if ($judgehost) { + $affectedLink = $this->generateUrl('jury_judgehost', ['judgehostid' => $judgehost->getJudgehostid()]); + } else { + $affectedText .= ' (deleted)'; + } break; case 'language': $affectedLink = $this->generateUrl('jury_language', ['langId' => $disabled['langid']]); diff --git a/webapp/templates/jury/internal_error.html.twig b/webapp/templates/jury/internal_error.html.twig index 3ba03ea3d8..fb809430ac 100644 --- a/webapp/templates/jury/internal_error.html.twig +++ b/webapp/templates/jury/internal_error.html.twig @@ -72,7 +72,13 @@ {% if affectedText is not null %}

- + {% endif %} From 082c0bbadb68284b3992eb7d8b5b2e2b22d58ba1 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:35:34 +0100 Subject: [PATCH 54/80] Remove doc mention of `judgehost restriction` Added a small part about how to pick up judgings together with parallel judging. This was left over from: https://github.com/DOMjudge/domjudge/pull/1137 Co-authored-by: Thijs Kinkhorst (cherry picked from commit c9fbcaa5f2b739c60f7a3af55e4891eafd4a1346) --- doc/manual/judging.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/manual/judging.rst b/doc/manual/judging.rst index 1cad85dda6..509d1d2f47 100644 --- a/doc/manual/judging.rst +++ b/doc/manual/judging.rst @@ -9,10 +9,12 @@ The flow of an incoming submission is as follows. checks, or accepted and stored as a *submission*. #. The first available *judgehost* compiles, runs and checks the submission. The outcome and outputs are stored as a - *judging* of this submission. Note that judgehosts may be - restricted to certain contests, languages and problems, so that it can be - the case that a judgehost is available, but not judging an available - submission. + *judging* of this submission. If parallel judging is enabled, + multiple judgehosts may pick up and work on the same submission + (if there is no queue of pending submissions). +#. To avoid starving other teams from judgehost resources, + submissions from teams that submit while they have other submissions + in the judge queue will get lower priority than a submission from a team that has no earlier submission being judged yet. #. If verification is not required, the result is automatically recorded and the team can view the result and the scoreboard is updated (unless after the scoreboard freeze). A judge can From 125a2df2f653b502d5f3617cef1bf7001499be95 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Thu, 30 Nov 2023 23:17:35 +0100 Subject: [PATCH 55/80] Correctly handle unshare call error status Thanks Keyu Tao for reporting. (cherry picked from commit 19909c45bc886771a481563d9265689185e63546) --- judge/runguard.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/judge/runguard.c b/judge/runguard.c index fd3d7117b4..d020c34eb9 100644 --- a/judge/runguard.c +++ b/judge/runguard.c @@ -1198,7 +1198,9 @@ int main(int argc, char **argv) cgroup_create(); - unshare(CLONE_FILES|CLONE_FS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWUTS|CLONE_SYSVSEM); + if ( unshare(CLONE_FILES|CLONE_FS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWUTS|CLONE_SYSVSEM)!=0 ) { + error(errno, "calling unshare"); + } /* Check if any Linux Out-Of-Memory killer adjustments have to * be made. The oom_adj or oom_score_adj is inherited by child From 32bd424b3fd4c8682b51f299fffe4631bcc12f54 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Mon, 5 Feb 2024 17:57:39 +0100 Subject: [PATCH 56/80] Make cgroup mount not readonly, needed for newer Docker for Mac setups. Fixes DOMjudge/domjudge-packaging#170 (cherry picked from commit 0a72de845fbcc43627df94351798fdaa6bf5777f) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index bb93035b6b..5b65bf0847 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,7 @@ services: image: domjudge/domjudge-contributor hostname: domjudge-contributor volumes: - - /sys/fs/cgroup:/sys/fs/cgroup:ro + - /sys/fs/cgroup:/sys/fs/cgroup - .:/domjudge:cached - /chroot links: From 5a3360d6d232e887c1ee53c9a2451754eba98616 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Tue, 27 Feb 2024 21:22:02 +0100 Subject: [PATCH 57/80] Release 8.2.3 --- ChangeLog | 5 +++-- README.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0979a02176..8cccb0856f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,9 @@ DOMjudge Programming Contest Judging System -Version 8.2.3DEV ----------------- +Version 8.2.3 - 28 February 2023 +-------------------------------- - [security] Close metadata file descriptor for the child in runguard. + - Various documentation & bugfixes. Version 8.2.2 - 20 October 2023 ------------------------------- diff --git a/README.md b/README.md index f58a53792b..0965d781b2 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) [![LGTM alerts](https://img.shields.io/lgtm/alerts/g/DOMjudge/domjudge.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/DOMjudge/domjudge/alerts/) -This is the Programming Contest Jury System "DOMjudge" version 8.2.2 +This is the Programming Contest Jury System "DOMjudge" version 8.2.3 DOMjudge is a system for running a programming contest, like the ICPC regional and world championship programming contests. From 3fb0003f03f52f9ab03c9fed04a0eaef20530322 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sat, 6 May 2023 19:26:35 +0200 Subject: [PATCH 58/80] Warn when uploading testdata with DOS/Windows newlines. Fixes #1961. (cherry picked from commit 0f93b1fbd1ea9f7d2a7f8e5cad4ac8bc6012a999) --- webapp/src/Service/ImportProblemService.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/webapp/src/Service/ImportProblemService.php b/webapp/src/Service/ImportProblemService.php index 01b845faa0..2a4d380721 100644 --- a/webapp/src/Service/ImportProblemService.php +++ b/webapp/src/Service/ImportProblemService.php @@ -430,6 +430,13 @@ public function importZippedProblem( } } + if (str_contains($testInput, "\r")) { + $messages['warning'][] = "Testcase file '$baseFileName.in' contains Windows newlines."; + } + if (str_contains($testOutput, "\r")) { + $messages['warning'][] = "Testcase file '$baseFileName.ans' contains Windows newlines."; + } + $md5in = md5($testInput); $md5out = md5($testOutput); From f5e83e2adf41d8174818c4d73e896e50616595e5 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:59:34 +0200 Subject: [PATCH 59/80] Force autoconf to lookup the macro Fix based on discussion with @ankon on this subject. This problem is not trivial to reproduce as different people have encountered this since the explicit failure added in https://github.com/DOMjudge/domjudge/commit/339ac729876393c788db1c715dff1f7c36cdfc1c (but first we didn't fail on not resolving the macro). @meistert found the proper documentation on this see: https://manpages.debian.org/testing/pkgconf/pkg.m4.7.en.html (cherry picked from commit ad1398dadfb6f1b910bb04ce9e301d6dcf705177) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b1cd8bbff2..2a06c0f258 100644 --- a/configure.ac +++ b/configure.ac @@ -216,7 +216,7 @@ AX_WITH_COMMENT(7,[ ]) # {{{ Directory for systemd unit files -PKG_PROG_PKG_CONFIG +PKG_PROG_PKG_CONFIG() AC_ARG_WITH([systemdsystemunitdir], [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],, [with_systemdsystemunitdir=auto]) From fd74386518f41faf6edc67accb9ba7602a37509f Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sat, 2 Sep 2023 20:44:56 +0800 Subject: [PATCH 60/80] Fix typo in documentation Fixed a typo in the word 'interfae' by replacing it with 'interface'. (cherry picked from commit e43b1455be15b74b1e28010470c63f7c427ec708) --- doc/manual/config-advanced.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/config-advanced.rst b/doc/manual/config-advanced.rst index 52c9dcd270..aff385bd57 100644 --- a/doc/manual/config-advanced.rst +++ b/doc/manual/config-advanced.rst @@ -7,7 +7,7 @@ DOMjudge can optionally present country flags, affiliation logos, team pictures and a page-wide banner on the public interface. You can place the images under the path `public/images/` (see -the Config checker in the admin interfae for the full filesystem +the Config checker in the admin interface for the full filesystem path of your installation) as follows: - *Country flags* are shown when the ``show_flags`` configuration option From 25d5276d3388b3d03951bc2ac6076237550bd94d Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 3 Sep 2023 07:06:09 +0800 Subject: [PATCH 61/80] Fix typo in documentation Fixed a typo in the word 'interfae' by replacing it with 'interface'. (cherry picked from commit 078f1c724281165952d9e2d63120a24d80996403) --- doc/manual/config-advanced.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/config-advanced.rst b/doc/manual/config-advanced.rst index aff385bd57..72b8016740 100644 --- a/doc/manual/config-advanced.rst +++ b/doc/manual/config-advanced.rst @@ -405,7 +405,7 @@ Clearing the PHP/Symfony cache ------------------------------ Some operations require you to clear the PHP/Symfony cache. To do this, execute -the `webapp/bin/console` (see the Config checker in the admin interfae for the +the `webapp/bin/console` (see the Config checker in the admin interface for the full filesystem path of your installation) binary with the `cache:clear` subcommand:: webapp/bin/console cache:clear From ac19b7db545053361c6c9c9065b5e084ee0a34ab Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Mon, 25 Sep 2023 19:55:04 +0200 Subject: [PATCH 62/80] Use correct printf format specifier for filesize. (#2158) The default value for filesize for scripts is 2.5GB, so more than 2^31 bytes, previously this caused a message like ``` /home/sitowert/domjudge/bin/runguard [56839 @ 0.001495]: verbose: setting filesize limit to -1610612736 bytes ``` After this commit, it is: ``` /home/sitowert/domjudge/bin/runguard [56839 @ 0.001521]: verbose: setting filesize limit to 2684354560 bytes ``` (cherry picked from commit a12c2604f98036297f3ac336971eb584e367168a) --- judge/runguard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/judge/runguard.c b/judge/runguard.c index d020c34eb9..a5257d67db 100644 --- a/judge/runguard.c +++ b/judge/runguard.c @@ -780,7 +780,7 @@ void setrestrictions() setlim(STACK); if ( filesize!=RLIM_INFINITY ) { - verbose("setting filesize limit to %d bytes",(int)filesize); + verbose("setting filesize limit to %lu bytes",filesize); lim.rlim_cur = lim.rlim_max = filesize; setlim(FSIZE); } From 0d78208256e046d7ea95616b326d7e838614a4cc Mon Sep 17 00:00:00 2001 From: AmirHossein Azhdarnezhad Date: Sat, 21 Oct 2023 03:08:55 +0330 Subject: [PATCH 63/80] Add `make` and `libcgroup` to DOMserver's software requirements (cherry picked from commit f66f56d60c1199786e2ed203a107d46b0d023fb4) --- doc/manual/install-domserver.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/install-domserver.rst b/doc/manual/install-domserver.rst index 9546ab92a3..1cbaafa905 100644 --- a/doc/manual/install-domserver.rst +++ b/doc/manual/install-domserver.rst @@ -35,14 +35,14 @@ For your convenience, the following command will install the necessary software on the DOMjudge server as mentioned above when using Debian GNU/Linux, or one of its derivative distributions like Ubuntu:: - sudo apt install acl zip unzip mariadb-server apache2 \ + sudo apt install libcgroup-dev make acl zip unzip mariadb-server apache2 \ php php-fpm php-gd php-cli php-intl php-mbstring php-mysql \ php-curl php-json php-xml php-zip composer ntp The following command can be used on RedHat Enterprise Linux, and related distributions like CentOS and Fedora:: - sudo yum install acl zip unzip mariadb-server httpd \ + sudo yum install make libcgroup-devel acl zip unzip mariadb-server httpd \ php-gd php-cli php-intl php-mbstring php-mysqlnd \ php-xml php-zip composer ntp From 95588cfcf708f9d2271ea806619bfa0d36221d6d Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:35:54 +0100 Subject: [PATCH 64/80] This repairs our teammanual generation Removing this seems to also remove the background color for the summary. We should investigate what was the goal of the LaTeX change and how we can reproduce it. (cherry picked from commit e3b5783e0a5283ba4e8d84f7324ae0da3c49b26e) --- doc/manual/conf.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 1838ce0e91..43785ce39e 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -148,8 +148,6 @@ \definecolor{noteBgColor}{rgb}{1,0,1} \definecolor{sphinxnoteBgColor}{RGB}{221,233,239} -\renewenvironment{sphinxnote}[1] -{\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}} \usepackage{fancyhdr} \pagestyle{fancy} From c3e004063306b6d792d67901c6940b717c337cac Mon Sep 17 00:00:00 2001 From: Thijs Kinkhorst Date: Mon, 1 Jan 2024 08:45:51 +0100 Subject: [PATCH 65/80] DOMjudge's 20 year anniversary (cherry picked from commit 68edf6cfd6e01564c023529a95475b13b3e70ad0) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0965d781b2..c712d467f2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ https://github.com/DOMjudge/domjudge/wiki Copyright & Licensing --------------------- -DOMjudge is Copyright (c) 2004 - 2023 by the DOMjudge developers and +DOMjudge is Copyright (c) 2004 - 2024 by the DOMjudge developers and all respective contributors. The current DOMjudge developers are Jaap Eldering, Nicky Gerritsen, Keith Johnson, Thijs Kinkhorst, Mart Pluijmaekers, Michael Vasseur and Tobias Werth; see the manual for From 9ffc3dac1b3f46dd9b58d343f88b0a9ee1602341 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Fri, 5 Jan 2024 18:37:01 +0100 Subject: [PATCH 66/80] Installing in $HOME should not be the default advice We ourselves install most of the time in /opt, and asking people to open their homefolder can yield other problems. Left the mention of prefix so people are aware they can pick another location to keep the documentation clear. (cherry picked from commit df281ac6574da1cbb4a885deea8a6db7db8800ed) --- doc/manual/install-domserver.rst | 4 ++-- doc/manual/install-judgehost.rst | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/manual/install-domserver.rst b/doc/manual/install-domserver.rst index 1cbaafa905..7cc61c0f7e 100644 --- a/doc/manual/install-domserver.rst +++ b/doc/manual/install-domserver.rst @@ -57,9 +57,9 @@ taken than simply running ``./configure && make && make install``. After installing the required software as described above, run configure. In this example to install DOMjudge in the directory ``domjudge`` under -your home directory:: +`/opt`:: - ./configure --prefix=$HOME/domjudge + ./configure --prefix=/opt/domjudge make domserver sudo make install-domserver diff --git a/doc/manual/install-judgehost.rst b/doc/manual/install-judgehost.rst index 77f1b8b370..f3e7e975fa 100644 --- a/doc/manual/install-judgehost.rst +++ b/doc/manual/install-judgehost.rst @@ -54,10 +54,9 @@ These instructions assume a release `tarball for instructions to build from git sources. After installing the software listed above, run configure. In this -example to install DOMjudge in the directory ``domjudge`` under your -home directory:: +example to install DOMjudge in the directory ``domjudge`` under `/opt`:: - ./configure --prefix=$HOME/domjudge + ./configure --prefix=/opt/domjudge make judgehost sudo make install-judgehost From f5d8b155a9e7e1baa4251aef1086dcf085ed24f9 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:50:01 +0100 Subject: [PATCH 67/80] Fix typos --- judge/judgedaemon.main.php | 2 +- webapp/src/Utils/Utils.php | 2 +- webapp/templates/jury/check_judgings.html.twig | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/judge/judgedaemon.main.php b/judge/judgedaemon.main.php index 35db3c2389..3f0a50f92b 100644 --- a/judge/judgedaemon.main.php +++ b/judge/judgedaemon.main.php @@ -1053,7 +1053,7 @@ function compile( ): bool { global $myhost, $EXITCODES; - // Re-use compilation if it already exists. + // Reuse compilation if it already exists. if (file_exists("$workdir/compile.success")) { return true; } diff --git a/webapp/src/Utils/Utils.php b/webapp/src/Utils/Utils.php index e525914d31..914d962bfd 100644 --- a/webapp/src/Utils/Utils.php +++ b/webapp/src/Utils/Utils.php @@ -335,7 +335,7 @@ public static function parseHexColor(string $hex): array } /** - * Comvert an RGB component to its hex value. + * Convert an RGB component to its hex value. */ public static function componentToHex(int $component): string { diff --git a/webapp/templates/jury/check_judgings.html.twig b/webapp/templates/jury/check_judgings.html.twig index 69c140692e..c8e0b7c807 100644 --- a/webapp/templates/jury/check_judgings.html.twig +++ b/webapp/templates/jury/check_judgings.html.twig @@ -46,7 +46,7 @@ {% elseif id == 'multiple' %} is judged as {{ result.actual }} but has multiple possible outcomes ({{ result.expected|join(', ') }}) {% elseif id == 'verified' %} - verfied as '{{ result.actual }}' + verified as '{{ result.actual }}' {% elseif id == 'nomatch' %} expected results unknown, leaving submission unchecked {% elseif id == 'earlier' %} From ca49ab6d17e60b5fa83276270279b22105f15b03 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Wed, 27 Mar 2024 13:37:58 +0100 Subject: [PATCH 68/80] Add nullcheck for problem of testcase in auditlog. Testcase.probid is nullable, so the problem doesn't have to exist. (cherry picked from commit 990838b45ffa466fa3fa872cc22c6c0938dabf25) --- webapp/src/Controller/Jury/AuditLogController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/Controller/Jury/AuditLogController.php b/webapp/src/Controller/Jury/AuditLogController.php index 0b0c65e2a1..b38100e5c2 100644 --- a/webapp/src/Controller/Jury/AuditLogController.php +++ b/webapp/src/Controller/Jury/AuditLogController.php @@ -168,7 +168,7 @@ private function generateDatatypeUrl(string $type, $id): ?string return $this->generateUrl('jury_user', ['userId' => $id]); case 'testcase': $testcase = $this->em->getRepository(Testcase::class)->find($id); - if ($testcase) { + if ($testcase && $testcase->getProblem()) { return $this->generateUrl('jury_problem_testcases', ['probId' => $testcase->getProblem()->getProbid()]); } break; From a714386a70060bc9a98aac35a43d85916117bbbf Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Mon, 27 May 2024 21:26:29 +0200 Subject: [PATCH 69/80] Select shortname from current contestproblem If you test a problem in contest A with shortname "bla" and run your real contest B (problem shortname "C") we would pick the first contestProblem so we would have displayed "bla" for the clarification. Fixes https://github.com/DOMjudge/domjudge/issues/2279 --- webapp/src/Controller/Team/MiscController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/webapp/src/Controller/Team/MiscController.php b/webapp/src/Controller/Team/MiscController.php index 073c2506c6..83e15f62b1 100644 --- a/webapp/src/Controller/Team/MiscController.php +++ b/webapp/src/Controller/Team/MiscController.php @@ -104,10 +104,12 @@ 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', 'p') + ->select('c', 'cp', '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) @@ -121,10 +123,12 @@ 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', 'p') + ->select('c', 'cp', 'p') ->andWhere('c.contest = :contest') + ->andWhere('cp.contest = :contest') ->andWhere('c.sender = :team') ->setParameter('contest', $contest) ->setParameter('team', $team) From 6a916416463852c007a2f1a0a2de5a2287cc6158 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Fri, 24 May 2024 08:27:22 +0200 Subject: [PATCH 70/80] Fix typo in prolog compile script As found by codespell (cherry picked from commit 4c3b57904564f8a44b089b07a8d1d301f14e3e7e) --- sql/files/defaultdata/plg/compile.plg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/files/defaultdata/plg/compile.plg b/sql/files/defaultdata/plg/compile.plg index 368a5f6781..cec2b596be 100644 --- a/sql/files/defaultdata/plg/compile.plg +++ b/sql/files/defaultdata/plg/compile.plg @@ -4,7 +4,7 @@ :- dynamic(loading/1). :- asserta(loading(0)). -% The first hook is for detectin +% The first hook is for detecting % loading state user:message_hook(Term, _, _) :- From 5d96aaba4d7ce8d103c224462e9c28c20e3031bb Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Fri, 24 Nov 2023 10:18:40 +0100 Subject: [PATCH 71/80] Clean up message handling after importing a zipped problem. Nowadays, the messages is a keyed array with the keys being the warning level. Previously, it was a flat data structure and apparently we didn't clean up all of them. There is still a code duplication between the two controller, but moving this to the Utils class is ugly because it would require passing in the controller. Fixes #2633. (cherry picked from commit a6640d5a5f9357cb0c41d2b51811524efe1fb567) --- .../Jury/ImportExportController.php | 21 ++++++++++++------- .../src/Controller/Jury/ProblemController.php | 19 +++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/webapp/src/Controller/Jury/ImportExportController.php b/webapp/src/Controller/Jury/ImportExportController.php index f1fa4f9b8f..2092b1d8c8 100644 --- a/webapp/src/Controller/Jury/ImportExportController.php +++ b/webapp/src/Controller/Jury/ImportExportController.php @@ -184,7 +184,7 @@ public function indexAction(Request $request): Response $this->dj->auditlog('problem', $newProblem->getProbid(), 'upload zip', $clientName); } else { - $this->addFlash('danger', implode("\n", $allMessages)); + $this->postMessages($allMessages); return $this->redirectToRoute('jury_problems'); } } catch (Exception $e) { @@ -194,12 +194,7 @@ public function indexAction(Request $request): Response $zip->close(); } } - - foreach (['info', 'warning', 'danger'] as $type) { - if (!empty($allMessages[$type])) { - $this->addFlash($type, implode("\n", $allMessages[$type])); - } - } + $this->postMessages($allMessages); if ($newProblem !== null) { return $this->redirectToRoute('jury_problem', ['probId' => $newProblem->getProbid()]); @@ -575,4 +570,16 @@ protected function getClarificationsHtml(): Response 'problems' => $contestProblems, ]); } + + /** + * @param array $allMessages + */ + private function postMessages(array $allMessages): void + { + foreach (['info', 'warning', 'danger'] as $type) { + if (!empty($allMessages[$type])) { + $this->addFlash($type, implode("\n", $allMessages[$type])); + } + } + } } diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index eae7954059..cfd509f905 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -972,12 +972,7 @@ public function editAction(Request $request, int $probId): Response $zip->close(); } } - - foreach (['info', 'warning', 'danger'] as $type) { - if (!empty($messages[$type])) { - $this->addFlash($type, implode("\n", $messages[$type])); - } - } + $this->postMessages($messages); return $this->redirectToRoute('jury_problem', ['probId' => $problem->getProbid()]); } @@ -1172,4 +1167,16 @@ public function requestRemainingRunsWholeProblemAction(string $probId): Redirect $this->judgeRemaining($judgings); return $this->redirect($this->generateUrl('jury_problem', ['probId' => $probId])); } + + /** + * @param array $allMessages + */ + private function postMessages(array $allMessages): void + { + foreach (['info', 'warning', 'danger'] as $type) { + if (!empty($allMessages[$type])) { + $this->addFlash($type, implode("\n", $allMessages[$type])); + } + } + } } From 955740263ccb6acfb4e6bc20101d8b4bb19b806a Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sat, 11 May 2024 10:22:18 +0200 Subject: [PATCH 72/80] Skip parts of the integration tests that rely on v1. This is unfortunate but gitlab seems to have enabled cgroups v2 on their runners and we still use cgroups v1, see https://github.com/DOMjudge/domjudge/issues/1072 (cherry picked from commit cb9e1a77d687697102736404c3da55d39ea1b459) --- gitlab/integration.sh | 132 +++++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 52 deletions(-) diff --git a/gitlab/integration.sh b/gitlab/integration.sh index 1b470f0e50..928686a3d0 100755 --- a/gitlab/integration.sh +++ b/gitlab/integration.sh @@ -81,11 +81,25 @@ mount mount -o remount,exec,dev /builds section_end mount +section_start check_cgroup_v1 "Checking for cgroup v1 availability" +grep cgroup$ /proc/filesystems +if [ $? -eq 0 ]; then + cgroupv1=1 +else + echo "Skipping tests that rely on cgroup v1" + cgroupv1=0 +fi +section_end check_cgroup_v1 + section_start judgehost "Configure judgehost" cd /opt/domjudge/judgehost/ sudo cp /opt/domjudge/judgehost/etc/sudoers-domjudge /etc/sudoers.d/ sudo chmod 400 /etc/sudoers.d/sudoers-domjudge -sudo bin/create_cgroups +if [ $cgroupv1 -ne 0 ]; then + # We allow this to go wrong as some gitlab runners do not have the + # swapaccount kernel option set. + sudo bin/create_cgroups || cgroupv1=0 +fi if [ ! -d ${DIR}/chroot/domjudge/ ]; then cd ${DIR}/misc-tools @@ -128,8 +142,10 @@ set -e if [ $PIN_JUDGEDAEMON -eq 1 ]; then PINNING="-n 0" fi -sudo -u domjudge bin/judgedaemon $PINNING |& tee /tmp/judgedaemon.log & -sleep 5 +if [ $cgroupv1 -ne 0 ]; then + sudo -u domjudge bin/judgedaemon $PINNING |& tee /tmp/judgedaemon.log & + sleep 5 +fi section_end more_setup @@ -154,9 +170,7 @@ for i in hello_kattis different guess; do done section_end submitting -section_start judging "Waiting until all submissions are judged" -# wait for and check results -NUMSUBS=$(curl --fail http://admin:$ADMINPASS@localhost/domjudge/api/contests/1/submissions | python3 -mjson.tool | grep -c '"id":') +section_start curlcookie "Preparing cookie jar for curl" export COOKIEJAR COOKIEJAR=$(mktemp --tmpdir) export CURLOPTS="--fail -sq -m 30 -b $COOKIEJAR" @@ -170,56 +184,64 @@ curl $CURLOPTS -c $COOKIEJAR -F "_csrf_token=$CSRFTOKEN" -F "_username=admin" -F curl $CURLOPTS -F "sendto=" -F "problem=1-" -F "bodytext=Testing" -F "submit=Send" \ "http://localhost/domjudge/jury/clarifications/send" -o /dev/null -# Don't spam the log. -set +x +section_end curlcookie -while /bin/true; do - sleep 30s - curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier?verify_multiple=1" -o /dev/null +if [ $cgroupv1 -ne 0 ]; then + section_start judging "Waiting until all submissions are judged" + # wait for and check results + NUMSUBS=$(curl --fail http://admin:$ADMINPASS@localhost/domjudge/api/contests/1/submissions | python3 -mjson.tool | grep -c '"id":') - # Check if we are done, i.e. everything is judged or something got disabled by internal error... - if tail /tmp/judgedaemon.log | grep -q "No submissions in queue"; then - break - fi - # ... or something has crashed. - if ! pgrep -f judgedaemon; then - break - fi -done + # Don't spam the log. + set +x -NUMNOTVERIFIED=$(curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier" | grep "submissions checked" | sed -r 's/^.* ([0-9]+) submissions checked.*$/\1/') -NUMVERIFIED=$( curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier" | grep "submissions not checked" | sed -r 's/^.* ([0-9]+) submissions not checked.*$/\1/') -NUMNOMAGIC=$( curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier" | grep "without magic string" | sed -r 's/^.* ([0-9]+) without magic string.*$/\1/') -section_end judging - -# We expect -# - two submissions with ambiguous outcome, -# - no submissions without magic string, -# - and all submissions to be judged. -if [ $NUMNOTVERIFIED -ne 2 ] || [ $NUMNOMAGIC -ne 0 ] || [ $NUMSUBS -gt $((NUMVERIFIED+NUMNOTVERIFIED)) ]; then - section_start error "Short error description" - # We error out below anyway, so no need to fail earlier than that. - set +e - echo "verified subs: $NUMVERIFIED, unverified subs: $NUMNOTVERIFIED, total subs: $NUMSUBS" - echo "(expected 2 submissions to be unverified, but all to be processed)" - echo "Of these $NUMNOMAGIC do not have the EXPECTED_RESULTS string (should be 0)." - curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier?verify_multiple=1" | w3m -dump -T text/html - section_end error - - section_start logfiles "All the more or less useful logfiles" - for i in /opt/domjudge/judgehost/judgings/*/*/*/*/*/compile.out; do - echo $i; - head -n 100 $i; - dir=$(dirname $i) - if [ -r $dir/testcase001/system.out ]; then - head $dir/testcase001/system.out - head $dir/testcase001/runguard.err - head $dir/testcase001/program.err - head $dir/testcase001/program.meta + while /bin/true; do + sleep 30s + curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier?verify_multiple=1" -o /dev/null + + # Check if we are done, i.e. everything is judged or something got disabled by internal error... + if tail /tmp/judgedaemon.log | grep -q "No submissions in queue"; then + break + fi + # ... or something has crashed. + if ! pgrep -f judgedaemon; then + break fi - echo; done - exit 1; + + NUMNOTVERIFIED=$(curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier" | grep "submissions checked" | sed -r 's/^.* ([0-9]+) submissions checked.*$/\1/') + NUMVERIFIED=$( curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier" | grep "submissions not checked" | sed -r 's/^.* ([0-9]+) submissions not checked.*$/\1/') + NUMNOMAGIC=$( curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier" | grep "without magic string" | sed -r 's/^.* ([0-9]+) without magic string.*$/\1/') + section_end judging + + # We expect + # - two submissions with ambiguous outcome, + # - no submissions without magic string, + # - and all submissions to be judged. + if [ $NUMNOTVERIFIED -ne 2 ] || [ $NUMNOMAGIC -ne 0 ] || [ $NUMSUBS -gt $((NUMVERIFIED+NUMNOTVERIFIED)) ]; then + section_start error "Short error description" + # We error out below anyway, so no need to fail earlier than that. + set +e + echo "verified subs: $NUMVERIFIED, unverified subs: $NUMNOTVERIFIED, total subs: $NUMSUBS" + echo "(expected 2 submissions to be unverified, but all to be processed)" + echo "Of these $NUMNOMAGIC do not have the EXPECTED_RESULTS string (should be 0)." + curl $CURLOPTS "http://localhost/domjudge/jury/judging-verifier?verify_multiple=1" | w3m -dump -T text/html + section_end error + + section_start logfiles "All the more or less useful logfiles" + for i in /opt/domjudge/judgehost/judgings/*/*/*/*/*/compile.out; do + echo $i; + head -n 100 $i; + dir=$(dirname $i) + if [ -r $dir/testcase001/system.out ]; then + head $dir/testcase001/system.out + head $dir/testcase001/runguard.err + head $dir/testcase001/program.err + head $dir/testcase001/program.meta + fi + echo; + done + exit 1; + fi fi section_start api_check "Performing API checks" @@ -239,7 +261,13 @@ if cat /opt/domjudge/domserver/webapp/var/log/prod.log | egrep '(CRITICAL|ERROR) fi # Check the Contest API: -$CHECK_API -n -C -e -a 'strict=1' http://admin:$ADMINPASS@localhost/domjudge/api +if [ $cgroupv1 -ne 0 ]; then + $CHECK_API -n -C -e -a 'strict=1' http://admin:$ADMINPASS@localhost/domjudge/api +else + # With cgroup v1 not being available we don't judge, so we cannot do + # consistency checks, so running the above command without -C. + $CHECK_API -n -e -a 'strict=1' http://admin:$ADMINPASS@localhost/domjudge/api +fi section_end api_check |& tee "$GITLABARTIFACTS/check_api.log" section_start validate_feed "Validate the eventfeed against API (ignoring failures)" From c87101bc805696a5a2ba4fec5c70b9b5518bfbf2 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Wed, 14 Jun 2023 22:14:16 +0200 Subject: [PATCH 73/80] Use ccs-specs repo for API check script and pin to a fixed commit. This way, CI doesn't just break when the upstream Contest API draft specification changes. (cherry picked from commit 53ccfefe238792406954574e28cc5847e1d2017e) --- gitlab/ci_settings.sh | 2 ++ gitlab/integration.sh | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gitlab/ci_settings.sh b/gitlab/ci_settings.sh index ad1eef947a..d63fb9b3b8 100755 --- a/gitlab/ci_settings.sh +++ b/gitlab/ci_settings.sh @@ -13,6 +13,8 @@ export GITSHA export PS4='(${BASH_SOURCE}:${LINENO}): - [$?] $ ' export LOGFILE="/opt/domjudge/domserver/webapp/var/log/prod.log" +CCS_SPECS_PINNED_SHA1='6b11623d586500d11ec20b6c12a4908b44ff0e41' + # Shared storage for all artifacts export GITLABARTIFACTS="$DIR/gitlabartifacts" mkdir -p "$GITLABARTIFACTS" diff --git a/gitlab/integration.sh b/gitlab/integration.sh index 928686a3d0..5a75f90819 100755 --- a/gitlab/integration.sh +++ b/gitlab/integration.sh @@ -108,13 +108,15 @@ fi section_end judgehost section_start more_setup "Remaining setup (e.g. starting judgedaemon)" -# download domjudge-scripts for API check + +# Download yajsv and ccs-specs for API check. cd $HOME -composer -n require justinrainbow/json-schema +curl -o yajsv https://github.com/neilpa/yajsv/releases/download/v1.4.1/yajsv.linux.amd64 +chmod a+x yajsv echo -e "\033[0m" -PATH=${PATH}:${HOME}/vendor/bin -git clone --depth=1 https://github.com/DOMjudge/domjudge-scripts.git -CHECK_API=${HOME}/domjudge-scripts/contest-api/check-api.sh +git clone https://github.com/icpc/ccs-specs.git +( cd ccs-specs && git reset --hard $CCS_SPECS_PINNED_SHA1 ) +CHECK_API="${HOME}/ccs-specs/check-api.sh -j ${HOME}/yajsv" # Recreate domjudge-run-0 user with random UID to prevent clashes with # existing users in the host and other CI jobs, which can lead to From 7c0c586dfb0f8358dffcd20b014638af0728af85 Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Tue, 1 Aug 2023 00:41:05 +0200 Subject: [PATCH 74/80] Use latest commit in CLICS 2023-06 version. This fixes the CI as the commit we used to pin to before did not exist anymore. (cherry picked from commit 5a59d30acabd8bef125307ab48c25e14212b847f) --- gitlab/ci_settings.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitlab/ci_settings.sh b/gitlab/ci_settings.sh index d63fb9b3b8..dfea8a1925 100755 --- a/gitlab/ci_settings.sh +++ b/gitlab/ci_settings.sh @@ -13,7 +13,7 @@ export GITSHA export PS4='(${BASH_SOURCE}:${LINENO}): - [$?] $ ' export LOGFILE="/opt/domjudge/domserver/webapp/var/log/prod.log" -CCS_SPECS_PINNED_SHA1='6b11623d586500d11ec20b6c12a4908b44ff0e41' +CCS_SPECS_PINNED_SHA1='a68aff54c4e60fc2bff2fc5c36c119bffa4d30f1' # Shared storage for all artifacts export GITLABARTIFACTS="$DIR/gitlabartifacts" From e52895f542d3c1227409d616659c62549d905ebe 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 75/80] 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 f59cd5ec41..7bd0e3c939 100644 --- a/gitlab/ci/template.yml +++ b/gitlab/ci/template.yml @@ -36,7 +36,6 @@ - /bin/true services: - name: mysql - command: ["--default-authentication-plugin=mysql_native_password"] alias: sqlserver .mariadb_job: From a609bfd4efa306924bc647ed9e0cb89d4175296e Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Sat, 3 Aug 2024 00:14:14 +0200 Subject: [PATCH 76/80] Use the LTS container This reverts commit e52895f542d3c1227409d616659c62549d905ebe. --- gitlab/ci/template.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitlab/ci/template.yml b/gitlab/ci/template.yml index 7bd0e3c939..43d88bc5da 100644 --- a/gitlab/ci/template.yml +++ b/gitlab/ci/template.yml @@ -35,7 +35,8 @@ script: - /bin/true services: - - name: mysql + - name: mysql:8.0 + command: ["--default-authentication-plugin=mysql_native_password"] alias: sqlserver .mariadb_job: From ad768f5e45b97a41cb1d26f314594af3b285f8cd Mon Sep 17 00:00:00 2001 From: Michael Vasseur <14887731+vmcj@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:22:33 +0200 Subject: [PATCH 77/80] Upload of problem metadata uses another endpoint See: https://domjudge-org.slack.com/archives/CHHURFUM7/p1726156440653609?thread_ts=1726145487.583349&cid=CHHURFUM7 (cherry picked from commit 72b3b49ee1103af45ff71c86139f0e287f9ee9de) --- doc/manual/import.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/import.rst b/doc/manual/import.rst index 5ff4eefdbb..cbd543b560 100644 --- a/doc/manual/import.rst +++ b/doc/manual/import.rst @@ -402,11 +402,11 @@ and click `Import`. To import the file using the API run the following commands:: - http --check-status -b -f POST "/contests//problems" data@problems.yaml + http --check-status -b -f POST "/contests//problems/add-data" data@problems.yaml To import the file using the CLI run the following command:: - /bin/console api:call -m POST -f data=problems.yaml contests//problems + /bin/console api:call -m POST -f data=problems.yaml contests//problems/add-data Replace ```` with the contest ID that was returned when importing the contest metadata. From 71daad7faa8bcf02e7ea2e8b5ed5ee10bcecf7e4 Mon Sep 17 00:00:00 2001 From: Nicky Gerritsen Date: Mon, 21 Oct 2024 19:56:31 +0200 Subject: [PATCH 78/80] Add note about setting the force flag for cgroup v1 very new systemd versions --- doc/manual/install-judgehost.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/install-judgehost.rst b/doc/manual/install-judgehost.rst index f3e7e975fa..dbb23e2f41 100644 --- a/doc/manual/install-judgehost.rst +++ b/doc/manual/install-judgehost.rst @@ -164,7 +164,8 @@ any other tasks on the same CPU core the judgedaemon is using: On modern distros (e.g. Debian bullseye and Ubuntu Jammy Jellyfish) which have cgroup v2 enabled by default, you need to add ``systemd.unified_cgroup_hierarchy=0`` -as well. Then run ``update-grub`` and reboot. +as well. If you are running systemd v257, you also need to add `SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1`. +Then run ``update-grub`` and reboot. After rebooting check that ``/proc/cmdline`` actually contains the added kernel options. On VM hosting providers such as Google Cloud or DigitalOcean, ``GRUB_CMDLINE_LINUX_DEFAULT`` may be overwritten From e1530314902ac517c1cab9378bb8a6af8be7a399 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Mon, 19 Aug 2024 22:43:34 +0200 Subject: [PATCH 79/80] Update broken link to problem package format Also point to the legacy ICPC version for now. A new version is planned to be released in September around the ICPC World Finals in Astana, but until that's finalized, point to what we're actually (roughly) implementing currently. (cherry picked from commit 11fe36fd45e0cb1d4bd7e25e1a653279f35e105e) --- doc/manual/problem-format.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/problem-format.rst b/doc/manual/problem-format.rst index ebbbf03355..341ddc853e 100644 --- a/doc/manual/problem-format.rst +++ b/doc/manual/problem-format.rst @@ -39,4 +39,4 @@ problem by uploading a zip file that contains only testcase files. Any jury solutions present will be automatically submitted when ``allow_submit`` is ``1`` and there's a team associated with the uploading user. -.. _ICPC problem package specification: https://icpc.io/problem-package-format/spec/problem_package_format +.. _ICPC problem package specification: https://icpc.io/problem-package-format/spec/legacy-icpc From 6627e5dd8703e4becfe8792a5ca6f02ca2323e2f Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Fri, 21 Mar 2025 13:48:37 +0100 Subject: [PATCH 80/80] Bump Debian debootstrap version The old version was not available anymore for download. (cherry picked from commit e6d7b4623924173c30f34e25ec2c6c04716757df) --- misc-tools/dj_make_chroot.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-tools/dj_make_chroot.in b/misc-tools/dj_make_chroot.in index 78f9cdf21f..1e2ecefb86 100755 --- a/misc-tools/dj_make_chroot.in +++ b/misc-tools/dj_make_chroot.in @@ -178,7 +178,7 @@ if [ "$DISTRO" = 'Debian' ]; then REMOVEDEBS="" # Which debootstrap package to install on non-Debian systems: - DEBOOTDEB="debootstrap_1.0.128+nmu2+deb12u1_all.deb" + DEBOOTDEB="debootstrap_1.0.128+nmu2+deb12u2_all.deb" # The Debian mirror/proxy below can be passed as environment # variables; if none are given the following defaults are used. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy

Affected {{ internalError.disabled.kind }}{{ affectedText }} + {% if affectedLink %} + {{ affectedText }} + {% else %} + {{ affectedText }} + {% endif %} +