Skip to content

Commit 378db01

Browse files
committed
Autocheck for new DOMjudge releases
Discussed during the hackathon in 2023. We allow admins to toggle an autoquery to domjudge.org for 2 reasons: - Alerting users that a new version might exist, helping us in case of security releases. - Giving a gentle nudge for people to upgrade making support easier. - Getting some information on what installations are out there.
1 parent d6dd5b3 commit 378db01

File tree

6 files changed

+130
-3
lines changed

6 files changed

+130
-3
lines changed

etc/db-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,11 @@
392392
description: Time in seconds after an external contest source reader last checked in before showing its status as `critical`.
393393
regex: /^\d+$/
394394
error_message: A non-negative number is required.
395+
- name: check_new_version
396+
type: bool
397+
default_value: false
398+
public: false
399+
description: Automatically check for new DOMjudge release?
395400
- name: adminer_enabled
396401
type: bool
397402
default_value: false

webapp/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@
111111
"twig/extra-bundle": "^3.5",
112112
"twig/markdown-extra": "^3.5",
113113
"twig/string-extra": "^3.5",
114-
"twig/twig": "^3.6"
114+
"twig/twig": "^3.6",
115+
"z4kn4fein/php-semver": "^3.0"
115116
},
116117
"require-dev": {
117118
"ext-dom": "*",

webapp/composer.lock

Lines changed: 56 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webapp/src/Service/DOMJudgeService.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use Doctrine\ORM\NoResultException;
3939
use Doctrine\ORM\Query\Expr\Join;
4040
use Doctrine\ORM\QueryBuilder;
41+
use Exception;
4142
use InvalidArgumentException;
4243
use Psr\Log\LoggerInterface;
4344
use ReflectionClass;
@@ -63,6 +64,7 @@
6364
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
6465
use Symfony\Component\Security\Core\User\UserInterface;
6566
use Twig\Environment;
67+
use z4kn4fein\SemVer\Version;
6668
use ZipArchive;
6769

6870
class DOMJudgeService
@@ -107,6 +109,8 @@ public function __construct(
107109
protected string $projectDir,
108110
#[Autowire('%domjudge.vendordir%')]
109111
protected string $vendorDir,
112+
#[Autowire('%domjudge.version%')]
113+
protected readonly string $domjudgeVersion,
110114
) {}
111115

112116
/**
@@ -1671,4 +1675,59 @@ public function getAllowedLanguagesForContest(?Contest $contest) : array {
16711675
->getQuery()
16721676
->getResult();
16731677
}
1678+
1679+
public function checkNewVersion(): string|false {
1680+
if (!$this->config->get('check_new_version')) {
1681+
return false;
1682+
}
1683+
$versionLocalString = explode("/", str_replace("DEV", "-prerelease", $this->domjudgeVersion))[0];
1684+
$versionLocal = Version::parse($versionLocalString, false);
1685+
$versionUrl = 'https://versions.domjudge.org';
1686+
$options = ['http' => ['method' => 'GET', 'header' => "User-Agent: tarball/" . $versionLocalString . "\r\n"]];
1687+
$context = stream_context_create($options);
1688+
$response = @file_get_contents($versionUrl, false, $context);
1689+
if ($response === false) {
1690+
return false;
1691+
}
1692+
$versions = json_decode($response, true);
1693+
/* Steer towards to the latest patch first
1694+
* the user can see on the website if there is a new Major/minor themselves
1695+
* otherwise the latest minor, or Major release. So the user might make the upgrade path:
1696+
* DJ6.0.0 -> DJ6.0.6 -> DJ6.6.0 -> DJ9.0.0 instead of
1697+
* -> DJ6.0.[1..6] -> DJ6.[1..6] -> DJ[7..9].0.0
1698+
*/
1699+
$latestPatchString = $versionLocal;
1700+
if (isset($versions[$versionLocal->getMajor()][$versionLocal->getMinor()])) {
1701+
$latestPatchString = Version::rsortString($versions[$versionLocal->getMajor()][$versionLocal->getMinor()])[0];
1702+
$latestPatch = Version::parse($latestPatchString);
1703+
if (Version::compare($versionLocal, $latestPatch) < 0) {
1704+
return $latestPatchString;
1705+
}
1706+
}
1707+
$latestMinorString = $versionLocal;
1708+
if (isset($versions[$versionLocal->getMajor()])) {
1709+
$highestMinorInMajor = array_keys($versions[$versionLocal->getMajor()]);
1710+
rsort($highestMinorInMajor);
1711+
$latestMinorString = Version::rsortString($versions[$versionLocal->getMajor()][$highestMinorInMajor[0]])[0];
1712+
$latestMinor = Version::parse($latestMinorString);
1713+
if (Version::compare($versionLocal, $latestMinor) < 0) {
1714+
return $latestMinorString;
1715+
}
1716+
}
1717+
$latestMajorString = $versionLocal;
1718+
try {
1719+
$highestMajor = array_keys($versions);
1720+
rsort($highestMajor);
1721+
$highestMinorInMajor = array_keys($versions[$highestMajor[0]]);
1722+
rsort($highestMinorInMajor);
1723+
$latestMajorString = Version::rsortString($versions[$highestMajor[0]][$highestMinorInMajor[0]])[0];
1724+
$latestMajor = Version::parse($latestMajorString);
1725+
if (Version::compare($versionLocal, $latestMajor) < 0) {
1726+
return $latestMajorString;
1727+
}
1728+
} catch (Exception $e) {
1729+
return false;
1730+
}
1731+
return false;
1732+
}
16741733
}

webapp/src/Twig/TwigExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ public function getGlobals(): array
159159
'doc_links' => $this->dj->getDocLinks(),
160160
'allow_registration' => $selfRegistrationCategoriesCount !== 0,
161161
'enable_ranking' => $this->config->get('enable_ranking'),
162+
'new_version_available' => $this->dj->checkNewVersion(),
162163
'editor_themes' => [
163164
'vs' => ['name' => 'Visual Studio (light)'],
164165
'vs-dark' => ['name' => 'Visual Studio (dark)'],

webapp/templates/jury/menu.html.twig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@
9393
</li>
9494
</ul>
9595
{% endif %}
96+
{% if new_version_available %}
97+
<ul class="navbar-nav">
98+
<li class="nav-item nav-link">
99+
<i class="fa-solid fa-ship fa-2x"></i> New release {{ new_version_available }} available.
100+
</li>
101+
</ul>
102+
{% endif %}
96103

97104
<ul class="navbar-nav ml-auto">
98105

0 commit comments

Comments
 (0)