diff --git a/assets/Layout/Footer.scss b/assets/Layout/Footer.scss index 9cb27157e1..552019f1d8 100644 --- a/assets/Layout/Footer.scss +++ b/assets/Layout/Footer.scss @@ -1,14 +1,6 @@ -@use '~@material/select'; -@use '~@material/select/mdc-select'; -@use '~@material/list/mdc-list'; -@use '~@material/menu-surface/mdc-menu-surface'; -@use '~@material/menu/mdc-menu'; -@use '~@material/select/styles'; @import './Variables'; @import './Mixins'; -// Keep the footer at the bottom at all time. - html, body { min-height: 100vh; @@ -21,39 +13,54 @@ body { margin-bottom: 1.25rem; } -// ---- - .footer { margin-top: auto; - padding: 1.5rem; + padding: 1rem; color: $footer-color; background-color: $footer-background-color; + @media (width >= 768px) { + padding: 2rem; + } + a { color: inherit; + text-decoration: underline; &:hover { - text-decoration: none; + color: var(--primary); } } - ul { - padding: 0; - list-style: none; + .footer-links { + a { + font-size: 0.9rem; + transition: color 0.3s ease; + text-decoration: none; - .list-vertical { - li { - display: block; - hyphens: auto; + &:hover { + color: var(--primary); + } + + &:not(:first-child) { + margin-left: 0.5rem; } } } -} -.mdc-select { - width: 100% !important; + .footer-copyright { + font-size: 0.9rem; + } } -.mdc-notched-outline__notch { - width: 100% !important; +.footer-download { + padding-top: 2rem; + padding-bottom: 2rem; + a { + text-decoration: none; + + img { + margin-top: 0.3rem; + } + } } diff --git a/bin/initial_setup.sh b/bin/initial_setup.sh index 53776f216c..33e683c6fc 100755 --- a/bin/initial_setup.sh +++ b/bin/initial_setup.sh @@ -10,7 +10,7 @@ sudo apt upgrade sudo apt install curl acl ## Php and its extensions, composer (php package manager) -sudo apt install php8.3-common php8.3-ldap php8.3-cli php8.3-curl php8.3-intl php8.3-apcu php8.3-imagick php8.3-mbstring php8.3-xml php8.3-fpm php8.3-mysql php8.3-gd php8.3-zip +sudo apt install php8.3-common php8.3-ldap php8.3-cli php8.3-curl php8.3-intl php8.3-apcu php8.3-imagick php8.3-mbstring php8.3-xml php8.3-fpm php8.3-mysql php8.3-gd php8.3-zip php8.3-bcmath sudo apt install composer ## Node and npm (node package manager) diff --git a/composer.json b/composer.json index 313d242601..8d5eaff3eb 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,7 @@ "description": "Catrobat's Share Community Platform", "require": { "php": ">=8.3", + "ext-bcmath": "*", "ext-SimpleXML": "*", "ext-gd": "*", "ext-imagick": "*", @@ -99,7 +100,8 @@ "ext-pcntl": "8.3", "ext-posix": "8.3", "ext-xml": "8.3", - "ext-zip": "8.3" + "ext-zip": "8.3", + "ext-bcmath": "8.3" }, "bin-dir": "bin", "preferred-install": { diff --git a/composer.lock b/composer.lock index ae457698b3..660c402827 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e788930f896920ab51c19161cf3c9e9e", + "content-hash": "a17ff90302e05c0a3014f237293b5d24", "packages": [ { "name": "beberlei/doctrineextensions", @@ -432,16 +432,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.1", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a" + "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a", - "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/48a792895a2b7a6ee65dd5442c299d7b835b6137", + "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137", "shasum": "" }, "require": { @@ -451,8 +451,8 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", "psr/log": "^1.0 || ^2.0 || ^3.0", - "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", @@ -488,7 +488,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.1" + "source": "https://github.com/composer/ca-bundle/tree/1.5.2" }, "funding": [ { @@ -504,7 +504,7 @@ "type": "tidelift" } ], - "time": "2024-07-08T15:28:20+00:00" + "time": "2024-09-25T07:49:53+00:00" }, { "name": "doctrine/cache", @@ -1762,16 +1762,16 @@ }, { "name": "doctrine/sql-formatter", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/sql-formatter.git", - "reference": "7f83911cc5eba870de7ebb11283972483f7e2891" + "reference": "16ca9e39877369d664f06dacde468548298bdc40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/7f83911cc5eba870de7ebb11283972483f7e2891", - "reference": "7f83911cc5eba870de7ebb11283972483f7e2891", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/16ca9e39877369d664f06dacde468548298bdc40", + "reference": "16ca9e39877369d664f06dacde468548298bdc40", "shasum": "" }, "require": { @@ -1779,6 +1779,7 @@ }, "require-dev": { "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^10.5", "vimeo/psalm": "^5.24" @@ -1811,9 +1812,9 @@ ], "support": { "issues": "https://github.com/doctrine/sql-formatter/issues", - "source": "https://github.com/doctrine/sql-formatter/tree/1.4.1" + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.0" }, - "time": "2024-08-05T20:32:22+00:00" + "time": "2024-09-11T07:29:40+00:00" }, { "name": "egulias/email-validator", @@ -2445,16 +2446,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.372.0", + "version": "v0.375.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "61b9426f6351ac3c652f6d9ba014c89fc446f764" + "reference": "ad8c4fcf925fd10198c20e2d7a3390183dc24bf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/61b9426f6351ac3c652f6d9ba014c89fc446f764", - "reference": "61b9426f6351ac3c652f6d9ba014c89fc446f764", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/ad8c4fcf925fd10198c20e2d7a3390183dc24bf1", + "reference": "ad8c4fcf925fd10198c20e2d7a3390183dc24bf1", "shasum": "" }, "require": { @@ -2483,9 +2484,9 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.372.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.375.0" }, - "time": "2024-09-09T01:04:23+00:00" + "time": "2024-09-29T01:10:26+00:00" }, { "name": "google/auth", @@ -3844,34 +3845,34 @@ }, { "name": "lcobucci/clock", - "version": "3.2.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/lcobucci/clock.git", - "reference": "6f28b826ea01306b07980cb8320ab30b966cd715" + "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/clock/zipball/6f28b826ea01306b07980cb8320ab30b966cd715", - "reference": "6f28b826ea01306b07980cb8320ab30b966cd715", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/db3713a61addfffd615b79bf0bc22f0ccc61b86b", + "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b", "shasum": "" }, "require": { - "php": "~8.2.0 || ~8.3.0", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", "psr/clock": "^1.0" }, "provide": { "psr/clock-implementation": "1.0" }, "require-dev": { - "infection/infection": "^0.27", - "lcobucci/coding-standard": "^11.0.0", + "infection/infection": "^0.29", + "lcobucci/coding-standard": "^11.1.0", "phpstan/extension-installer": "^1.3.1", "phpstan/phpstan": "^1.10.25", "phpstan/phpstan-deprecation-rules": "^1.1.3", "phpstan/phpstan-phpunit": "^1.3.13", "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^10.2.3" + "phpunit/phpunit": "^11.3.6" }, "type": "library", "autoload": { @@ -3892,7 +3893,7 @@ "description": "Yet another clock abstraction", "support": { "issues": "https://github.com/lcobucci/clock/issues", - "source": "https://github.com/lcobucci/clock/tree/3.2.0" + "source": "https://github.com/lcobucci/clock/tree/3.3.1" }, "funding": [ { @@ -3904,7 +3905,7 @@ "type": "patreon" } ], - "time": "2023-11-17T17:00:27+00:00" + "time": "2024-09-24T20:45:14+00:00" }, { "name": "lcobucci/jwt", @@ -4476,16 +4477,16 @@ }, { "name": "php-http/client-common", - "version": "2.7.1", + "version": "2.7.2", "source": { "type": "git", "url": "https://github.com/php-http/client-common.git", - "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612" + "reference": "0cfe9858ab9d3b213041b947c881d5b19ceeca46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/client-common/zipball/1e19c059b0e4d5f717bf5d524d616165aeab0612", - "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612", + "url": "https://api.github.com/repos/php-http/client-common/zipball/0cfe9858ab9d3b213041b947c881d5b19ceeca46", + "reference": "0cfe9858ab9d3b213041b947c881d5b19ceeca46", "shasum": "" }, "require": { @@ -4539,22 +4540,22 @@ ], "support": { "issues": "https://github.com/php-http/client-common/issues", - "source": "https://github.com/php-http/client-common/tree/2.7.1" + "source": "https://github.com/php-http/client-common/tree/2.7.2" }, - "time": "2023-11-30T10:31:25+00:00" + "time": "2024-09-24T06:21:48+00:00" }, { "name": "php-http/discovery", - "version": "1.19.4", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "0700efda8d7526335132360167315fdab3aeb599" + "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", - "reference": "0700efda8d7526335132360167315fdab3aeb599", + "url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d", + "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d", "shasum": "" }, "require": { @@ -4618,22 +4619,22 @@ ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.19.4" + "source": "https://github.com/php-http/discovery/tree/1.20.0" }, - "time": "2024-03-29T13:00:05+00:00" + "time": "2024-10-02T11:20:13+00:00" }, { "name": "php-http/httplug", - "version": "2.4.0", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/php-http/httplug.git", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67" + "reference": "5cad731844891a4c282f3f3e1b582c46839d22f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67", + "url": "https://api.github.com/repos/php-http/httplug/zipball/5cad731844891a4c282f3f3e1b582c46839d22f4", + "reference": "5cad731844891a4c282f3f3e1b582c46839d22f4", "shasum": "" }, "require": { @@ -4675,9 +4676,9 @@ ], "support": { "issues": "https://github.com/php-http/httplug/issues", - "source": "https://github.com/php-http/httplug/tree/2.4.0" + "source": "https://github.com/php-http/httplug/tree/2.4.1" }, - "time": "2023-04-14T15:10:03+00:00" + "time": "2024-09-23T11:39:58+00:00" }, { "name": "php-http/httplug-bundle", @@ -4844,16 +4845,16 @@ }, { "name": "php-http/message", - "version": "1.16.1", + "version": "1.16.2", "source": { "type": "git", "url": "https://github.com/php-http/message.git", - "reference": "5997f3289332c699fa2545c427826272498a2088" + "reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/message/zipball/5997f3289332c699fa2545c427826272498a2088", - "reference": "5997f3289332c699fa2545c427826272498a2088", + "url": "https://api.github.com/repos/php-http/message/zipball/06dd5e8562f84e641bf929bfe699ee0f5ce8080a", + "reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a", "shasum": "" }, "require": { @@ -4907,9 +4908,9 @@ ], "support": { "issues": "https://github.com/php-http/message/issues", - "source": "https://github.com/php-http/message/tree/1.16.1" + "source": "https://github.com/php-http/message/tree/1.16.2" }, - "time": "2024-03-07T13:22:09+00:00" + "time": "2024-10-02T11:34:13+00:00" }, { "name": "php-http/promise", @@ -5023,16 +5024,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.41", + "version": "3.0.42", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "621c73f7dcb310b61de34d1da4c4204e8ace6ceb" + "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/621c73f7dcb310b61de34d1da4c4204e8ace6ceb", - "reference": "621c73f7dcb310b61de34d1da4c4204e8ace6ceb", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db92f1b1987b12b13f248fe76c3a52cadb67bb98", + "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98", "shasum": "" }, "require": { @@ -5113,7 +5114,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.41" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.42" }, "funding": [ { @@ -5129,20 +5130,20 @@ "type": "tidelift" } ], - "time": "2024-08-12T00:13:54+00:00" + "time": "2024-09-16T03:06:04+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.30.1", + "version": "1.32.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "51b95ec8670af41009e2b2b56873bad96682413e" + "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e", - "reference": "51b95ec8670af41009e2b2b56873bad96682413e", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ca22b154efdd9e3c68c56f5d94670920a1c19a4", + "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4", "shasum": "" }, "require": { @@ -5174,9 +5175,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.32.0" }, - "time": "2024-09-07T20:13:05+00:00" + "time": "2024-09-26T07:23:32+00:00" }, { "name": "psr/cache", @@ -8061,16 +8062,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "5c31b278a52023970f4ef398e42ab9048483abfa" + "reference": "2568d0adaa5b0018b07beaa90363b880a43cc957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/5c31b278a52023970f4ef398e42ab9048483abfa", - "reference": "5c31b278a52023970f4ef398e42ab9048483abfa", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/2568d0adaa5b0018b07beaa90363b880a43cc957", + "reference": "2568d0adaa5b0018b07beaa90363b880a43cc957", "shasum": "" }, "require": { @@ -8149,7 +8150,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.1.4" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.1.5" }, "funding": [ { @@ -8165,7 +8166,7 @@ "type": "tidelift" } ], - "time": "2024-08-13T10:29:23+00:00" + "time": "2024-09-08T12:32:26+00:00" }, { "name": "symfony/dotenv", @@ -8733,16 +8734,16 @@ }, { "name": "symfony/form", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "3018ad169ea7532eec19e001f2c9f049ff051bd6" + "reference": "6b8b53ad6d42f14b158c896163b96ff260d78222" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/3018ad169ea7532eec19e001f2c9f049ff051bd6", - "reference": "3018ad169ea7532eec19e001f2c9f049ff051bd6", + "url": "https://api.github.com/repos/symfony/form/zipball/6b8b53ad6d42f14b158c896163b96ff260d78222", + "reference": "6b8b53ad6d42f14b158c896163b96ff260d78222", "shasum": "" }, "require": { @@ -8810,7 +8811,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v7.1.4" + "source": "https://github.com/symfony/form/tree/v7.1.5" }, "funding": [ { @@ -8826,7 +8827,7 @@ "type": "tidelift" } ], - "time": "2024-08-12T09:59:40+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/framework-bundle", @@ -11328,16 +11329,16 @@ }, { "name": "symfony/security-core", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "f5ccd9d005993e5ff7251e57fe4a0615c8535866" + "reference": "dbeb09f0b786590d126c0da297e2320e66ec353b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/f5ccd9d005993e5ff7251e57fe4a0615c8535866", - "reference": "f5ccd9d005993e5ff7251e57fe4a0615c8535866", + "url": "https://api.github.com/repos/symfony/security-core/zipball/dbeb09f0b786590d126c0da297e2320e66ec353b", + "reference": "dbeb09f0b786590d126c0da297e2320e66ec353b", "shasum": "" }, "require": { @@ -11394,7 +11395,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v7.1.4" + "source": "https://github.com/symfony/security-core/tree/v7.1.5" }, "funding": [ { @@ -11410,7 +11411,7 @@ "type": "tidelift" } ], - "time": "2024-08-29T08:16:25+00:00" + "time": "2024-09-20T13:35:23+00:00" }, { "name": "symfony/security-csrf", @@ -11482,16 +11483,16 @@ }, { "name": "symfony/security-http", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "acd1ecc807b76b9bdefe53168c3a52a11205fc20" + "reference": "d47c013bccf4b81a1496826d42dfa05da549131a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/acd1ecc807b76b9bdefe53168c3a52a11205fc20", - "reference": "acd1ecc807b76b9bdefe53168c3a52a11205fc20", + "url": "https://api.github.com/repos/symfony/security-http/zipball/d47c013bccf4b81a1496826d42dfa05da549131a", + "reference": "d47c013bccf4b81a1496826d42dfa05da549131a", "shasum": "" }, "require": { @@ -11550,7 +11551,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v7.1.4" + "source": "https://github.com/symfony/security-http/tree/v7.1.5" }, "funding": [ { @@ -11566,20 +11567,20 @@ "type": "tidelift" } ], - "time": "2024-08-15T22:52:38+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/serializer", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "0158b0e91b7cf7e744a6fb9acaeb613d1ca40dbb" + "reference": "71d6e1f70f00752d1469d0f5e83b0a51716f288b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/0158b0e91b7cf7e744a6fb9acaeb613d1ca40dbb", - "reference": "0158b0e91b7cf7e744a6fb9acaeb613d1ca40dbb", + "url": "https://api.github.com/repos/symfony/serializer/zipball/71d6e1f70f00752d1469d0f5e83b0a51716f288b", + "reference": "71d6e1f70f00752d1469d0f5e83b0a51716f288b", "shasum": "" }, "require": { @@ -11593,12 +11594,14 @@ "symfony/dependency-injection": "<6.4", "symfony/property-access": "<6.4", "symfony/property-info": "<6.4", + "symfony/type-info": "<7.1.5", "symfony/uid": "<6.4", "symfony/validator": "<6.4", "symfony/yaml": "<6.4" }, "require-dev": { "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0", "seld/jsonlint": "^1.10", "symfony/cache": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", @@ -11614,7 +11617,7 @@ "symfony/property-access": "^6.4|^7.0", "symfony/property-info": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/type-info": "^7.1", + "symfony/type-info": "^7.1.5", "symfony/uid": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0", "symfony/var-dumper": "^6.4|^7.0", @@ -11647,7 +11650,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v7.1.4" + "source": "https://github.com/symfony/serializer/tree/v7.1.5" }, "funding": [ { @@ -11663,7 +11666,7 @@ "type": "tidelift" } ], - "time": "2024-08-22T09:39:57+00:00" + "time": "2024-09-20T12:13:15+00:00" }, { "name": "symfony/service-contracts", @@ -12333,16 +12336,16 @@ }, { "name": "symfony/type-info", - "version": "v7.1.1", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "60b28eb733f1453287f1263ed305b96091e0d1dc" + "reference": "9f6094aa900d2c06bd61576a6f279d4ac441515f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/60b28eb733f1453287f1263ed305b96091e0d1dc", - "reference": "60b28eb733f1453287f1263ed305b96091e0d1dc", + "url": "https://api.github.com/repos/symfony/type-info/zipball/9f6094aa900d2c06bd61576a6f279d4ac441515f", + "reference": "9f6094aa900d2c06bd61576a6f279d4ac441515f", "shasum": "" }, "require": { @@ -12395,7 +12398,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v7.1.1" + "source": "https://github.com/symfony/type-info/tree/v7.1.5" }, "funding": [ { @@ -12411,7 +12414,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:59:31+00:00" + "time": "2024-09-19T21:48:23+00:00" }, { "name": "symfony/validator", @@ -14415,16 +14418,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "v1.5.2", + "version": "v1.5.3", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9", + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9", "shasum": "" }, "require": { @@ -14465,9 +14468,9 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3" }, - "time": "2022-03-02T22:36:06+00:00" + "time": "2024-04-30T00:40:11+00:00" }, { "name": "fidry/cpu-core-counter", @@ -14947,16 +14950,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.19.2", + "version": "v4.19.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "0ed4c8949a32986043e977dbe14776c14d644c45" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ed4c8949a32986043e977dbe14776c14d644c45", - "reference": "0ed4c8949a32986043e977dbe14776c14d644c45", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { @@ -14965,7 +14968,7 @@ }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -14997,9 +15000,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, - "time": "2024-09-17T19:36:00+00:00" + "time": "2024-09-29T15:01:53+00:00" }, { "name": "phar-io/manifest", @@ -15871,16 +15874,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.33", + "version": "10.5.35", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4def7a9cda75af9c2bc179ed53a8e41313e7f7cf" + "reference": "7ac8b4e63f456046dcb4c9787da9382831a1874b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4def7a9cda75af9c2bc179ed53a8e41313e7f7cf", - "reference": "4def7a9cda75af9c2bc179ed53a8e41313e7f7cf", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7ac8b4e63f456046dcb4c9787da9382831a1874b", + "reference": "7ac8b4e63f456046dcb4c9787da9382831a1874b", "shasum": "" }, "require": { @@ -15952,7 +15955,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.33" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.35" }, "funding": [ { @@ -15968,7 +15971,7 @@ "type": "tidelift" } ], - "time": "2024-09-09T06:06:56+00:00" + "time": "2024-09-19T10:52:21+00:00" }, { "name": "phrity/net-stream", @@ -16087,16 +16090,16 @@ }, { "name": "phrity/util-errorhandler", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/sirn-se/phrity-util-errorhandler.git", - "reference": "4016d9f9615a4c602f525b0542e4835e316a42e4" + "reference": "483228156e06673963902b1cc1e6bd9541ab4d5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-util-errorhandler/zipball/4016d9f9615a4c602f525b0542e4835e316a42e4", - "reference": "4016d9f9615a4c602f525b0542e4835e316a42e4", + "url": "https://api.github.com/repos/sirn-se/phrity-util-errorhandler/zipball/483228156e06673963902b1cc1e6bd9541ab4d5e", + "reference": "483228156e06673963902b1cc1e6bd9541ab4d5e", "shasum": "" }, "require": { @@ -16132,9 +16135,9 @@ ], "support": { "issues": "https://github.com/sirn-se/phrity-util-errorhandler/issues", - "source": "https://github.com/sirn-se/phrity-util-errorhandler/tree/1.1.0" + "source": "https://github.com/sirn-se/phrity-util-errorhandler/tree/1.1.1" }, - "time": "2024-03-05T19:32:14+00:00" + "time": "2024-09-12T06:49:16+00:00" }, { "name": "phrity/websocket", @@ -17832,16 +17835,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v7.1.1", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "01ce8174447f1f1dd33a5854b01beef79061d9fa" + "reference": "b92af238457a7cdd2738f941cd525d76313e8283" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/01ce8174447f1f1dd33a5854b01beef79061d9fa", - "reference": "01ce8174447f1f1dd33a5854b01beef79061d9fa", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b92af238457a7cdd2738f941cd525d76313e8283", + "reference": "b92af238457a7cdd2738f941cd525d76313e8283", "shasum": "" }, "require": { @@ -17879,7 +17882,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.1.1" + "source": "https://github.com/symfony/dom-crawler/tree/v7.1.5" }, "funding": [ { @@ -17895,7 +17898,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-15T06:48:17+00:00" }, { "name": "symfony/maker-bundle", @@ -18516,6 +18519,7 @@ "prefer-lowest": false, "platform": { "php": ">=8.3", + "ext-bcmath": "*", "ext-simplexml": "*", "ext-gd": "*", "ext-imagick": "*", @@ -18536,7 +18540,8 @@ "ext-pcntl": "8.3", "ext-posix": "8.3", "ext-xml": "8.3", - "ext-zip": "8.3" + "ext-zip": "8.3", + "ext-bcmath": "8.3" }, "plugin-api-version": "2.6.0" } diff --git a/config/services.php b/config/services.php index 9a4206cd44..dee2dec986 100644 --- a/config/services.php +++ b/config/services.php @@ -63,9 +63,7 @@ use App\Api\StudioApi; use App\Api\UserApi; use App\Api\UtilityApi; -use App\DB\Entity\FeatureFlag; use App\DB\Entity\Flavor; -use App\DB\Entity\MaintenanceInformation; use App\DB\Entity\MediaLibrary\MediaPackage; use App\DB\Entity\MediaLibrary\MediaPackageCategory; use App\DB\Entity\MediaLibrary\MediaPackageFile; @@ -75,8 +73,10 @@ use App\DB\Entity\Project\Special\ExampleProgram; use App\DB\Entity\Project\Special\FeaturedProgram; use App\DB\Entity\Project\Tag; -use App\DB\Entity\Survey; use App\DB\Entity\System\CronJob; +use App\DB\Entity\System\FeatureFlag; +use App\DB\Entity\System\MaintenanceInformation; +use App\DB\Entity\System\Survey; use App\DB\Entity\Translation\CommentMachineTranslation; use App\DB\Entity\Translation\ProjectCustomTranslation; use App\DB\Entity\Translation\ProjectMachineTranslation; diff --git a/docker/Dockerfile b/docker/Dockerfile index c718aadd67..1770c6d629 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -33,6 +33,7 @@ RUN apt-get update && \ php8.3-xdebug \ php8.3-xml \ php8.3-zip \ + php8.3-bcmath \ libapache2-mod-php8.3 \ acl \ make \ diff --git a/migrations/2024/Version20240916115931.php b/migrations/2024/Version20240916115931.php new file mode 100644 index 0000000000..3b183752c0 --- /dev/null +++ b/migrations/2024/Version20240916115931.php @@ -0,0 +1,32 @@ +addSql('CREATE TABLE Statistic (id INT AUTO_INCREMENT NOT NULL, projects BIGINT NOT NULL, users BIGINT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci`'); + $this->addSql('INSERT INTO Statistic (id, projects, users) VALUES (1, 0, 0)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE Statistic'); + } +} diff --git a/src/Admin/System/FeatureFlag/FeatureFlagAdmin.php b/src/Admin/System/FeatureFlag/FeatureFlagAdmin.php index e510bd1274..60bb77223b 100644 --- a/src/Admin/System/FeatureFlag/FeatureFlagAdmin.php +++ b/src/Admin/System/FeatureFlag/FeatureFlagAdmin.php @@ -4,7 +4,7 @@ namespace App\Admin\System\FeatureFlag; -use App\DB\Entity\FeatureFlag; +use App\DB\Entity\System\FeatureFlag; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Datagrid\ListMapper; diff --git a/src/Admin/System/FeatureFlag/FeatureFlagController.php b/src/Admin/System/FeatureFlag/FeatureFlagController.php index effc8ec665..3ea3b4bcc9 100644 --- a/src/Admin/System/FeatureFlag/FeatureFlagController.php +++ b/src/Admin/System/FeatureFlag/FeatureFlagController.php @@ -4,7 +4,7 @@ namespace App\Admin\System\FeatureFlag; -use App\DB\Entity\FeatureFlag; +use App\DB\Entity\System\FeatureFlag; use Sonata\AdminBundle\Controller\CRUDController; use Symfony\Component\HttpFoundation\RedirectResponse; diff --git a/src/Admin/System/FeatureFlag/FeatureFlagManager.php b/src/Admin/System/FeatureFlag/FeatureFlagManager.php index f7c767def5..b4c831c3df 100644 --- a/src/Admin/System/FeatureFlag/FeatureFlagManager.php +++ b/src/Admin/System/FeatureFlag/FeatureFlagManager.php @@ -4,7 +4,7 @@ namespace App\Admin\System\FeatureFlag; -use App\DB\Entity\FeatureFlag; +use App\DB\Entity\System\FeatureFlag; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\RequestStack; diff --git a/src/Admin/UserCommunication/MaintenanceInformation/MaintenanceInformationAdmin.php b/src/Admin/UserCommunication/MaintenanceInformation/MaintenanceInformationAdmin.php index 700fefa236..07fce4539d 100644 --- a/src/Admin/UserCommunication/MaintenanceInformation/MaintenanceInformationAdmin.php +++ b/src/Admin/UserCommunication/MaintenanceInformation/MaintenanceInformationAdmin.php @@ -4,7 +4,7 @@ namespace App\Admin\UserCommunication\MaintenanceInformation; -use App\DB\Entity\MaintenanceInformation; +use App\DB\Entity\System\MaintenanceInformation; use Doctrine\ORM\EntityManagerInterface; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\DatagridMapper; diff --git a/src/Admin/UserCommunication/Survey/AllSurveysAdmin.php b/src/Admin/UserCommunication/Survey/AllSurveysAdmin.php index 85d18bc8a7..947133aa9d 100644 --- a/src/Admin/UserCommunication/Survey/AllSurveysAdmin.php +++ b/src/Admin/UserCommunication/Survey/AllSurveysAdmin.php @@ -5,7 +5,7 @@ namespace App\Admin\UserCommunication\Survey; use App\DB\Entity\Flavor; -use App\DB\Entity\Survey; +use App\DB\Entity\System\Survey; use App\DB\EntityRepository\FlavorRepository; use Doctrine\ORM\EntityManagerInterface; use Sonata\AdminBundle\Admin\AbstractAdmin; diff --git a/src/Api/ProjectsApi.php b/src/Api/ProjectsApi.php index 3542ef1bd4..4383705fff 100644 --- a/src/Api/ProjectsApi.php +++ b/src/Api/ProjectsApi.php @@ -195,7 +195,8 @@ public function projectsPost(string $checksum, UploadedFile $file, string $accep $user, $file, $this->facade->getLoader()->getClientIp(), $accept_language, $flavor ) ); - } catch (\Exception) { + } catch (\Exception $e) { + $this->facade->getLogger()->critical('Project Upload broken: '.$e->getMessage().$e->getTraceAsString()); $responseCode = Response::HTTP_UNPROCESSABLE_ENTITY; $error_response = $this->facade->getResponseManager()->createUploadErrorResponse($accept_language); $this->facade->getResponseManager()->addResponseHashToHeaders($responseHeaders, $error_response); diff --git a/src/Api/Services/Projects/ProjectsApiFacade.php b/src/Api/Services/Projects/ProjectsApiFacade.php index 6040e66bab..546d397c27 100644 --- a/src/Api/Services/Projects/ProjectsApiFacade.php +++ b/src/Api/Services/Projects/ProjectsApiFacade.php @@ -6,6 +6,7 @@ use App\Api\Services\AuthenticationManager; use App\Api\Services\Base\AbstractApiFacade; +use Psr\Log\LoggerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class ProjectsApiFacade extends AbstractApiFacade @@ -17,6 +18,7 @@ public function __construct( private readonly ProjectsApiProcessor $processor, private readonly ProjectsRequestValidator $request_validator, private readonly EventDispatcherInterface $event_dispatcher, + private readonly LoggerInterface $logger, ) { parent::__construct($authentication_manager); } @@ -49,4 +51,9 @@ public function getEventDispatcher(): EventDispatcherInterface { return $this->event_dispatcher; } + + public function getLogger(): LoggerInterface + { + return $this->logger; + } } diff --git a/src/Api/Services/Utility/UtilityApiLoader.php b/src/Api/Services/Utility/UtilityApiLoader.php index 9f74a92e64..1910d3ea6b 100644 --- a/src/Api/Services/Utility/UtilityApiLoader.php +++ b/src/Api/Services/Utility/UtilityApiLoader.php @@ -6,7 +6,7 @@ use App\Api\Services\Base\AbstractApiLoader; use App\DB\Entity\Flavor; -use App\DB\Entity\Survey; +use App\DB\Entity\System\Survey; use Doctrine\ORM\EntityManagerInterface; class UtilityApiLoader extends AbstractApiLoader diff --git a/src/Api/Services/Utility/UtilityResponseManager.php b/src/Api/Services/Utility/UtilityResponseManager.php index 47e90c22a8..09af2e54ea 100644 --- a/src/Api/Services/Utility/UtilityResponseManager.php +++ b/src/Api/Services/Utility/UtilityResponseManager.php @@ -5,7 +5,7 @@ namespace App\Api\Services\Utility; use App\Api\Services\Base\AbstractResponseManager; -use App\DB\Entity\Survey; +use App\DB\Entity\System\Survey; use OpenAPI\Server\Model\SurveyResponse; class UtilityResponseManager extends AbstractResponseManager diff --git a/src/Application/Controller/Base/IndexController.php b/src/Application/Controller/Base/IndexController.php index c5cd7f06a9..44ae54737a 100644 --- a/src/Application/Controller/Base/IndexController.php +++ b/src/Application/Controller/Base/IndexController.php @@ -5,8 +5,8 @@ namespace App\Application\Controller\Base; use App\DB\Entity\Flavor; -use App\DB\Entity\MaintenanceInformation; use App\DB\Entity\Project\Special\FeaturedProgram; +use App\DB\Entity\System\MaintenanceInformation; use App\DB\Entity\User\User; use App\DB\EntityRepository\Project\Special\FeaturedRepository; use App\Storage\ImageRepository; diff --git a/src/Application/Twig/TwigExtension.php b/src/Application/Twig/TwigExtension.php index 53d78eb08a..417ea4d534 100644 --- a/src/Application/Twig/TwigExtension.php +++ b/src/Application/Twig/TwigExtension.php @@ -8,6 +8,7 @@ use App\DB\Entity\Flavor; use App\DB\Entity\MediaLibrary\MediaPackageFile; use App\DB\EntityRepository\MediaLibrary\MediaPackageFileRepository; +use App\DB\EntityRepository\System\StatisticRepository; use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; @@ -31,7 +32,8 @@ public function __construct( #[Autowire('%kernel.project_dir%/translations')] private readonly string $catrobat_translation_dir, private readonly TranslatorInterface $translator, - private readonly FeatureFlagManager $featureFlagManager, + private readonly FeatureFlagManager $feature_flag_manager, + private readonly StatisticRepository $statistic_repository, ) { } @@ -65,22 +67,32 @@ public function humanFriendlyNumberFilter(mixed $input): bool|string public static function humanFriendlyNumber(mixed $input, TranslatorInterface $translator, mixed $user_locale): bool|string { + // Check if the input is numeric or a numeric string if (!is_numeric($input)) { - return $input; + return $input ?? '0'; } + // Handle the case where the input is a string representing a large number + $input = (string) $input; + $number_formatter = new \NumberFormatter($user_locale, \NumberFormatter::DECIMAL); - if ($input >= 1_000_000) { - $number_formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, 1); + // Handle large numbers (bigint) and normal numeric values + if (bccomp($input, '1000000') >= 0) { + // Divide by 1 million + $formatted_number = bcdiv($input, '1000000', 1); // Result is a string + + // Convert the result to float for NumberFormatter::format + $formatted_number = (float) $formatted_number; - return $number_formatter->format($input / 1_000_000).' '. + return $number_formatter->format($formatted_number).' '. $translator->trans('format.million_abbreviation', [], 'catroweb'); } + // For smaller numbers, convert the input to float $number_formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, 0); - return $number_formatter->format($input); + return $number_formatter->format((float) $input); } #[\Override] @@ -105,12 +117,13 @@ public function getFunctions(): array new TwigFunction('assetFileExists', $this->assetFileExists(...)), new TwigFunction('isVersionSupportedByCatBlocks', $this->isVersionSupportedByCatBlocks(...)), new TwigFunction('isFeatureFlagEnabled', $this->isFeatureFlagEnabled(...)), + new TwigFunction('getStatistics', $this->getStatistics(...)), ]; } public function isFeatureFlagEnabled(string $featureFlag): bool { - return $this->featureFlagManager->isEnabled($featureFlag); + return $this->feature_flag_manager->isEnabled($featureFlag); } public function isVersionSupportedByCatBlocks(string $version): bool @@ -351,4 +364,14 @@ private function getUserAgent(): string return $request->headers->get('User-Agent') ?? ''; } + + private function getStatistics(): array + { + $statistic = $this->statistic_repository->find(1); + + return [ + 'projects' => $this->humanFriendlyNumberFilter($statistic?->getProjects()), + 'users' => $this->humanFriendlyNumberFilter($statistic?->getUsers()), + ]; + } } diff --git a/src/DB/Entity/FeatureFlag.php b/src/DB/Entity/System/FeatureFlag.php similarity index 96% rename from src/DB/Entity/FeatureFlag.php rename to src/DB/Entity/System/FeatureFlag.php index 6a1843ccd7..1577d44efa 100644 --- a/src/DB/Entity/FeatureFlag.php +++ b/src/DB/Entity/System/FeatureFlag.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DB\Entity; +namespace App\DB\Entity\System; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; diff --git a/src/DB/Entity/MaintenanceInformation.php b/src/DB/Entity/System/MaintenanceInformation.php similarity index 98% rename from src/DB/Entity/MaintenanceInformation.php rename to src/DB/Entity/System/MaintenanceInformation.php index 0434bf8291..88522d4bda 100644 --- a/src/DB/Entity/MaintenanceInformation.php +++ b/src/DB/Entity/System/MaintenanceInformation.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DB\Entity; +namespace App\DB\Entity\System; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; diff --git a/src/DB/Entity/System/Statistic.php b/src/DB/Entity/System/Statistic.php new file mode 100644 index 0000000000..03928b7942 --- /dev/null +++ b/src/DB/Entity/System/Statistic.php @@ -0,0 +1,58 @@ +id = $id; + + return $this; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getProjects(): ?string + { + return $this->projects; + } + + public function setProjects(string $projects): static + { + $this->projects = $projects; + + return $this; + } + + public function getUsers(): ?string + { + return $this->users; + } + + public function setUsers(string $users): static + { + $this->users = $users; + + return $this; + } +} diff --git a/src/DB/Entity/Survey.php b/src/DB/Entity/System/Survey.php similarity index 99% rename from src/DB/Entity/Survey.php rename to src/DB/Entity/System/Survey.php index f227fefa59..60194d96dd 100644 --- a/src/DB/Entity/Survey.php +++ b/src/DB/Entity/System/Survey.php @@ -2,8 +2,9 @@ declare(strict_types=1); -namespace App\DB\Entity; +namespace App\DB\Entity\System; +use App\DB\Entity\Flavor; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; diff --git a/src/DB/EntityRepository/System/StatisticRepository.php b/src/DB/EntityRepository/System/StatisticRepository.php new file mode 100644 index 0000000000..307f6661fe --- /dev/null +++ b/src/DB/EntityRepository/System/StatisticRepository.php @@ -0,0 +1,34 @@ + + */ +class StatisticRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Statistic::class); + } + + public function incrementProjects(): void + { + $this->getEntityManager() + ->createQuery('UPDATE App\DB\Entity\System\Statistic s SET s.projects = s.projects + 1 WHERE s.id = 1') + ->execute() + ; + } + + public function incrementUser(): void + { + $this->getEntityManager() + ->createQuery('UPDATE App\DB\Entity\System\Statistic s SET s.users = s.users + 1 WHERE s.id = 1') + ->execute() + ; + } +} diff --git a/src/Project/EntityListener/ProjectPostPersistEntityListener.php b/src/Project/EntityListener/ProjectPostPersistEntityListener.php index 0bae113db3..a37a8d463f 100644 --- a/src/Project/EntityListener/ProjectPostPersistEntityListener.php +++ b/src/Project/EntityListener/ProjectPostPersistEntityListener.php @@ -5,6 +5,7 @@ namespace App\Project\EntityListener; use App\DB\Entity\Project\Program; +use App\DB\EntityRepository\System\StatisticRepository; use App\User\Achievements\AchievementManager; use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener; use Doctrine\ORM\Event\PostPersistEventArgs; @@ -14,7 +15,8 @@ class ProjectPostPersistEntityListener { public function __construct( - protected AchievementManager $achievement_manager) + protected AchievementManager $achievement_manager, + protected StatisticRepository $statistic_repository) { } @@ -26,5 +28,6 @@ public function postPersist(Program $project, PostPersistEventArgs $args): void $user = $project->getUser(); $user->addProgram($project); $this->achievement_manager->unlockAchievementBronzeUser($user); + $this->statistic_repository->incrementProjects(); } } diff --git a/src/System/Commands/DBUpdater/SpecialUpdateCommand.php b/src/System/Commands/DBUpdater/SpecialUpdateCommand.php index cb9c20b1b9..510967b0b6 100644 --- a/src/System/Commands/DBUpdater/SpecialUpdateCommand.php +++ b/src/System/Commands/DBUpdater/SpecialUpdateCommand.php @@ -4,8 +4,10 @@ namespace App\System\Commands\DBUpdater; -use App\User\Achievements\AchievementManager; -use App\User\UserManager; +use App\DB\Entity\System\Statistic; +use App\DB\EntityRepository\Project\ProgramRepository; +use App\DB\EntityRepository\System\StatisticRepository; +use App\DB\EntityRepository\User\UserRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -15,14 +17,29 @@ #[AsCommand(name: 'catrobat:update:special', description: 'Adding/Updating/Deleting data in the Database')] class SpecialUpdateCommand extends Command { - public function __construct(protected EntityManagerInterface $entity_manager, protected AchievementManager $achievement_manager, protected UserManager $user_manager) - { + public function __construct( + protected EntityManagerInterface $entity_manager, + protected StatisticRepository $statistic_repository, + protected UserRepository $user_repository, + protected ProgramRepository $project_repository, + ) { parent::__construct(); } #[\Override] protected function execute(InputInterface $input, OutputInterface $output): int { + $statistic = $this->statistic_repository->find(1); + if ($statistic?->getUsers()) { + return 0; + } + + $statistic = new Statistic(); + $statistic->setProjects((string) $this->project_repository->count()); + $statistic->setUsers((string) $this->user_repository->count()); + $this->entity_manager->persist($statistic); + $this->entity_manager->flush(); + return 0; } } diff --git a/src/System/Commands/Reset/ResetCommand.php b/src/System/Commands/Reset/ResetCommand.php index 0d61c1a7da..bed62d7296 100644 --- a/src/System/Commands/Reset/ResetCommand.php +++ b/src/System/Commands/Reset/ResetCommand.php @@ -5,9 +5,12 @@ namespace App\System\Commands\Reset; use App\DB\Entity\Project\Program; +use App\DB\Entity\System\Statistic; use App\DB\EntityRepository\Project\ProgramRepository; +use App\DB\EntityRepository\System\StatisticRepository; use App\System\Commands\Helpers\CommandHelper; use App\System\Commands\ImportProjects\ProgramImportCommand; +use Doctrine\ORM\EntityManagerInterface; use Random\RandomException; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -22,7 +25,11 @@ class ResetCommand extends Command { final public const string DOWNLOAD_PROGRAMS_DEFAULT_AMOUNT = '30'; - public function __construct(private readonly ProgramRepository $program_manager, private readonly ParameterBagInterface $parameter_bag) + public function __construct( + private readonly EntityManagerInterface $entity_manager, + private readonly ProgramRepository $program_manager, + private readonly StatisticRepository $statistic_repository, + private readonly ParameterBagInterface $parameter_bag) { parent::__construct(); } @@ -137,6 +144,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->downloadProjects($program_names, $user_array, $output); $this->exampleProject($program_names, $output); $this->markNotForKids($program_names, $output); + $this->addStatistics(); // https://share.catrob.at/app/project/{id_of_project}/remix_graph_data to get remixes @@ -569,4 +577,16 @@ private function markNotForKids(array $program_names, OutputInterface $output): } } } + + private function addStatistics(): void + { + $statistic = $this->statistic_repository->find(1); + if (!$statistic) { + $statistic = new Statistic(); + } + $statistic->setProjects('13461234621'); + $statistic->setUsers('345423543'); + $this->entity_manager->persist($statistic); + $this->entity_manager->flush(); + } } diff --git a/src/System/Testing/Behat/Context/DataFixturesContext.php b/src/System/Testing/Behat/Context/DataFixturesContext.php index bf51d2da1c..ae277cce06 100644 --- a/src/System/Testing/Behat/Context/DataFixturesContext.php +++ b/src/System/Testing/Behat/Context/DataFixturesContext.php @@ -5,7 +5,6 @@ namespace App\System\Testing\Behat\Context; use App\DB\Entity\Flavor; -use App\DB\Entity\MaintenanceInformation; use App\DB\Entity\MediaLibrary\MediaPackage; use App\DB\Entity\MediaLibrary\MediaPackageCategory; use App\DB\Entity\MediaLibrary\MediaPackageFile; @@ -17,7 +16,9 @@ use App\DB\Entity\Studio\StudioActivity; use App\DB\Entity\Studio\StudioJoinRequest; use App\DB\Entity\Studio\StudioUser; -use App\DB\Entity\Survey; +use App\DB\Entity\System\MaintenanceInformation; +use App\DB\Entity\System\Statistic; +use App\DB\Entity\System\Survey; use App\DB\Entity\Translation\CommentMachineTranslation; use App\DB\Entity\Translation\ProjectCustomTranslation; use App\DB\Entity\Translation\ProjectMachineTranslation; @@ -1809,4 +1810,31 @@ public function theStudioWithNameShouldHaveValues(string $name, TableNode $table } } } + + /** + * @Given there are statistics with :user_count user and :project_count projects + */ + public function thereAreStatistics(string $user_count, string $project_count): void + { + $statistic = $this->getStatisticsRepository()->findOneBy(['id' => 1]); + if (!$statistic) { + $statistic = new Statistic(); + } + $statistic->setUsers($user_count); + $statistic->setProjects($project_count); + $em = $this->getManager(); + $em->persist($statistic); + $em->flush(); + } + + /** + * @Then There should be statistics with :user_count user and :project_count projects + */ + public function thereShouldBeStatistics(string $user_count, string $project_count): void + { + $statistic = $this->getStatisticsRepository()->findOneBy(['id' => 1]); + $this->getManager()->refresh($statistic); + Assert::assertSame($user_count, $statistic->getUsers(), 'Expected user count check failed'); + Assert::assertSame($project_count, $statistic->getProjects(), 'Expected project count check failed'); + } } diff --git a/src/System/Testing/Behat/ContextTrait.php b/src/System/Testing/Behat/ContextTrait.php index f04cba6935..7fd0be609f 100644 --- a/src/System/Testing/Behat/ContextTrait.php +++ b/src/System/Testing/Behat/ContextTrait.php @@ -29,6 +29,7 @@ use App\DB\EntityRepository\Project\ScratchProgramRepository; use App\DB\EntityRepository\Project\TagRepository; use App\DB\EntityRepository\System\CronJobRepository; +use App\DB\EntityRepository\System\StatisticRepository; use App\DB\EntityRepository\User\Notification\NotificationRepository; use App\DB\EntityRepository\User\RecommenderSystem\UserLikeSimilarityRelationRepository; use App\DB\EntityRepository\User\RecommenderSystem\UserRemixSimilarityRelationRepository; @@ -229,6 +230,11 @@ public function getStudioManager(): ?StudioManager return $this->getContainer()->get(StudioManager::class); } + public function getStatisticsRepository(): ?StatisticRepository + { + return $this->getContainer()->get(StatisticRepository::class); + } + public function getSymfonyParameter(string $param): mixed { return $this->getContainer()->getParameter($param); diff --git a/src/User/EntityListener/UserPostPersistEntityListener.php b/src/User/EntityListener/UserPostPersistEntityListener.php index a34b38abe5..8dabbd9276 100644 --- a/src/User/EntityListener/UserPostPersistEntityListener.php +++ b/src/User/EntityListener/UserPostPersistEntityListener.php @@ -5,6 +5,7 @@ namespace App\User\EntityListener; use App\DB\Entity\User\User; +use App\DB\EntityRepository\System\StatisticRepository; use App\Security\Authentication\VerifyEmail; use App\User\Achievements\AchievementManager; use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener; @@ -16,7 +17,8 @@ class UserPostPersistEntityListener { public function __construct( protected AchievementManager $achievement_manager, - protected VerifyEmail $verify_email) + protected VerifyEmail $verify_email, + protected StatisticRepository $statistic_repository) { } @@ -29,5 +31,6 @@ public function postPersist(User $user, PostPersistEventArgs $args): void if (!$user->isVerified()) { $this->verify_email->init($user)->send(); } + $this->statistic_repository->incrementUser(); } } diff --git a/templates/Layout/Footer.html.twig b/templates/Layout/Footer.html.twig index a8ca387f0a..9da0559837 100644 --- a/templates/Layout/Footer.html.twig +++ b/templates/Layout/Footer.html.twig @@ -1,88 +1,37 @@ -