Skip to content

Commit 1f3e49d

Browse files
authored
Merge branch 'main' into ignore-start-status-event
2 parents 80e66fb + 0576250 commit 1f3e49d

File tree

9 files changed

+132
-54
lines changed

9 files changed

+132
-54
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,46 @@ assignees: ''
77

88
---
99

10-
NOTE: If this is a _discussion starter_, you need any _installation help_ or have a _question_ on how to accomplish something,
10+
<!--
11+
NOTE: If this is a _discussion starter_, you need any _installation help_, or have a _question_ on how to accomplish something,
1112
rather post at [our discussion channel](https://www.domjudge.org/chat) or send an email to our
1213
[DOMjudge-devel mailinglist](https://www.domjudge.org/mailman/postorius/lists/domjudge-devel.domjudge.org/)
1314
instead of filing an issue here.
15+
-->
1416

1517
### Description of the problem
16-
> Replace this line with a short description.
18+
<!--
19+
Write here a short description.
20+
-->
1721

1822
### Your environment
19-
> Include details about your installation here.
20-
> - DOMjudge version (e.g. 7.0.0 or a github commit hash)
21-
> - Operating system / Linux distribution and version (e.g. Ubuntu 18.04)
22-
> - Webserver (e.g. Apache or nginx)
23+
<!--
24+
Include details about your installation here.
25+
- DOMjudge version (e.g. 7.0.0 or a github commit hash)
26+
- Operating system / Linux distribution and version (e.g. Ubuntu 18.04)
27+
- Webserver (e.g. Apache or nginx)
28+
-->
2329

2430
### Steps to reproduce
25-
> Replace this with a description how we can reproduce your bug.
26-
> - Step 1
27-
> - Step 2
28-
> - Step 3
31+
<!--
32+
Write here a description how we can reproduce your bug.
33+
1. Step 1
34+
1. Step 2
35+
1. Step 3
36+
-->
2937

3038
### Expected behaviour
31-
> Replace this line with what you would expect to happen.
39+
<!--
40+
Write here what you would expect to happen.
41+
-->
3242

3343
### Actual behaviour
34-
> Replace this line with what happens instead.
44+
<!--
45+
Write here what happens instead.
46+
-->
3547

3648
### Any other information that you want to share?
37-
> Please include webserver, symfony and judgedaemon log snippets here as appropriate.
38-
> Screenshots may help in case of UI bugs.
49+
<!--
50+
Please include webserver, symfony and judgedaemon log snippets here as appropriate.
51+
Screenshots may help in case of UI bugs.
52+
-->

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,36 @@ assignees: ''
77

88
---
99

10-
NOTE: If this is a _discussion starter_, you need any _installation help_ or have a _question_ on how to accomplish something,
10+
<!--
11+
NOTE: If this is a _discussion starter_, you need any _installation help_, or have a _question_ on how to accomplish something,
1112
rather post at [our discussion channel](https://www.domjudge.org/chat) or send an email to our
1213
[DOMjudge-devel mailinglist](https://www.domjudge.org/mailman/postorius/lists/domjudge-devel.domjudge.org/).
1314
1415
Thank you for suggesting ways to improve DOMjudge. Before you file a feature
1516
request, it might be useful to discuss it first via the chat or mailing list
1617
linked above. We can then assess together whether there is
1718
not already a way to accomplish your goal with DOMjudge currently.
19+
-->
1820

1921
### Description of the enhancement request
20-
> Replace this line with a short description.
22+
<!--
23+
Write here a short description.
24+
-->
2125

2226
### The goal you want to achieve
23-
> Please elaborate on the (larger, higher level) goal you want to achieve with this enhancement, so we have a good understanding what this feature would be useful for and how it fits in DOMjudge as a whole.
27+
<!--
28+
Please elaborate on the (larger, higher level) goal you want to achieve with this enhancement, so we have a good understanding what this feature would be useful for and how it fits in DOMjudge as a whole.
29+
-->
2430

2531
### Expected behaviour
26-
> Replace this line with what you would expect to happen.
27-
> Please describe the workflow how you want this feature to work with expected start URL
28-
> - Step 1
29-
> - Step 2
32+
<!--
33+
Write here what you would expect to happen.
34+
For example describe the flow how you want this feature to work.
35+
1. Step 1
36+
2. Step 2
37+
-->
38+
3039
### Any other information that you want to share?
31-
> Screenshots may help in case of UI enhancements with annotated drawings.
40+
<!--
41+
Screenshots with annotated drawings may help in case of UI enhancements.
42+
-->

webapp/public/js/domjudge.js

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,10 @@ function initializeKeyboardShortcuts() {
834834
if (keysCookie != 1 && keysCookie != "") {
835835
return;
836836
}
837+
// Do not trigger shortcuts if user is pressing Ctrl/Alt/Option/Meta key.
838+
if (e.altKey || e.ctrlKey || e.metaKey) {
839+
return;
840+
}
837841
// Check if the user is not typing in an input field.
838842
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
839843
return;
@@ -901,38 +905,40 @@ function initializeKeyboardShortcuts() {
901905
if (e.key >= '0' && e.key <= '9') {
902906
sequence += e.key;
903907
box.text(type + sequence);
904-
} else if (e.key === 'Enter') {
905-
ignore = false;
906-
switch (type) {
907-
case 's':
908-
type = 'submissions';
909-
break;
910-
case 't':
911-
type = 'teams';
912-
break;
913-
case 'p':
914-
type = 'problems';
915-
break;
916-
case 'c':
917-
type = 'clarifications';
918-
break;
919-
case 'j':
920-
window.location = domjudge_base_url + '/jury/submissions/by-judging-id/' + sequence;
921-
return;
922-
}
923-
var redirect_to = domjudge_base_url + '/jury/' + type;
924-
if (sequence) {
925-
redirect_to += '/' + sequence;
926-
}
927-
window.location = redirect_to;
928908
} else {
929909
ignore = false;
930910
if (box) {
931911
box.remove();
932912
}
913+
// We want to reset the `sequence` variable before redirecting, but then we do need to save the value typed by the user
914+
var typedSequence = sequence;
933915
sequence = '';
934916
$body.off('keydown');
935917
$body.on('keydown', oldFunc);
918+
if (e.key === 'Enter') {
919+
switch (type) {
920+
case 's':
921+
type = 'submissions';
922+
break;
923+
case 't':
924+
type = 'teams';
925+
break;
926+
case 'p':
927+
type = 'problems';
928+
break;
929+
case 'c':
930+
type = 'clarifications';
931+
break;
932+
case 'j':
933+
type = 'submissions/by-judging-id';
934+
break;
935+
}
936+
var redirect_to = domjudge_base_url + '/jury/' + type;
937+
if (typedSequence) {
938+
redirect_to += '/' + typedSequence;
939+
}
940+
window.location = redirect_to;
941+
}
936942
}
937943
});
938944
}

webapp/src/Controller/API/ContestController.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use Symfony\Component\HttpFoundation\StreamedResponse;
4040
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
4141
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
42+
use Symfony\Component\HttpKernel\Exception\HttpException;
4243
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
4344
use Symfony\Component\HttpKernel\KernelInterface;
4445
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -637,8 +638,9 @@ public function getEventFeedAction(
637638
if ($event === null) {
638639
throw new BadRequestHttpException(
639640
sprintf(
640-
'Invalid parameter "%s" requested.',
641-
$request->query->has('since_token') ? 'since_token' : 'since_id'
641+
'Invalid parameter "%s" requested with value "%s".',
642+
$request->query->has('since_token') ? 'since_token' : 'since_id',
643+
$sinceToken ?? $sinceId
642644
)
643645
);
644646
}
@@ -654,6 +656,7 @@ public function getEventFeedAction(
654656
$response->setCallback(function () use ($format, $cid, $contest, $request, $since_id, $types, $strict, $stream, $metadataFactory, $kernel) {
655657
$lastUpdate = 0;
656658
$lastIdSent = max(0, $since_id); // Don't try to look for event_id=0
659+
$lastIdExists = $since_id === -1;
657660
$typeFilter = false;
658661
if ($types) {
659662
$typeFilter = explode(',', $types);
@@ -721,19 +724,31 @@ public function getEventFeedAction(
721724
// Add missing state events that should have happened already.
722725
$this->eventLogService->addMissingStateEvents($contest);
723726

724-
// We fetch *all* events after the last seen to check that
727+
// We fetch *all* events from the last seen to check that
725728
// we don't skip events that are committed out of order.
729+
// This includes the last seen event itself, just to check
730+
// that the database is consistent and, for example, has
731+
// not been reloaded while this process is (long) running.
726732
$q = $this->em->createQueryBuilder()
727733
->from(Event::class, 'e')
728734
->select('e')
729-
->andWhere('e.eventid > :lastIdSent')
735+
->andWhere('e.eventid >= :lastIdSent')
730736
->setParameter('lastIdSent', $lastIdSent)
731737
->orderBy('e.eventid', 'ASC')
732738
->getQuery();
733739

734740
/** @var Event[] $events */
735741
$events = $q->getResult();
736742

743+
if ($lastIdExists) {
744+
if (count($events) == 0 || $events[0]->getEventid() !== $lastIdSent) {
745+
throw new HttpException(500, sprintf('Cannot find event %d in database anymore', $lastIdSent));
746+
}
747+
// Remove the previously last sent event. We just fetched
748+
// it to make sure it's there.
749+
unset($events[0]);
750+
}
751+
737752
// Look for any missing sequential events and wait for them to
738753
// be committed if so.
739754
$missingEvents = false;
@@ -860,6 +875,7 @@ public function getEventFeedAction(
860875
flush();
861876
$lastUpdate = Utils::now();
862877
$lastIdSent = $event->getEventid();
878+
$lastIdExists = true;
863879
$numEventsSent++;
864880

865881
if ($missingEvents && $event->getEventid() >= $lastFoundId) {

webapp/src/Controller/Jury/ContestController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,8 +1038,8 @@ private function doLock(int $contestId, bool $locked): Response
10381038
return $this->redirectToRoute('jury_contest', ['contestId' => $contestId]);
10391039
}
10401040

1041-
#[Route(path: '/{contestId<\d+>}/scoreboard-zip/{type<public|unfrozen>}/contest.zip', name: 'jury_scoreboard_data_zip')]
1042-
public function publicScoreboardDataZipAction(
1041+
#[Route(path: '/{contestId<\d+>}/{type<public|unfrozen>}-scoreboard.zip', name: 'jury_scoreboard_data_zip')]
1042+
public function scoreboardDataZipAction(
10431043
int $contestId,
10441044
string $type,
10451045
RequestStack $requestStack,

webapp/src/Controller/PublicController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function scoreboardAction(
8989
return $this->render('public/scoreboard.html.twig', $data, $response);
9090
}
9191

92-
#[Route(path: '/scoreboard-zip/contest.zip', name: 'public_scoreboard_data_zip')]
92+
#[Route(path: '/scoreboard.zip', name: 'public_scoreboard_data_zip')]
9393
public function scoreboardDataZipAction(
9494
RequestStack $requestStack,
9595
Request $request,

webapp/src/Controller/Team/SubmissionController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ public function downloadAction(int $submitId): Response
242242
$submitId));
243243
}
244244

245+
if ($this->submissionService->getSubmissionFileCount($submission) === 1) {
246+
return $this->submissionService->getSubmissionFileResponse($submission);
247+
}
248+
245249
return $this->submissionService->getSubmissionZipResponse($submission);
246250
}
247251
}

webapp/src/Service/DOMJudgeService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1557,7 +1557,7 @@ public function getScoreboardZip(
15571557
}
15581558
$zip->close();
15591559

1560-
return Utils::streamZipFile($tempFilename, 'contest.zip');
1560+
return Utils::streamZipFile($tempFilename, 'scoreboard.zip');
15611561
}
15621562

15631563
private function allowJudge(ContestProblem $problem, Submission $submission, Language $language, bool $manualRequest): bool

webapp/src/Service/SubmissionService.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,4 +768,31 @@ public function getSubmissionZipResponse(Submission $submission): StreamedRespon
768768

769769
return Utils::streamZipFile($tmpfname, 's' . $submission->getSubmitid() . '.zip');
770770
}
771+
772+
public function getSubmissionFileResponse(Submission $submission): StreamedResponse
773+
{
774+
/** @var SubmissionFile[] $files */
775+
$files = $submission->getFiles();
776+
777+
if (count($files) !== 1) {
778+
throw new ServiceUnavailableHttpException(null, 'Submission does not contain exactly one file.');
779+
}
780+
781+
$file = $files[0];
782+
$filename = $file->getFilename();
783+
$sourceCode = $file->getSourcecode();
784+
785+
return new StreamedResponse(function () use ($sourceCode) {
786+
echo $sourceCode;
787+
}, 200, [
788+
'Content-Type' => 'text/plain',
789+
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
790+
'Content-Length' => strlen($sourceCode),
791+
]);
792+
}
793+
794+
public function getSubmissionFileCount(Submission $submission): int
795+
{
796+
return count($submission->getFiles());
797+
}
771798
}

0 commit comments

Comments
 (0)