diff --git a/.env b/.env index e438f74731..aebb5d16cc 100644 --- a/.env +++ b/.env @@ -107,10 +107,9 @@ GOOGLE_CLOUD_PROJECT='' MAILER_DSN='null://null' ###< symfony/mailer ### -###> symfony/brevo-mailer ### -# MAILER_DSN=brevo+api://KEY@default -# MAILER_DSN=brevo+smtp://USERNAME:PASSWORD@default -###< symfony/brevo-mailer ### +###> symfony/amazon-mailer ### +# MAILER_DSN=ses+smtp://ACCESS_KEY:SECRET_KEY@default?region=eu-central-1 +###< symfony/amazon-mailer ### ###> bugsnag/bugsnag-symfony ### BUGSNAG_API_KEY='' diff --git a/composer.json b/composer.json index 7097e10098..1234263009 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "sonata-project/exporter": "3.4.*", "sonata-project/twig-extensions": "2.6.*", "symfony/asset": "7.4.*", - "symfony/brevo-mailer": "7.4.*", + "symfony/amazon-mailer": "7.4.*", "symfony/cache": "7.4.*", "symfony/config": "7.4.*", "symfony/console": "7.4.*", diff --git a/composer.lock b/composer.lock index 926f4d4a18..b1cc722aed 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,141 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cc659d8045d12437f5948afb3987c198", + "content-hash": "357fba43de72a6eef12bb2b472d85d5e", "packages": [ + { + "name": "async-aws/core", + "version": "1.29.0", + "source": { + "type": "git", + "url": "https://github.com/async-aws/core.git", + "reference": "70899695fcc7b23a9247926ff8b581668583b993" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/async-aws/core/zipball/70899695fcc7b23a9247926ff8b581668583b993", + "reference": "70899695fcc7b23a9247926ff8b581668583b993", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-simplexml": "*", + "php": "^8.2", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0", + "symfony/http-client-contracts": "^1.1.8 || ^2.0 || ^3.0", + "symfony/service-contracts": "^1.0 || ^2.0 || ^3.0" + }, + "conflict": { + "async-aws/s3": "<1.1", + "symfony/http-client": "5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.42", + "symfony/error-handler": "^7.3.2 || ^8.0", + "symfony/phpunit-bridge": "^7.3.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.29-dev" + } + }, + "autoload": { + "psr-4": { + "AsyncAws\\Core\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Core package to integrate with AWS. This is a lightweight AWS SDK provider by AsyncAws.", + "keywords": [ + "amazon", + "async-aws", + "aws", + "sdk", + "sts" + ], + "support": { + "source": "https://github.com/async-aws/core/tree/1.29.0" + }, + "funding": [ + { + "url": "https://github.com/jderusse", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2026-04-18T17:06:10+00:00" + }, + { + "name": "async-aws/ses", + "version": "1.14.2", + "source": { + "type": "git", + "url": "https://github.com/async-aws/ses.git", + "reference": "ab3bceb3380e971a5619fbd27d921a5352e644f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/async-aws/ses/zipball/ab3bceb3380e971a5619fbd27d921a5352e644f4", + "reference": "ab3bceb3380e971a5619fbd27d921a5352e644f4", + "shasum": "" + }, + "require": { + "async-aws/core": "^1.9", + "php": "^8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.42", + "symfony/error-handler": "^7.3.2 || ^8.0", + "symfony/phpunit-bridge": "^7.3.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "AsyncAws\\Ses\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "SES client, part of the AWS SDK provided by AsyncAws.", + "keywords": [ + "amazon", + "async-aws", + "aws", + "sdk", + "ses" + ], + "support": { + "source": "https://github.com/async-aws/ses/tree/1.14.2" + }, + "funding": [ + { + "url": "https://github.com/jderusse", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2026-04-18T17:06:10+00:00" + }, { "name": "beberlei/doctrineextensions", "version": "v1.5.0", @@ -7023,34 +7156,31 @@ "time": "2025-11-23T16:41:45+00:00" }, { - "name": "symfony/asset", + "name": "symfony/amazon-mailer", "version": "v7.4.6", "source": { "type": "git", - "url": "https://github.com/symfony/asset.git", - "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb" + "url": "https://github.com/symfony/amazon-mailer.git", + "reference": "6fedfa970a1b5b2c93fd32c598df7db7d03070b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/d944ae87e4697af05aadeacfc5e603c3c18ef4fb", - "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/6fedfa970a1b5b2c93fd32c598df7db7d03070b4", + "reference": "6fedfa970a1b5b2c93fd32c598df7db7d03070b4", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/http-foundation": "<6.4" + "async-aws/ses": "^1.8", + "php": ">=8.2", + "symfony/mailer": "^7.2|^8.0" }, "require-dev": { - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0" + "symfony/http-client": "^6.4|^7.0|^8.0" }, - "type": "library", + "type": "symfony-mailer-bridge", "autoload": { "psr-4": { - "Symfony\\Component\\Asset\\": "" + "Symfony\\Component\\Mailer\\Bridge\\Amazon\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -7070,10 +7200,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", + "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v7.4.6" + "source": "https://github.com/symfony/amazon-mailer/tree/v7.4.6" }, "funding": [ { @@ -7093,37 +7223,37 @@ "type": "tidelift" } ], - "time": "2026-02-09T09:33:46+00:00" + "time": "2026-02-11T15:05:50+00:00" }, { - "name": "symfony/brevo-mailer", - "version": "v7.4.0", + "name": "symfony/asset", + "version": "v7.4.6", "source": { "type": "git", - "url": "https://github.com/symfony/brevo-mailer.git", - "reference": "f1ef26ffe147e9185531030fc1503ed7b63fa0ef" + "url": "https://github.com/symfony/asset.git", + "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/brevo-mailer/zipball/f1ef26ffe147e9185531030fc1503ed7b63fa0ef", - "reference": "f1ef26ffe147e9185531030fc1503ed7b63fa0ef", + "url": "https://api.github.com/repos/symfony/asset/zipball/d944ae87e4697af05aadeacfc5e603c3c18ef4fb", + "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/mailer": "^7.2|^8.0" + "php": ">=8.2" }, "conflict": { - "symfony/mime": "<6.2" + "symfony/http-foundation": "<6.4" }, "require-dev": { - "symfony/http-client": "^6.3|^7.0|^8.0", - "symfony/webhook": "^6.3|^7.0|^8.0" + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, - "type": "symfony-mailer-bridge", + "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Mailer\\Bridge\\Brevo\\": "" + "Symfony\\Component\\Asset\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -7135,18 +7265,18 @@ ], "authors": [ { - "name": "Pierre Tanguy", - "homepage": "https://github.com/petanguy" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Brevo Mailer Bridge", + "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/brevo-mailer/tree/v7.4.0" + "source": "https://github.com/symfony/asset/tree/v7.4.6" }, "funding": [ { @@ -7166,7 +7296,7 @@ "type": "tidelift" } ], - "time": "2025-08-04T08:00:56+00:00" + "time": "2026-02-09T09:33:46+00:00" }, { "name": "symfony/cache", @@ -8729,16 +8859,16 @@ }, { "name": "symfony/http-client", - "version": "v7.4.7", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "1010624285470eb60e88ed10035102c75b4ea6af" + "reference": "01933e626c3de76bea1e22641e205e78f6a34342" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/1010624285470eb60e88ed10035102c75b4ea6af", - "reference": "1010624285470eb60e88ed10035102c75b4ea6af", + "url": "https://api.github.com/repos/symfony/http-client/zipball/01933e626c3de76bea1e22641e205e78f6a34342", + "reference": "01933e626c3de76bea1e22641e205e78f6a34342", "shasum": "" }, "require": { @@ -8806,7 +8936,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.4.7" + "source": "https://github.com/symfony/http-client/tree/v7.4.8" }, "funding": [ { @@ -8826,7 +8956,7 @@ "type": "tidelift" } ], - "time": "2026-03-05T11:16:58+00:00" + "time": "2026-03-30T12:55:43+00:00" }, { "name": "symfony/http-client-contracts", @@ -9199,16 +9329,16 @@ }, { "name": "symfony/mailer", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9" + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/b02726f39a20bc65e30364f5c750c4ddbf1f58e9", - "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f6ea532250b476bfc1b56699b388a1bdbf168f62", + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62", "shasum": "" }, "require": { @@ -9259,7 +9389,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.6" + "source": "https://github.com/symfony/mailer/tree/v7.4.8" }, "funding": [ { @@ -9279,20 +9409,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/mime", - "version": "v7.4.7", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1" + "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1", - "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "url": "https://api.github.com/repos/symfony/mime/zipball/6df02f99998081032da3407a8d6c4e1dcb5d4379", + "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379", "shasum": "" }, "require": { @@ -9348,7 +9478,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.7" + "source": "https://github.com/symfony/mime/tree/v7.4.8" }, "funding": [ { @@ -9368,7 +9498,7 @@ "type": "tidelift" } ], - "time": "2026-03-05T15:24:09+00:00" + "time": "2026-03-30T14:11:46+00:00" }, { "name": "symfony/monolog-bridge", @@ -10018,7 +10148,7 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.33.0", + "version": "v1.36.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -10081,7 +10211,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.36.0" }, "funding": [ { @@ -10105,7 +10235,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.34.0", + "version": "v1.36.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -10166,7 +10296,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.34.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.36.0" }, "funding": [ { @@ -10190,7 +10320,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.34.0", + "version": "v1.36.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -10251,7 +10381,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.34.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.36.0" }, "funding": [ { @@ -10275,7 +10405,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.34.0", + "version": "v1.36.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -10335,7 +10465,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.34.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.36.0" }, "funding": [ { @@ -10439,16 +10569,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.33.0", + "version": "v1.36.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/3600c2cb22399e25bb226e4a135ce91eeb2a6149", + "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149", "shasum": "" }, "require": { @@ -10495,7 +10625,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.36.0" }, "funding": [ { @@ -10515,7 +10645,7 @@ "type": "tidelift" } ], - "time": "2025-07-08T02:45:35+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/polyfill-php84", diff --git a/config/services.php b/config/services.php index 97860ff2b2..3686745b79 100644 --- a/config/services.php +++ b/config/services.php @@ -141,7 +141,7 @@ $parameters->set('catrobat.translations.project_cache_threshold', 15); $parameters->set('catrobat.upload.temp.dir', '%catrobat.pubdir%resources/tmp/uploads/'); $parameters->set('catrobat.upload.temp.path', 'resources/tmp/uploads/'); - $parameters->set('dkim.private.key', '%kernel.project_dir%/.dkim/private.key'); + $parameters->set('.container.dumper.inline_class_loader', true); $parameters->set('reset_password.throttle_limit', 86400); diff --git a/deploy.php b/deploy.php index eaaa31e0cf..1162ae45ef 100644 --- a/deploy.php +++ b/deploy.php @@ -44,7 +44,6 @@ add('shared_files', [ '.env.prod.local', // keep only production .env 'google_cloud_key.json', - '.dkim/private.key', ]); // Writable directories diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 0a617747d8..3ef9748672 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -475,11 +475,7 @@ - - - - - + getContent()]]> diff --git a/src/System/Mail/EmailBudgetManager.php b/src/System/Mail/EmailBudgetManager.php index 231a88cdb5..2dd4e81c0a 100644 --- a/src/System/Mail/EmailBudgetManager.php +++ b/src/System/Mail/EmailBudgetManager.php @@ -11,14 +11,14 @@ class EmailBudgetManager { - public const int DAILY_LIMIT = 300; + public const int DAILY_LIMIT = 5000; public const array TYPE_RESERVES = [ - 'verification' => 150, - 'reset' => 30, - 'consent' => 30, - 'admin' => 50, - 'management' => 40, + 'verification' => 2500, + 'reset' => 500, + 'consent' => 500, + 'admin' => 750, + 'management' => 750, ]; public function __construct( diff --git a/src/System/Mail/MailerAdapter.php b/src/System/Mail/MailerAdapter.php index 78a163cb92..32b1f13b88 100644 --- a/src/System/Mail/MailerAdapter.php +++ b/src/System/Mail/MailerAdapter.php @@ -6,12 +6,9 @@ use Psr\Log\LoggerInterface; use Symfony\Bridge\Twig\Mime\TemplatedEmail; -use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Address; -use Symfony\Component\Mime\Crypto\DkimSigner; -use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Message; use Twig\Environment; @@ -21,8 +18,6 @@ public function __construct( protected MailerInterface $mailer, protected LoggerInterface $logger, protected Environment $templateWrapper, - #[Autowire('%dkim.private.key%')] - protected string $dkim_private_key_path, protected EmailBudgetManager $budgetManager, ) { } @@ -36,7 +31,6 @@ public function send(string $to, string $subject, string $template, array $conte } $email = $this->buildEmail($to, $subject, $template, $context); - // $email = $this->signEmail($email); // Signing is currently disabled due to breveo $this->sendEmail($email, $to); $this->budgetManager->recordSend($emailType); @@ -62,19 +56,6 @@ protected function buildEmail(string $to, string $subject, string $template, arr ; } - protected function signEmail(Message $email): Message - { - try { - return new DkimSigner('file://'.$this->dkim_private_key_path, 'share.catrob.at', 'sf')->sign($email); - } catch (InvalidArgumentException $invalidArgumentException) { - if ('prod' === $_ENV['APP_ENV']) { - $this->logger->error(sprintf('Private dkim key is missing (%s): ', $this->dkim_private_key_path).$invalidArgumentException->getMessage()); - } - - return $email; - } - } - protected function sendEmail(Message $email, string $to): void { try { diff --git a/symfony.lock b/symfony.lock index b5f4411257..32d745882e 100644 --- a/symfony.lock +++ b/symfony.lock @@ -597,18 +597,18 @@ "stella-maris/clock": { "version": "0.1.4" }, - "symfony/asset": { - "version": "v4.4.5" - }, - "symfony/brevo-mailer": { - "version": "6.4", + "symfony/amazon-mailer": { + "version": "7.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "6.4", - "ref": "7c1038ceb733175f610a913a885a7c8b552b703a" + "version": "4.4", + "ref": "9648db3ecae5c8a6b1a5f74715d3907124348815" } }, + "symfony/asset": { + "version": "v4.4.5" + }, "symfony/browser-kit": { "version": "v5.0.5" }, diff --git a/tests/PhpUnit/Admin/System/Maintenance/SystemHealthServiceTest.php b/tests/PhpUnit/Admin/System/Maintenance/SystemHealthServiceTest.php index 57a0e318b6..479f104266 100644 --- a/tests/PhpUnit/Admin/System/Maintenance/SystemHealthServiceTest.php +++ b/tests/PhpUnit/Admin/System/Maintenance/SystemHealthServiceTest.php @@ -69,15 +69,15 @@ public function testGetEmailBudgetReturnsCorrectStructure(): void { $email = $this->service->getEmailBudget(); - self::assertSame(300, $email['daily_limit']); + self::assertSame(EmailBudgetManager::DAILY_LIMIT, $email['daily_limit']); self::assertSame(25, $email['sent_today']); - self::assertSame(275, $email['remaining']); + self::assertSame(EmailBudgetManager::DAILY_LIMIT - 25, $email['remaining']); self::assertArrayHasKey('breakdown', $email); self::assertArrayHasKey('verification', $email['breakdown']); self::assertArrayHasKey('reset', $email['breakdown']); self::assertSame(10, $email['breakdown']['verification']['sent']); - self::assertSame(150, $email['breakdown']['verification']['reserve']); - self::assertSame(140, $email['breakdown']['verification']['remaining']); + self::assertSame(EmailBudgetManager::TYPE_RESERVES['verification'], $email['breakdown']['verification']['reserve']); + self::assertSame(EmailBudgetManager::TYPE_RESERVES['verification'] - 10, $email['breakdown']['verification']['remaining']); } public function testGetProjectCountsReturnsAllCategories(): void diff --git a/tests/PhpUnit/System/Mail/EmailBudgetManagerTest.php b/tests/PhpUnit/System/Mail/EmailBudgetManagerTest.php index 4bcae1c325..9a88cc7479 100644 --- a/tests/PhpUnit/System/Mail/EmailBudgetManagerTest.php +++ b/tests/PhpUnit/System/Mail/EmailBudgetManagerTest.php @@ -53,12 +53,11 @@ public function testCanSendReturnsFalseWhenDailyLimitReached(): void public function testCanSendRespectsTypeReserve(): void { - // Fill up verification reserve (150) - $this->budget->setVerificationSent(150); - $this->budget->setTotalSent(150); + // Fill up verification reserve (2500) + $this->budget->setVerificationSent(2500); + $this->budget->setTotalSent(2500); - // Verification can still send from shared pool (300 - 300 reserves = 0 shared) - // Total reserved = 150 + 30 + 30 + 50 + 40 = 300, shared pool = 0 + // Total reserved = 2500 + 500 + 500 + 750 + 750 = 5000, shared pool = 0 self::assertFalse($this->manager->canSend('verification')); // Other types are still within their reserves @@ -67,10 +66,10 @@ public function testCanSendRespectsTypeReserve(): void public function testCanSendAllowsOverflowIntoSharedPool(): void { - // With total reserves = 300 and daily limit = 300, shared pool = 0 + // With total reserves = 5000 and daily limit = 5000, shared pool = 0 // So overflowing a reserve is NOT possible when reserves sum to daily limit - $this->budget->setVerificationSent(150); - $this->budget->setTotalSent(150); + $this->budget->setVerificationSent(2500); + $this->budget->setTotalSent(2500); self::assertFalse($this->manager->canSend('verification')); } @@ -107,23 +106,23 @@ public function testGetRemainingBudget(): void $remaining = $this->manager->getRemainingBudget(); - self::assertSame(148, $remaining['verification']); - self::assertSame(29, $remaining['reset']); - self::assertSame(30, $remaining['consent']); - self::assertSame(50, $remaining['admin']); - self::assertSame(40, $remaining['management']); - self::assertSame(297, $remaining['total']); + self::assertSame(2498, $remaining['verification']); + self::assertSame(499, $remaining['reset']); + self::assertSame(500, $remaining['consent']); + self::assertSame(750, $remaining['admin']); + self::assertSame(750, $remaining['management']); + self::assertSame(4997, $remaining['total']); } public function testGetRemainingBudgetNeverNegative(): void { - $this->budget->setResetSent(100); - $this->budget->setTotalSent(100); + $this->budget->setResetSent(1000); + $this->budget->setTotalSent(1000); $remaining = $this->manager->getRemainingBudget(); self::assertSame(0, $remaining['reset']); - self::assertSame(200, $remaining['total']); + self::assertSame(4000, $remaining['total']); } public function testCanSendThrowsOnInvalidType(): void @@ -143,12 +142,12 @@ public function testRecordSendThrowsOnInvalidType(): void public function testBudgetExhaustionByType(): void { // Fill reset reserve completely - for ($i = 0; $i < 30; ++$i) { + for ($i = 0; $i < 500; ++$i) { self::assertTrue($this->manager->canSend('reset')); $this->manager->recordSend('reset'); } - // Reset reserve exhausted, shared pool = 0 (reserves sum to 300 = daily limit) + // Reset reserve exhausted, shared pool = 0 (reserves sum to 5000 = daily limit) self::assertFalse($this->manager->canSend('reset')); // Other types still have budget within their reserves @@ -158,7 +157,7 @@ public function testBudgetExhaustionByType(): void public function testTotalLimitPreventsAllSending(): void { - $this->budget->setTotalSent(300); + $this->budget->setTotalSent(5000); $this->budget->setVerificationSent(0); self::assertFalse($this->manager->canSend('verification'));