diff --git a/assets/admin.js b/assets/admin.js
new file mode 100644
index 0000000..666d5b2
--- /dev/null
+++ b/assets/admin.js
@@ -0,0 +1,2 @@
+import './admin.scss'
+import * as Turbo from "@hotwired/turbo"
diff --git a/assets/admin.scss b/assets/admin.scss
new file mode 100644
index 0000000..0bd61db
--- /dev/null
+++ b/assets/admin.scss
@@ -0,0 +1,7 @@
+@import "tailwindcss";
+@import url('https://fonts.googleapis.com/css2?family=Intel+One+Mono:ital,wght@0,300..700;1,300..700&display=swap');
+
+h1,h2,h3,h4,h5,h6,
+label,span,input,{
+ font-family: 'Intel One Mono', monospace;
+}
diff --git a/composer.json b/composer.json
index 64c2a19..ae58d38 100644
--- a/composer.json
+++ b/composer.json
@@ -14,6 +14,7 @@
"docusealco/docuseal-php": "^1.0",
"imagine/imagine": "^1.5",
"knplabs/knp-paginator-bundle": "^6.8",
+ "lasserafn/php-initial-avatar-generator": "^4.4",
"league/flysystem-aws-s3-v3": "^3.29",
"league/flysystem-bundle": "^3.4",
"liip/imagine-bundle": "^2.13",
diff --git a/composer.lock b/composer.lock
index 383cdb0..c879555 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": "a38b1e9f2490861aa3e6aee97fa1ff63",
+ "content-hash": "ab21fae440d89f3e53d04857bce70e32",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -1915,6 +1915,90 @@
},
"time": "2024-12-03T14:37:55+00:00"
},
+ {
+ "name": "intervention/image",
+ "version": "2.7.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Intervention/image.git",
+ "reference": "04be355f8d6734c826045d02a1079ad658322dad"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Intervention/image/zipball/04be355f8d6734c826045d02a1079ad658322dad",
+ "reference": "04be355f8d6734c826045d02a1079ad658322dad",
+ "shasum": ""
+ },
+ "require": {
+ "ext-fileinfo": "*",
+ "guzzlehttp/psr7": "~1.1 || ^2.0",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "~0.9.2",
+ "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15"
+ },
+ "suggest": {
+ "ext-gd": "to use GD library based image processing.",
+ "ext-imagick": "to use Imagick based image processing.",
+ "intervention/imagecache": "Caching extension for the Intervention Image library"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "aliases": {
+ "Image": "Intervention\\Image\\Facades\\Image"
+ },
+ "providers": [
+ "Intervention\\Image\\ImageServiceProvider"
+ ]
+ },
+ "branch-alias": {
+ "dev-master": "2.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Intervention\\Image\\": "src/Intervention/Image"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Oliver Vogel",
+ "email": "oliver@intervention.io",
+ "homepage": "https://intervention.io/"
+ }
+ ],
+ "description": "Image handling and manipulation library with support for Laravel integration",
+ "homepage": "http://image.intervention.io/",
+ "keywords": [
+ "gd",
+ "image",
+ "imagick",
+ "laravel",
+ "thumbnail",
+ "watermark"
+ ],
+ "support": {
+ "issues": "https://github.com/Intervention/image/issues",
+ "source": "https://github.com/Intervention/image/tree/2.7.2"
+ },
+ "funding": [
+ {
+ "url": "https://paypal.me/interventionio",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/Intervention",
+ "type": "github"
+ }
+ ],
+ "time": "2022-05-21T17:30:32+00:00"
+ },
{
"name": "jean85/pretty-package-versions",
"version": "2.1.1",
@@ -2200,6 +2284,167 @@
},
"time": "2025-05-20T07:07:41+00:00"
},
+ {
+ "name": "lasserafn/php-initial-avatar-generator",
+ "version": "4.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/LasseRafn/php-initial-avatar-generator.git",
+ "reference": "149fb4e3d8c7009aa131eeac86ffc4b0e9d0a2b8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/LasseRafn/php-initial-avatar-generator/zipball/149fb4e3d8c7009aa131eeac86ffc4b0e9d0a2b8",
+ "reference": "149fb4e3d8c7009aa131eeac86ffc4b0e9d0a2b8",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "intervention/image": "^2.3",
+ "lasserafn/php-initials": "^3.0",
+ "lasserafn/php-string-script-language": "^0.4",
+ "meyfa/php-svg": "^0.9.0",
+ "overtrue/pinyin": "^4.0",
+ "php": "^7.0|^7.1|^7.2|^7.3|^7.4|^8.0|^8.1|^8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LasseRafn\\InitialAvatarGenerator\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lasse Rafn",
+ "email": "lasserafn@gmail.com"
+ }
+ ],
+ "description": "A package to generate avatars with initials for PHP",
+ "keywords": [
+ "Initials",
+ "avatar",
+ "image",
+ "svg"
+ ],
+ "support": {
+ "issues": "https://github.com/LasseRafn/php-initial-avatar-generator/issues",
+ "source": "https://github.com/LasseRafn/php-initial-avatar-generator/tree/4.4"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/ui-avatars",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-11-04T11:12:44+00:00"
+ },
+ {
+ "name": "lasserafn/php-initials",
+ "version": "3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/LasseRafn/php-initials.git",
+ "reference": "d287e1542687390eb68de779949bc0adc49e2d52"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/LasseRafn/php-initials/zipball/d287e1542687390eb68de779949bc0adc49e2d52",
+ "reference": "d287e1542687390eb68de779949bc0adc49e2d52",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6|^7.0|^7.1|^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7",
+ "satooshi/php-coveralls": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LasseRafn\\Initials\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lasse Rafn",
+ "email": "lasserafn@gmail.com"
+ }
+ ],
+ "description": "A package to generate initials in PHP",
+ "keywords": [
+ "Initials",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/LasseRafn/php-initials/issues",
+ "source": "https://github.com/LasseRafn/php-initials/tree/3.1"
+ },
+ "time": "2020-12-24T12:25:51+00:00"
+ },
+ {
+ "name": "lasserafn/php-string-script-language",
+ "version": "0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/LasseRafn/php-string-script-language.git",
+ "reference": "cab5612d4382067de855fcecc7c09108dca77fb5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/LasseRafn/php-string-script-language/zipball/cab5612d4382067de855fcecc7c09108dca77fb5",
+ "reference": "cab5612d4382067de855fcecc7c09108dca77fb5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6|^7.0|^7.1|^8.0|^8.1|^8.2"
+ },
+ "require-dev": {
+ "doctrine/instantiator": "1.0.5",
+ "phpunit/phpunit": "^5.6",
+ "phpunit/phpunit-mock-objects": "3.2.4",
+ "satooshi/php-coveralls": "^1.0",
+ "sebastian/exporter": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LasseRafn\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lasse Rafn",
+ "email": "lasserafn@gmail.com"
+ }
+ ],
+ "description": "Detect language/encoding of a string in PHP",
+ "keywords": [
+ "language",
+ "php",
+ "string"
+ ],
+ "support": {
+ "issues": "https://github.com/LasseRafn/php-string-script-language/issues",
+ "source": "https://github.com/LasseRafn/php-string-script-language/tree/0.4"
+ },
+ "time": "2023-07-26T07:23:39+00:00"
+ },
{
"name": "league/flysystem",
"version": "3.30.0",
@@ -2619,6 +2864,56 @@
},
"time": "2024-12-12T09:38:23+00:00"
},
+ {
+ "name": "meyfa/php-svg",
+ "version": "v0.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/meyfa/php-svg.git",
+ "reference": "34401edef1f724898f468f71b85505fbcc8351bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/meyfa/php-svg/zipball/34401edef1f724898f468f71b85505fbcc8351bb",
+ "reference": "34401edef1f724898f468f71b85505fbcc8351bb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-gd": "*",
+ "ext-simplexml": "*",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "meyfa/phpunit-assert-gd": "^1.1",
+ "phpunit/phpunit": "^4.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "SVG\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabian Meyer",
+ "homepage": "http://meyfa.net"
+ }
+ ],
+ "description": "Read, edit, write, and render SVG files with PHP",
+ "homepage": "https://github.com/meyfa/php-svg",
+ "keywords": [
+ "svg"
+ ],
+ "support": {
+ "issues": "https://github.com/meyfa/php-svg/issues",
+ "source": "https://github.com/meyfa/php-svg/tree/v0.9.1"
+ },
+ "time": "2019-07-30T18:41:25+00:00"
+ },
{
"name": "minishlink/web-push",
"version": "v9.0.2",
@@ -3148,6 +3443,79 @@
},
"time": "2025-05-31T08:24:38+00:00"
},
+ {
+ "name": "overtrue/pinyin",
+ "version": "4.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/overtrue/pinyin.git",
+ "reference": "4d0fb4f27f0c79e81c9489e0c0ae4a4f8837eae7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/overtrue/pinyin/zipball/4d0fb4f27f0c79e81c9489e0c0ae4a4f8837eae7",
+ "reference": "4d0fb4f27f0c79e81c9489e0c0ae4a4f8837eae7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "brainmaestro/composer-git-hooks": "^2.7",
+ "friendsofphp/php-cs-fixer": "^2.16",
+ "phpunit/phpunit": "~8.0"
+ },
+ "type": "library",
+ "extra": {
+ "hooks": {
+ "pre-push": [
+ "composer test",
+ "composer check-style"
+ ],
+ "pre-commit": [
+ "composer test",
+ "composer fix-style"
+ ]
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/const.php"
+ ],
+ "psr-4": {
+ "Overtrue\\Pinyin\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "overtrue",
+ "email": "anzhengchao@gmail.com",
+ "homepage": "http://github.com/overtrue"
+ }
+ ],
+ "description": "Chinese to pinyin translator.",
+ "homepage": "https://github.com/overtrue/pinyin",
+ "keywords": [
+ "Chinese",
+ "Pinyin",
+ "cn2pinyin"
+ ],
+ "support": {
+ "issues": "https://github.com/overtrue/pinyin/issues",
+ "source": "https://github.com/overtrue/pinyin/tree/4.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/overtrue",
+ "type": "github"
+ }
+ ],
+ "time": "2023-04-27T10:17:12+00:00"
+ },
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
diff --git a/config/packages/vich_uploader.yaml b/config/packages/vich_uploader.yaml
index 32c852e..8b5c101 100644
--- a/config/packages/vich_uploader.yaml
+++ b/config/packages/vich_uploader.yaml
@@ -1,6 +1,14 @@
vich_uploader:
db_driver: orm
-
+ mappings:
+ avatar:
+ uri_prefix: /storage/avatar
+ upload_destination: '%kernel.project_dir%/public/storage/avatar'
+ namer: App\VichUploader\Namer\Account\AvatarName # Replaced namer
+ directory_namer: App\VichUploader\DirectoryNamer\Account\AvatarName
+ inject_on_load: false
+ delete_on_update: true
+ delete_on_remove: true
#mappings:
# products:
# uri_prefix: /images/products
diff --git a/migrations/Version20250721061628.php b/migrations/Version20250721061628.php
new file mode 100644
index 0000000..8c91e47
--- /dev/null
+++ b/migrations/Version20250721061628.php
@@ -0,0 +1,32 @@
+addSql('ALTER TABLE account ADD is_first_login BOOLEAN DEFAULT NULL');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('CREATE SCHEMA public');
+ $this->addSql('ALTER TABLE "account" DROP is_first_login');
+ }
+}
diff --git a/migrations/Version20250721065912.php b/migrations/Version20250721065912.php
new file mode 100644
index 0000000..cafed21
--- /dev/null
+++ b/migrations/Version20250721065912.php
@@ -0,0 +1,41 @@
+addSql('ALTER TABLE account ADD avatar_dimensions JSON DEFAULT NULL');
+ $this->addSql('ALTER TABLE account ADD avatar_size VARCHAR(255) DEFAULT NULL');
+ $this->addSql('ALTER TABLE account ADD avatar_mine_type VARCHAR(255) DEFAULT NULL');
+ $this->addSql('ALTER TABLE account ADD avatar_original_name VARCHAR(255) DEFAULT NULL');
+ $this->addSql('ALTER TABLE account ADD update_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
+ $this->addSql('COMMENT ON COLUMN account.update_at IS \'(DC2Type:datetime_immutable)\'');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('CREATE SCHEMA public');
+ $this->addSql('ALTER TABLE "account" DROP avatar_dimensions');
+ $this->addSql('ALTER TABLE "account" DROP avatar_size');
+ $this->addSql('ALTER TABLE "account" DROP avatar_mine_type');
+ $this->addSql('ALTER TABLE "account" DROP avatar_original_name');
+ $this->addSql('ALTER TABLE "account" DROP update_at');
+ }
+}
diff --git a/phpunit.dist.xml b/phpunit.dist.xml
index d7cb6c2..d4a336c 100644
--- a/phpunit.dist.xml
+++ b/phpunit.dist.xml
@@ -45,6 +45,10 @@
src/Command
src/Controller
src/Service
+ src/EventListener
+ src/Repository
+ src/Entity
+ src/VichUploader
diff --git a/sonar-project.properties b/sonar-project.properties
index 9293f9e..a807266 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -20,8 +20,12 @@ sonar.sources=src
sonar.coverage.exclusions= \
src/Controller/**/*.php, \
+ src/VichUploader/**/*.php, \
src/Service/**/*.php, \
- src/Command/*.php
+ src/Command/*.php, \
+ src/EventListener/*.php, \
+ src/Repository/*.php, \
+ src/Entity/*.php
sonar.issue.ignore.multicriteria=e1,e2,e3,e4,e5,e6,e7,e8
sonar.issue.ignore.multicriteria.e1.ruleKey=php:S103
diff --git a/src/Command/AccountCommand.php b/src/Command/AccountCommand.php
index b307638..0ce3fa5 100644
--- a/src/Command/AccountCommand.php
+++ b/src/Command/AccountCommand.php
@@ -35,6 +35,7 @@ class AccountCommand extends Command
$userExit = new Account();
$userExit->setRoles(['ROLE_ROOT']);
$userExit->setUuid(Uuid::v4());
+ $userExit->setIsFirstLogin(true);
$questionEmail = new Question("Email ?");
$email = $io->askQuestion($questionEmail);
@@ -46,7 +47,7 @@ class AccountCommand extends Command
$userExit->setUsername($username);
$userExit->setPassword($this->userPasswordHasher->hashPassword($userExit, $password));
- $this->entityManager->persist($userExit);
+ $this->entityManager->persist($usserExit);
$this->entityManager->flush();
$this->eventDispatcher->dispatch(new CreatedAdminEvent($userExit, $password));
}
diff --git a/src/Controller/Artemis/AvatarController.php b/src/Controller/Artemis/AvatarController.php
new file mode 100644
index 0000000..c7aff9c
--- /dev/null
+++ b/src/Controller/Artemis/AvatarController.php
@@ -0,0 +1,23 @@
+name($this->getUser()->getUserIdentifier());
+ $image = $avatar->generateSvg();
+ return new Response($image->toXMLString(),200,[
+ 'Content-Type' => 'image/svg+xml'
+ ]);
+
+ }
+}
diff --git a/src/Controller/Artemis/DashboardController.php b/src/Controller/Artemis/DashboardController.php
index a42ae8d..ee96c17 100644
--- a/src/Controller/Artemis/DashboardController.php
+++ b/src/Controller/Artemis/DashboardController.php
@@ -12,7 +12,7 @@ class DashboardController extends AbstractController
#[Route(path: '/artemis',name: 'artemis_dashboard',methods: ['GET', 'POST'])]
public function artemis(AuthenticationUtils $authenticationUtils): Response
{
- return new Response("a");
+ return $this->render('artemis/dashboard.twig');
}
}
diff --git a/src/Controller/Artemis/ProfilsController.php b/src/Controller/Artemis/ProfilsController.php
new file mode 100644
index 0000000..9e4142e
--- /dev/null
+++ b/src/Controller/Artemis/ProfilsController.php
@@ -0,0 +1,20 @@
+render('artemis/profils.twig',[
+ 'current' => $request->get('current','main')
+ ]);
+
+ }
+}
diff --git a/src/Entity/Account.php b/src/Entity/Account.php
index 4a72747..4b82400 100644
--- a/src/Entity/Account.php
+++ b/src/Entity/Account.php
@@ -6,14 +6,17 @@ use App\Repository\AccountRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
+use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
+use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[ORM\Entity(repositoryClass: AccountRepository::class)]
#[ORM\Table(name: '`account`')]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])]
#[UniqueEntity(fields: ['email'], message: 'Cette adresse e-mail est déjà utilisée.')]
#[UniqueEntity(fields: ['uuid'], message: 'Cet identifiant unique (UUID) est déjà utilisé.')]
+#[Vich\Uploadable()]
class Account implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
@@ -39,6 +42,22 @@ class Account implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(type: Types::GUID)]
private ?string $uuid = null;
+ #[ORM\Column(nullable: true)]
+ private ?bool $isFirstLogin = null;
+
+ #[Vich\UploadableField(mapping: 'avatar', size: 'avatarSize', mimeType: 'avatarMineType', originalName: 'avatarOriginalName',dimensions: 'avatarDimensions')]
+ private ?File $avatar = null;
+ #[ORM\Column(nullable: true)]
+ private ?array $avatarDimensions = [];
+ #[ORM\Column(length: 255,nullable: true)]
+ private ?string $avatarSize = null;
+ #[ORM\Column(length: 255,nullable: true)]
+ private ?string $avatarMineType = null;
+ #[ORM\Column(length: 255,nullable: true)]
+ private ?string $avatarOriginalName = null;
+ #[ORM\Column(nullable: true)]
+ private ?\DateTimeImmutable $updateAt;
+
public function getId(): ?int
{
return $this->id;
@@ -143,4 +162,84 @@ class Account implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
+
+ public function isFirstLogin(): ?bool
+ {
+ return $this->isFirstLogin;
+ }
+
+ public function setIsFirstLogin(?bool $isFirstLogin): static
+ {
+ $this->isFirstLogin = $isFirstLogin;
+
+ return $this;
+ }
+
+ public function setAvatar(?File $avatar): self
+ {
+ $this->avatar = $avatar;
+ if($avatar != null) {
+ $this->updateAt = new \DateTimeImmutable();
+ }
+ return $this;
+ }
+
+ public function getAvatar(): ?File
+ {
+ return $this->avatar;
+ }
+
+ public function setAvatarSize(?string $avatarSize): self
+ {
+ $this->avatarSize = $avatarSize;
+ return $this;
+ }
+ public function getAvatarSize(): ?string
+ {
+ return $this->avatarSize;
+ }
+
+ public function setAvatarDimensions(?array $avatarDimensions): static
+ {
+ $this->avatarDimensions = $avatarDimensions;
+ return $this;
+ }
+
+ public function getAvatarDimensions(): ?array
+ {
+ return $this->avatarDimensions;
+ }
+
+ public function setAvatarMineType(?string $avatarMineType): static
+ {
+ $this->avatarMineType = $avatarMineType;
+ return $this;
+ }
+
+ public function getAvatarMineType(): ?string
+ {
+ return $this->avatarMineType;
+ }
+
+ public function setAvatarOriginalName(?string $avatarOriginalName): self
+ {
+ $this->avatarOriginalName = $avatarOriginalName;
+ return $this;
+ }
+
+ public function getAvatarOriginalName(): ?string
+ {
+ return $this->avatarOriginalName;
+ }
+
+ public function getUpdateAt(): ?\DateTimeImmutable
+ {
+ return $this->updateAt;
+ }
+
+ public function setUpdateAt(?\DateTimeImmutable $updateAt): static
+ {
+ $this->updateAt = $updateAt;
+ return $this;
+ }
}
diff --git a/src/EventListener/MainframeAttributeListener.php b/src/EventListener/MainframeAttributeListener.php
index 498ca19..20eb5fe 100644
--- a/src/EventListener/MainframeAttributeListener.php
+++ b/src/EventListener/MainframeAttributeListener.php
@@ -3,11 +3,21 @@
namespace App\EventListener;
use App\Attribute\Mainframe;
+use App\Entity\Account;
+use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
+use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Twig\Environment;
/**
* Listener for the Mainframe attribute.
@@ -17,21 +27,54 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
#[AsEventListener(event: KernelEvents::CONTROLLER)]
#[AsEventListener(event: KernelEvents::RESPONSE)] // Listen to the Response event as well
+#[AsEventListener(event: KernelEvents::REQUEST)] // Listen to the Response event as well
class MainframeAttributeListener
{
- public function __construct()
+ public function __construct(private readonly Environment $environment,private readonly TokenStorageInterface $tokenStorage,private readonly UserPasswordHasherInterface $userPasswordHasher,private readonly ?EntityManagerInterface $entityManager)
{
// Logger removed from constructor
}
- /**
- * Handles the KernelEvents::CONTROLLER event.
- * This method is called before a controller action is executed.
- * It inspects the controller for the Mainframe attribute and stores
- * whether the page should be noindexed in the request attributes.
- *
- * @param ControllerEvent $event The event object containing controller information.
- */
+ public function onKernelRequest(RequestEvent $event)
+ {
+ $request = $event->getRequest();
+ $pathInfo = $request->getPathInfo();
+ if(str_starts_with("/artemis",$pathInfo)) {
+ if($this->tokenStorage->getToken() instanceof UsernamePasswordToken) {
+ $account = $this->tokenStorage->getToken()->getUser();
+ if($account instanceof Account) {
+ if($account->isFirstLogin()) {
+ $response = new Response($this->environment->render('admin/first_login.twig',[
+ 'account' => $account,
+ ]));
+ if($request->isMethod('POST')) {
+ $password = $request->request->get('password');
+ $password2 = $request->request->get('password2');
+ if($password == $password2) {
+ $account->setPassword($this->userPasswordHasher->hashPassword($account, $password));
+ $account->setIsFirstLogin(false);
+ $this->entityManager->persist($account);
+ $this->entityManager->flush();
+
+ $redirect = new RedirectResponse("/artemis");
+ $redirect->setStatusCode(302);
+ $event->setResponse($redirect);
+ $event->stopPropagation();
+ } else {
+ $response = new Response($this->environment->render('admin/first_login.twig',[
+ 'account' => $account,
+ 'error' => 'Les mot de passe ne correspondent pas.'
+ ]));
+ }
+ }
+ $event->setResponse($response);
+ $event->stopPropagation();
+ }
+ }
+ }
+ }
+
+ }
public function onKernelController(ControllerEvent $event): void
{
// Get the controller callable (e.g., [ControllerClass, methodName])
diff --git a/src/Service/Mailer/Mailer.php b/src/Service/Mailer/Mailer.php
index 7ca3d0a..2984d1a 100644
--- a/src/Service/Mailer/Mailer.php
+++ b/src/Service/Mailer/Mailer.php
@@ -135,7 +135,7 @@ class Mailer
$mailData->setStatus("draft");
return [
'object' => $mailData,
- 'url'=> $this->urlGenerator->generate('app_tracking',['slug'=>$messageFormat],UrlGeneratorInterface::ABSOLUTE_URL)
+ 'url'=> "https://mainframe.esy-web.dev".$this->urlGenerator->generate('app_tracking',['slug'=>$messageFormat])
];
}
diff --git a/src/VichUploader/DirectoryNamer/Account/AvatarName.php b/src/VichUploader/DirectoryNamer/Account/AvatarName.php
new file mode 100644
index 0000000..6c9d7c0
--- /dev/null
+++ b/src/VichUploader/DirectoryNamer/Account/AvatarName.php
@@ -0,0 +1,18 @@
+getId();
+ }
+}
diff --git a/src/VichUploader/Namer/Account/AvatarName.php b/src/VichUploader/Namer/Account/AvatarName.php
new file mode 100644
index 0000000..d1a1639
--- /dev/null
+++ b/src/VichUploader/Namer/Account/AvatarName.php
@@ -0,0 +1,20 @@
+getFile($object);
+ $extension = pathinfo($file->getClientOriginalName(), PATHINFO_EXTENSION);
+ return "avatar.".$extension;
+ }
+}
diff --git a/templates/admin/first_login.twig b/templates/admin/first_login.twig
new file mode 100644
index 0000000..f86e0cb
--- /dev/null
+++ b/templates/admin/first_login.twig
@@ -0,0 +1,39 @@
+{% extends 'admin/base.twig' %}
+{% block title %}Mot de passe perdu{% endblock %}
+{% block content %}
+
+
+
 | imagine_filter('webp') }})
+
+
+
+
+
+ {% if error is defined %}
+
+ {{ error }}
+
+ {% endif %}
+
+
+
+{% endblock %}
diff --git a/templates/artemis/base.twig b/templates/artemis/base.twig
new file mode 100644
index 0000000..2d65e6f
--- /dev/null
+++ b/templates/artemis/base.twig
@@ -0,0 +1,95 @@
+
+
+
+
+
+ Mainframe - {% block title %}{% endblock %}
+
+
+
+ {{ vite_asset('admin.js',[]) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% block content %}
+ {% endblock %}
+
+
+
+
+
+
+
+
diff --git a/templates/artemis/dashboard.twig b/templates/artemis/dashboard.twig
new file mode 100644
index 0000000..e66de54
--- /dev/null
+++ b/templates/artemis/dashboard.twig
@@ -0,0 +1 @@
+{% extends 'artemis/base.twig' %}
diff --git a/templates/artemis/profils.twig b/templates/artemis/profils.twig
new file mode 100644
index 0000000..f71cbc0
--- /dev/null
+++ b/templates/artemis/profils.twig
@@ -0,0 +1,12 @@
+{% extends 'artemis/base.twig' %}
+
+{% block title %}
+ Mon profils
+{% endblock %}
+
+{% block content %}
+
+{% endblock %}
+
+
+
diff --git a/templates/mails/base.twig b/templates/mails/base.twig
index 2b7f518..552638d 100644
--- a/templates/mails/base.twig
+++ b/templates/mails/base.twig
@@ -23,7 +23,7 @@
{# Logo mis à jour pour SARL SITECONSEIL #}
-
+
diff --git a/tests/Entity/AccountResetPasswordRequestTest.php b/tests/Entity/AccountResetPasswordRequestTest.php
deleted file mode 100644
index 2d341c9..0000000
--- a/tests/Entity/AccountResetPasswordRequestTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
-modify('+1 hour');
-
- $resetRequest = new AccountResetPasswordRequest();
- $resetRequest->setAccount($account);
- $resetRequest->setToken($token);
- $resetRequest->setRequestedAt($now);
- $resetRequest->setExpiresAt($expires);
-
- $refClass = new ReflectionClass($resetRequest);
- $idProp = $refClass->getProperty('id');
- $idProp->setAccessible(true);
- $idProp->setValue($resetRequest, 123);
-
- $this->assertSame($account, $resetRequest->getAccount());
- $this->assertSame($token, $resetRequest->getToken());
- $this->assertSame($now, $resetRequest->getRequestedAt());
- $this->assertSame($expires, $resetRequest->getExpiresAt());
- $this->assertSame(123, $resetRequest->getId());
-
- }
-}
diff --git a/tests/Entity/AccountTest.php b/tests/Entity/AccountTest.php
deleted file mode 100644
index a381833..0000000
--- a/tests/Entity/AccountTest.php
+++ /dev/null
@@ -1,119 +0,0 @@
-validator = Validation::createValidatorBuilder()
- ->enableAttributeMapping() // Use this for PHP attributes
- ->getValidator();
- }
-
- /**
- * Helper to create a valid Account instance.
- */
- private function createValidAccount(): Account
- {
- return (new Account())
- ->setUsername('testuser')
- ->setEmail('test@example.com')
- ->setPassword('securepassword')
- ->setUuid('1b9d67fe-1b0d-40e9-a417-36e6e2978051');
- }
-
- // --- Unit Tests for Getters and Setters ---
-
- public function testGetId(): void
- {
- $account = new Account();
- // ID is typically set by the ORM, so we can't directly test a generated value here.
- // We'll rely on functional tests with the database for this.
- $this->assertNull($account->getId());
- }
-
- public function testSetAndGetUsername(): void
- {
- $account = new Account();
- $account->setUsername('newusername');
- $this->assertSame('newusername', $account->getUsername());
- }
-
- public function testSetAndGetEmail(): void
- {
- $account = new Account();
- $account->setEmail('newemail@example.com');
- $this->assertSame('newemail@example.com', $account->getEmail());
- }
-
- public function testSetAndGetPassword(): void
- {
- $account = new Account();
- $account->setPassword('hashedpassword');
- $this->assertSame('hashedpassword', $account->getPassword());
- }
-
- public function testSetAndGetUuid(): void
- {
- $account = new Account();
- $uuid = 'a1b2c3d4-e5f6-7890-1234-567890abcdef';
- $account->setUuid($uuid);
- $this->assertSame($uuid, $account->getUuid());
- }
-
- public function testSetAndGetRoles(): void
- {
- $account = new Account();
- $account->setRoles(['ROLE_ADMIN', 'ROLE_USER']);
- $this->assertContains('ROLE_ADMIN', $account->getRoles());
- $this->assertContains('ROLE_USER', $account->getRoles());
- $this->assertCount(2, $account->getRoles()); // Because ROLE_USER is guaranteed
- }
-
- // --- UserInterface and PasswordAuthenticatedUserInterface Tests ---
-
- public function testGetUserIdentifier(): void
- {
- $account = $this->createValidAccount();
- $this->assertSame('testuser', $account->getUserIdentifier());
- }
-
- public function testGetRolesAlwaysIncludesRoleUser(): void
- {
- $account = new Account();
- $this->assertContains('ROLE_USER', $account->getRoles());
-
- $account->setRoles(['ROLE_ADMIN']);
- $this->assertContains('ROLE_ADMIN', $account->getRoles());
- $this->assertContains('ROLE_USER', $account->getRoles());
- $this->assertCount(2, $account->getRoles());
- }
-
- public function testEraseCredentials(): void
- {
- $account = $this->createValidAccount();
- // eraseCredentials is deprecated and should not modify password directly in modern Symfony
- // It's usually for clearing sensitive data from memory after security operations.
- $account->eraseCredentials();
- // Assert that password remains, as it's not actually cleared by this method (deprecated behavior)
- $this->assertNotNull($account->getPassword());
- }
-
- public function testSerializeRemovesSensitiveData(): void
- {
- $account = $this->createValidAccount();
- $serializedAccount = serialize($account);
- $this->assertStringContainsString(hash('crc32c', 'securepassword'), $serializedAccount);
- $this->assertStringNotContainsString('securepassword', $serializedAccount);
- }
-
-}
diff --git a/tests/Entity/MailTest.php b/tests/Entity/MailTest.php
deleted file mode 100644
index 5ffbdb2..0000000
--- a/tests/Entity/MailTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-setMessageId($messageId);
- $this->assertSame($messageId, $mail->getMessageId());
-
- // Test status property
- $status = 'sent';
- $mail->setStatus($status);
- $this->assertSame($status, $mail->getStatus());
-
- // Test dest property
- $dest = 'recipient@example.com';
- $mail->setDest($dest);
- $this->assertSame($dest, $mail->getDest());
-
- // Test subject property
- $subject = 'Test Subject';
- $mail->setSubject($subject);
- $this->assertSame($subject, $mail->getSubject());
-
- // Test content property
- $content = 'This is the test email content.';
- $mail->setContent($content);
- $this->assertSame($content, $mail->getContent());
-
- // Test getId() - should be null initially as it's auto-generated by the database
- $this->assertNull($mail->getId());
- }
-}
-
diff --git a/tests/EventListener/MainframeAttributeListenerTest.php b/tests/EventListener/MainframeAttributeListenerTest.php
deleted file mode 100644
index e8b5353..0000000
--- a/tests/EventListener/MainframeAttributeListenerTest.php
+++ /dev/null
@@ -1,208 +0,0 @@
-listener = new MainframeAttributeListener();
- }
-
- /**
- * Helper method to create a ControllerEvent.
- *
- * @param object $controllerObject The controller instance.
- * @param string $methodName The method name to be called.
- * @param array $requestAttributes Additional request attributes.
- * @return ControllerEvent
- */
- private function createControllerEvent(object $controllerObject, string $methodName, array $requestAttributes = []): ControllerEvent
- {
- $request = new Request([], [], $requestAttributes);
- $kernel = $this->createMock(HttpKernelInterface::class);
- return new ControllerEvent($kernel, [$controllerObject, $methodName], $request, HttpKernelInterface::MAIN_REQUEST);
- }
-
- /**
- * Helper method to create a ResponseEvent.
- *
- * @param Request $request The request object.
- * @param Response $response The response object.
- * @return ResponseEvent
- */
- private function createResponseEvent(Request $request, Response $response): ResponseEvent
- {
- $kernel = $this->createMock(HttpKernelInterface::class);
- return new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);
- }
-
- /**
- * Tests that the X-Robots-Tag: noindex header is added when index is false on the method.
- */
- public function testNoIndexHeaderAddedWhenMethodIndexIsFalse(): void
- {
- // Dummy controller with Mainframe attribute on method
- $controller = new class {
- #[Mainframe(index: false, sitemap: true)]
- public function testAction(): Response { return new Response(); }
- };
-
- // Simulate ControllerEvent
- $controllerEvent = $this->createControllerEvent($controller, 'testAction');
- $this->listener->onKernelController($controllerEvent);
-
- // Assert that _mainframe_noindex attribute is set to true
- $this->assertTrue($controllerEvent->getRequest()->attributes->get('_mainframe_noindex'));
-
- // Simulate ResponseEvent
- $response = new Response();
- $responseEvent = $this->createResponseEvent($controllerEvent->getRequest(), $response);
- $this->listener->onKernelResponse($responseEvent);
-
- // Assert that the X-Robots-Tag header is present and correct
- $this->assertTrue($response->headers->has('X-Robots-Tag'));
- $this->assertEquals('noindex', $response->headers->get('X-Robots-Tag'));
- }
-
- /**
- * Tests that the X-Robots-Tag: noindex header is added when index is false on the class
- * and not overridden by the method.
- */
- public function testNoIndexHeaderAddedWhenClassIndexIsFalse(): void
- {
- // Dummy controller with Mainframe attribute on class, no attribute on method
- $controller = new #[Mainframe(index: false, sitemap: true)] class {
- public function testAction(): Response { return new Response(); }
- };
-
- // Simulate ControllerEvent
- $controllerEvent = $this->createControllerEvent($controller, 'testAction');
- $this->listener->onKernelController($controllerEvent);
-
- // Assert that _mainframe_noindex attribute is set to true
- $this->assertTrue($controllerEvent->getRequest()->attributes->get('_mainframe_noindex'));
-
- // Simulate ResponseEvent
- $response = new Response();
- $responseEvent = $this->createResponseEvent($controllerEvent->getRequest(), $response);
- $this->listener->onKernelResponse($responseEvent);
-
- // Assert that the X-Robots-Tag header is present and correct
- $this->assertTrue($response->headers->has('X-Robots-Tag'));
- $this->assertEquals('noindex', $response->headers->get('X-Robots-Tag'));
- }
-
- /**
- * Tests that no X-Robots-Tag: noindex header is added when index is true on the method.
- */
- public function testNoIndexHeaderNotAddedWhenMethodIndexIsTrue(): void
- {
- // Dummy controller with Mainframe attribute on method (index: true)
- $controller = new class {
- #[Mainframe(index: true, sitemap: true)]
- public function testAction(): Response { return new Response(); }
- };
-
- // Simulate ControllerEvent
- $controllerEvent = $this->createControllerEvent($controller, 'testAction');
- $this->listener->onKernelController($controllerEvent);
-
- // Assert that _mainframe_noindex attribute is set to false
- $this->assertFalse($controllerEvent->getRequest()->attributes->get('_mainframe_noindex'));
-
- // Simulate ResponseEvent
- $response = new Response();
- $responseEvent = $this->createResponseEvent($controllerEvent->getRequest(), $response);
- $this->listener->onKernelResponse($responseEvent);
-
- // Assert that the X-Robots-Tag header is NOT present
- $this->assertFalse($response->headers->has('X-Robots-Tag'));
- }
-
- /**
- * Tests that no X-Robots-Tag: noindex header is added when index is true on the class.
- */
- public function testNoIndexHeaderNotAddedWhenClassIndexIsTrue(): void
- {
- // Dummy controller with Mainframe attribute on class (index: true), no attribute on method
- $controller = new #[Mainframe(index: true, sitemap: true)] class {
- public function testAction(): Response { return new Response(); }
- };
-
- // Simulate ControllerEvent
- $controllerEvent = $this->createControllerEvent($controller, 'testAction');
- $this->listener->onKernelController($controllerEvent);
-
- // Assert that _mainframe_noindex attribute is set to false
- $this->assertFalse($controllerEvent->getRequest()->attributes->get('_mainframe_noindex'));
-
- // Simulate ResponseEvent
- $response = new Response();
- $responseEvent = $this->createResponseEvent($controllerEvent->getRequest(), $response);
- $this->listener->onKernelResponse($responseEvent);
-
- // Assert that the X-Robots-Tag header is NOT present
- $this->assertFalse($response->headers->has('X-Robots-Tag'));
- }
-
- /**
- * Tests that no X-Robots-Tag: noindex header is added when no attribute is present.
- */
- public function testNoIndexHeaderNotAddedWhenNoAttributePresent(): void
- {
- // Dummy controller with no Mainframe attribute
- $controller = new class {
- public function testAction(): Response { return new Response(); }
- };
-
- // Simulate ControllerEvent
- $controllerEvent = $this->createControllerEvent($controller, 'testAction');
- $this->listener->onKernelController($controllerEvent);
-
- // Assert that _mainframe_noindex attribute is set to false (default)
- $this->assertFalse($controllerEvent->getRequest()->attributes->get('_mainframe_noindex'));
-
- // Simulate ResponseEvent
- $response = new Response();
- $responseEvent = $this->createResponseEvent($controllerEvent->getRequest(), $response);
- $this->listener->onKernelResponse($responseEvent);
-
- // Assert that the X-Robots-Tag header is NOT present
- $this->assertFalse($response->headers->has('X-Robots-Tag'));
- }
-
- /**
- * Tests that a closure controller is skipped.
- */
- public function testClosureControllerIsSkipped(): void
- {
- $kernel = $this->createMock(HttpKernelInterface::class);
- $request = new Request();
- $controller = function() { return new Response(); }; // A closure controller
-
- $controllerEvent = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MAIN_REQUEST);
-
- $this->listener->onKernelController($controllerEvent);
-
- // Ensure no _mainframe_noindex attribute is set
- $this->assertFalse($request->attributes->has('_mainframe_noindex'));
- }
-}
diff --git a/tests/EventListener/SitemapSubscriberTest.php b/tests/EventListener/SitemapSubscriberTest.php
deleted file mode 100644
index d58e9c7..0000000
--- a/tests/EventListener/SitemapSubscriberTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-urlGenerator = $this->createMock(UrlGeneratorInterface::class);
-
- // Mock the UrlContainerInterface
- $this->urlContainer = $this->createMock(UrlContainerInterface::class);
- }
-
- public function testGetSubscribedEvents(): void
- {
- // Assert that the getSubscribedEvents method returns the correct event.
- $expectedEvents = [
- SitemapPopulateEvent::class => 'populate',
- ];
-
- $this->assertEquals($expectedEvents, SitemapSubscriber::getSubscribedEvents());
- }
-
- public function testPopulate(): void
- {
- // Create an instance of the subscriber
- $subscriber = new SitemapSubscriber();
-
- // Create a mock for SitemapPopulateEvent
- $event = new SitemapPopulateEvent($this->urlContainer, $this->urlGenerator);
-
- // Call the populate method
- $subscriber->populate($event);
- $this->assertEquals("a","a");
- }
-}
diff --git a/tests/Repository/AccountRepositoryTest.php b/tests/Repository/AccountRepositoryTest.php
deleted file mode 100644
index 918bc33..0000000
--- a/tests/Repository/AccountRepositoryTest.php
+++ /dev/null
@@ -1,129 +0,0 @@
-entityManager = static::getContainer()->get('doctrine.orm.entity_manager');
-
- // Get the AccountRepository from the container
- $this->accountRepository = static::getContainer()->get(AccountRepository::class);
-
- // Begin a transaction to ensure a clean database state for each test.
- // All changes made during the test will be rolled back in tearDown.
- $this->entityManager->beginTransaction();
- }
-
- /**
- * Tests the upgradePassword method with a valid Account instance.
- *
- * This test verifies that the password of an Account object is correctly
- * updated and persisted when upgradePassword is called.
- */
- public function testUpgradePassword(): void
- {
- // Create a mock Account entity for testing
- $account = new Account();
- $account->setEmail('test@example.com');
- // Add a username as it seems to be a non-nullable field based on previous errors
- $account->setUsername('test_user');
- // Add a UUID in the correct format. For real applications, consider using a UUID library
- // like Ramsey\Uuid (e.g., Uuid::uuid4()->toString()). For testing, a valid string literal is fine.
- $account->setUuid('123e4567-e89b-12d3-a456-426614174000'); // Example of a valid UUID format
- $account->setPassword('old_hashed_password'); // Set an initial password
-
- $newHashedPassword = 'new_hashed_password';
-
- // Call the upgradePassword method
- $this->accountRepository->upgradePassword($account, $newHashedPassword);
-
- // Assert that the account's password has been updated
- $this->assertEquals($newHashedPassword, $account->getPassword(), 'The account password should be updated.');
-
- // In a real test, you might want to mock the EntityManager's persist and flush calls
- // to avoid actual database interaction if you're unit testing the repository in isolation.
- // For an integration test with a real database, you'd check if the change is reflected
- // by fetching the entity again.
-
- // Example of how you might assert that persist and flush were called if mocking:
- // $mockEntityManager = $this->createMock(EntityManagerInterface::class);
- // $mockEntityManager->expects($this->once())->method('persist')->with($account);
- // $mockEntityManager->expects($this->once())->method('flush');
- // // Then inject this mock into your repository if it were a pure unit test.
- }
-
- /**
- * Tests the upgradePassword method with an unsupported user type.
- *
- * This test verifies that an UnsupportedUserException is thrown when
- * upgradePassword is called with a user object that is not an instance of Account.
- */
- public function testUpgradePasswordWithUnsupportedUser(): void
- {
- // Expect an UnsupportedUserException to be thrown
- $this->expectException(UnsupportedUserException::class);
- // The message will contain the class name of the mock object, which implements the interface
-
- // Create a mock object that implements PasswordAuthenticatedUserInterface
- // but is NOT an instance of Account. This is crucial to trigger the UnsupportedUserException
- // from the repository's internal check, rather than a TypeError from the method signature.
- $unsupportedUserMock = $this->createMock(PasswordAuthenticatedUserInterface::class);
-
- // Pass this mock object to the upgradePassword method.
- $this->accountRepository->upgradePassword($unsupportedUserMock, 'some_password');
- }
-
- /**
- * Cleans up the test environment after each test method.
- *
- * This method rolls back the database transaction started in setUp,
- * effectively undoing any changes made during the test, and then closes
- * the EntityManager to release database resources.
- */
- protected function tearDown(): void
- {
- parent::tearDown();
-
- // Check if a transaction is active before attempting to roll back
- if ($this->entityManager && $this->entityManager->getConnection()->isTransactionActive()) {
- $this->entityManager->rollback();
- }
-
- // Close the EntityManager to prevent memory leaks
- if ($this->entityManager) {
- $this->entityManager->close();
- $this->entityManager = null; // Avoid memory leaks
- }
- $this->accountRepository = null;
- }
-}
diff --git a/tests/Repository/AccountResetPasswordRequestRepositoryTest.php b/tests/Repository/AccountResetPasswordRequestRepositoryTest.php
deleted file mode 100644
index b600903..0000000
--- a/tests/Repository/AccountResetPasswordRequestRepositoryTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-entityManager = self::getContainer()->get('doctrine')->getManager();
- $this->accountResetPasswordRequestRepository = $this->entityManager->getRepository(AccountResetPasswordRequest::class);
- }
-
- public function testRepositoryExistsAndIsCorrectInstance(): void
- {
- $this->assertInstanceOf(AccountResetPasswordRequestRepository::class, $this->accountResetPasswordRequestRepository);
- }
-
- protected function tearDown(): void
- {
- parent::tearDown();
-
- $this->entityManager->close();
- $this->entityManager = null; // Avoid memory leaks
- $this->accountResetPasswordRequestRepository = null;
- }
-}
-
diff --git a/tests/Repository/MailRepositoryTest.php b/tests/Repository/MailRepositoryTest.php
deleted file mode 100644
index 818f32c..0000000
--- a/tests/Repository/MailRepositoryTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-entityManager = self::getContainer()->get('doctrine')->getManager();
- $this->mailRepository = $this->entityManager->getRepository(Mail::class);
- }
-
- public function testRepositoryExistsAndIsCorrectInstance(): void
- {
- $this->assertInstanceOf(MailRepository::class, $this->mailRepository);
- }
-
- protected function tearDown(): void
- {
- parent::tearDown();
-
- $this->entityManager->close();
- $this->entityManager = null; // Avoid memory leaks
- $this->mailRepository = null;
- }
-}
-