feat/login #10

Open
maurine wants to merge 13 commits from feat/login into main
19 changed files with 227 additions and 128 deletions
Showing only changes of commit d46b61a0ad - Show all commits

View File

@@ -1,4 +1,3 @@
# Plateforme web pour les adhérents KAZ # Plateforme web pour les adhérents KAZ
## Objectif ## Objectif
@@ -11,6 +10,7 @@ Cette application web permet aux adhérents de l'association KAZ de gérer leur
## Architecture technique ## Architecture technique
- **Frontend** : [Twig](https://twig.symfony.com/) + [Tailwind CSS](https://tailwindcss.com/) - **Frontend** : [Twig](https://twig.symfony.com/) + [Tailwind CSS](https://tailwindcss.com/)
- **Documentation installation Tailwind** : [Plus d'infos ici](https://tailwindcss.com/docs/installation/framework-guides/symfony)
- **Backend** : PHP 8.4 / [Symfony](https://symfony.com/) - **Backend** : PHP 8.4 / [Symfony](https://symfony.com/)
- **Base de données** : [PostgreSQL](https://www.postgresql.org/) - **Base de données** : [PostgreSQL](https://www.postgresql.org/)
- **Intégration** : Communication via API avec les outils de KAZ (notamment OpenLDAP). - **Intégration** : Communication via API avec les outils de KAZ (notamment OpenLDAP).

0
[all
View File

View File

@@ -1,18 +0,0 @@
services:
###> doctrine/doctrine-bundle ###
database:
ports:
- "5432"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
mailer:
image: axllent/mailpit
ports:
- "1025"
- "8025"
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
###< symfony/mailer ###

View File

@@ -25,29 +25,5 @@ services:
environment: environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1 MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1 MP_SMTP_AUTH_ALLOW_INSECURE: 1
###> doctrine/doctrine-bundle ###
database:
image: postgres:${POSTGRES_VERSION:-16}-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-app}
# You should definitely change the password in production
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
POSTGRES_USER: ${POSTGRES_USER:-app}
healthcheck:
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"]
timeout: 5s
retries: 5
start_period: 60s
volumes:
- database_data:/var/lib/postgresql/data:rw
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
# - ./docker/db/data:/var/lib/postgresql/data:rw
###< doctrine/doctrine-bundle ###
volumes: volumes:
database_data: database_data:
###> doctrine/doctrine-bundle ###
database_data:
###< doctrine/doctrine-bundle ###

View File

@@ -20,7 +20,7 @@ final class Version20260313151403 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs // this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE "user" (id UUID NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, email_quota VARCHAR(255) NOT NULL, email_de_secours VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, lastname VARCHAR(255) NOT NULL, firstname VARCHAR(255) NOT NULL, PRIMARY KEY (id))'); $this->addSql('CREATE TABLE "user" (id UUID NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, email_quota VARCHAR(255) NOT NULL, alternate_email VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, lastname VARCHAR(255) NOT NULL, firstname VARCHAR(255) NOT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)'); $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
$this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))'); $this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)'); $this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)');

View File

@@ -20,12 +20,12 @@ final class Version20260316103235 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs // this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE "user" ALTER email_de_secours DROP NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER alternate_email DROP NOT NULL');
} }
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs // this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE "user" ALTER email_de_secours SET NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER alternate_email SET NOT NULL');
} }
} }

View File

@@ -24,7 +24,7 @@ final class Version20260316114715 extends AbstractMigration
$this->addSql('ALTER TABLE "user" ADD first_name VARCHAR(255) NOT NULL'); $this->addSql('ALTER TABLE "user" ADD first_name VARCHAR(255) NOT NULL');
$this->addSql('ALTER TABLE "user" DROP lastname'); $this->addSql('ALTER TABLE "user" DROP lastname');
$this->addSql('ALTER TABLE "user" DROP firstname'); $this->addSql('ALTER TABLE "user" DROP firstname');
$this->addSql('ALTER TABLE "user" ALTER email_de_secours SET NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER alternate_email SET NOT NULL');
$this->addSql('ALTER TABLE "user" ALTER identifiant_kaz SET NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER identifiant_kaz SET NOT NULL');
$this->addSql('ALTER TABLE "user" ALTER quota SET NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER quota SET NOT NULL');
$this->addSql('ALTER TABLE "user" ALTER has_nextcloud_access SET NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER has_nextcloud_access SET NOT NULL');
@@ -39,7 +39,7 @@ final class Version20260316114715 extends AbstractMigration
$this->addSql('ALTER TABLE "user" ADD firstname VARCHAR(255) NOT NULL'); $this->addSql('ALTER TABLE "user" ADD firstname VARCHAR(255) NOT NULL');
$this->addSql('ALTER TABLE "user" DROP last_name'); $this->addSql('ALTER TABLE "user" DROP last_name');
$this->addSql('ALTER TABLE "user" DROP first_name'); $this->addSql('ALTER TABLE "user" DROP first_name');
$this->addSql('ALTER TABLE "user" ALTER email_de_secours DROP NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER alternate_email DROP NOT NULL');
$this->addSql('ALTER TABLE "user" ALTER identifiant_kaz DROP NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER identifiant_kaz DROP NOT NULL');
$this->addSql('ALTER TABLE "user" ALTER quota DROP NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER quota DROP NOT NULL');
$this->addSql('ALTER TABLE "user" ALTER has_nextcloud_access DROP NOT NULL'); $this->addSql('ALTER TABLE "user" ALTER has_nextcloud_access DROP NOT NULL');

View File

@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
/** /**
* Auto-generated Migration: Please modify to your needs! * Auto-generated Migration: Please modify to your needs!
*/ */
final class Version20260313104837 extends AbstractMigration final class Version20260328101039 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
{ {
@@ -20,7 +20,8 @@ final class Version20260313104837 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs // this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE "user" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, role VARCHAR(255) NOT NULL, mail VARCHAR(255) NOT NULL, mail_quota VARCHAR(255) NOT NULL, mail_de_secours VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, PRIMARY KEY (id))'); $this->addSql('CREATE TABLE "user" (id UUID NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, email_quota VARCHAR(255) NOT NULL, alternate_email VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, last_name VARCHAR(255) NOT NULL, first_name VARCHAR(255) NOT NULL, photo VARCHAR(255) DEFAULT NULL, telephone VARCHAR(20) DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
$this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))'); $this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)'); $this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)');
} }

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260328101220 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE "user" (id UUID NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, email_quota VARCHAR(255) NOT NULL, alternate_email VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, last_name VARCHAR(255) NOT NULL, first_name VARCHAR(255) NOT NULL, photo VARCHAR(255) DEFAULT NULL, telephone VARCHAR(20) DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
$this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE "user"');
$this->addSql('DROP TABLE messenger_messages');
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260329084928 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE "user" (id UUID NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, email_quota VARCHAR(255) NOT NULL, alternate_email VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, last_name VARCHAR(255) NOT NULL, first_name VARCHAR(255) NOT NULL, photo VARCHAR(255) DEFAULT NULL, telephone VARCHAR(20) DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
$this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE "user"');
$this->addSql('DROP TABLE messenger_messages');
}
}

View File

@@ -27,7 +27,7 @@ class UserController extends AbstractController
* Permet de vérifier si un utilisateur existe dans le ldap. * Permet de vérifier si un utilisateur existe dans le ldap.
* *
* @param string $email L'adresse e-mail de l'utilisateur. * @param string $email L'adresse e-mail de l'utilisateur.
* @param KazApiService $apiClient Le service utilisé pour récupérer les données utilisateur. * @param KazApiService $apiKazService Le service utilisé pour récupérer les données utilisateur.
* *
* @return Response La page index utilisateur rendue. * @return Response La page index utilisateur rendue.
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
@@ -37,29 +37,32 @@ class UserController extends AbstractController
* @throws TransportExceptionInterface * @throws TransportExceptionInterface
*/ */
# #[Route('/user/{email}', name: 'app_user', methods: ['GET'])] #[Route('/user/{email}', name: 'app_user_by_mail', methods: ['GET'])]
# public function index(string $email, KazApiService $apiClient): Response public function index(string $email, KazApiService $apiKazService): Response
# { {
# $exist = $apiClient->getUserData($email); $user = $apiKazService->getUserData($email);
# return $this->render('user/profil_infos.html.twig', [
# return $this->render('user/index.html.twig', [ 'user' => $user,
# 'exist' => $exist, ]);
# ]); }
# }
/* TODO : Param l'API avec un Serializer pour la lecture du fichier JSON ? */ /* TODO : Param l'API avec un Serializer pour la lecture du fichier JSON ? */
#[Route('/mon-profil', name: 'app_user', methods: ['GET', 'POST'])] #[Route('/mon-profil', name: 'app_user', methods: ['GET', 'POST'])]
#[IsGranted('ROLE_USER')] #[IsGranted('ROLE_USER')]
public function showProfile( public function showProfile(
Request $request, Request $request,
EntityManagerInterface $entityManager, EntityManagerInterface $entityManager,
FileUploader $fileUploader FileUploader $fileUploader,
KazApiService $apiKazService
): Response { ): Response {
# Récupération de l'utilisateur actuellement connecté # Récupération de l'utilisateur actuellement connecté
$user = $this->getUser(); $user = $this->getUser();
/* Utilisation des fixtures pour vérifier la mise en page. $kazUser = $apiKazService->getUserData($user->getEmail());
TODO: modifier pour que ça communique avec l'API */
$user = $user->updateFromKazUser($kazUser);
//TODO: modifier pour que ça communique avec l'API */
# Création du formulaire lié à l'utilisateur connecté # Création du formulaire lié à l'utilisateur connecté
$form = $this->createForm(UserProfileType::class, $user); $form = $this->createForm(UserProfileType::class, $user);
@@ -82,6 +85,22 @@ class UserController extends AbstractController
$user->setPhoto($newFilename); $user->setPhoto($newFilename);
} }
$alternateEmail = $form->get('alternateEmail')->getData();
$regexEmail = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
if(isset($alternateEmail) && preg_match($regexEmail, $alternateEmail)) {
$user->setAlternateEmail($form->get('alternateEmail')->getData());
} else {
$alternateEmail->addError(new FormError('L\'adresse e-mail n\'est pas valide.'));
}
$telephone = $form->get('telephone')->getData();
$regexTelephone = '/^[0-9\+\s\.\-\(\)]+$/';
if(isset($telephone) && preg_match($regexTelephone, $telephone)) {
$user->setTelephone($telephone);
} else {
$telephone->addError(new FormError('Le numéro de téléphone n\'est pas valide.'));
}
# Sauvegarde en base de données # Sauvegarde en base de données
$entityManager->flush(); $entityManager->flush();
@@ -105,9 +124,6 @@ class UserController extends AbstractController
EntityManagerInterface $entityManager EntityManagerInterface $entityManager
): Response ): Response
{ {
# Récupération de l'utilisateur actuellement connecté
$user = $this->getUser();
# Création du formulaire # Création du formulaire
$form = $this->createForm(ChangePasswordType::class); $form = $this->createForm(ChangePasswordType::class);

View File

@@ -42,37 +42,55 @@ class AppFixtures extends Fixture
$user->setNextcloudQuota($faker->numberBetween(1, 20) . 'G'); $user->setNextcloudQuota($faker->numberBetween(1, 20) . 'G');
$user->setQuota($faker->numberBetween(1, 10) . 'G'); $user->setQuota($faker->numberBetween(1, 10) . 'G');
$user->setEmailQuota('1G'); $user->setEmailQuota('1G');
$user->setEmailDeSecours($faker->unique()->safeEmail()); $user->setAlternateEmail($faker->unique()->safeEmail());
$user->setHasAgoraAccess($faker->boolean(70)); // 70% de chance d'avoir accès $user->setHasAgoraAccess($faker->boolean(70)); // 70% de chance d'avoir accès
$user->setHasMobilizon($faker->boolean(50)); $user->setHasMobilizon($faker->boolean(50));
$user->setHasNextcloudAccess($faker->boolean(90)); $user->setHasNextcloudAccess($faker->boolean(90));
$user->setIdentifiantKaz($faker->uuid()); $user->setIdentifiantKaz($faker->uuid());
}
// Création d'un compte de test fixe
$admin = new User();
$admin->setEmail('admin@kaz.bzh');
$admin->setRoles(['ROLE_USER', 'ROLE_ADMIN', 'ROLE_ORGANISATION']);
$admin->setPassword($this->hasher->hashPassword($admin, 'password'));
$admin->setFirstName('Admin');
$admin->setLastName('KAZ');
// Remplissage des champs obligatoires restants pour éviter les erreurs SQL
$admin->setEmailDeSecours('secours@kaz.bzh');
$admin->setIdentifiantKaz('ADMIN-KAZ-001');
$admin->setQuota('5G');
$admin->setEmailQuota('1G');
$admin->setNextcloudQuota('10G');
$admin->setHasNextcloudAccess(true);
$admin->setHasMobilizon(true);
$admin->setHasAgoraAccess(true);
$manager->persist($admin);
# Préparation de l'enregistrement de l'objet en base de données # Préparation de l'enregistrement de l'objet en base de données
$manager->persist($user); $manager->persist($user);
# Exécution réelle des requêtes SQL (envoi vers la base), une fois la bouche finie
$manager->flush();
} }
// Création d'un compte de test fixe
$admin = new User();
$admin->setEmail('admin@kaz.bzh');
$admin->setRoles(['ROLE_USER', 'ROLE_ADMIN', 'ROLE_ORGANISATION']);
$admin->setPassword($this->hasher->hashPassword($admin, 'password'));
$admin->setFirstName('Admin');
$admin->setLastName('KAZ');
// Remplissage des champs obligatoires restants pour éviter les erreurs SQL
$admin->setAlternateEmail('secours@kaz.bzh');
$admin->setIdentifiantKaz('ADMIN-KAZ-001');
$admin->setQuota('5G');
$admin->setEmailQuota('1G');
$admin->setNextcloudQuota('10G');
$admin->setHasNextcloudAccess(true);
$admin->setHasMobilizon(true);
$admin->setHasAgoraAccess(true);
$manager->persist($admin);
// Création d'un compte de test fixe
$melvin = new User();
$melvin->setEmail('melvin.leveque@kazkouil.fr');
$melvin->setRoles(['ROLE_USER', 'ROLE_ADMIN', 'ROLE_ORGANISATION']);
$melvin->setPassword($this->hasher->hashPassword($melvin, 'password'));
$melvin->setFirstName('');
$melvin->setLastName('');
$melvin->setAlternateEmail('');
$melvin->setIdentifiantKaz('MELVIN-KAZ-001');
$melvin->setQuota('5G');
$melvin->setEmailQuota('1G');
$melvin->setNextcloudQuota('10G');
$melvin->setHasNextcloudAccess(true);
$melvin->setHasMobilizon(true);
$melvin->setHasAgoraAccess(true);
$manager->persist($melvin);
# Exécution réelle des requêtes SQL (envoi vers la base), une fois la bouche finie
$manager->flush();
}
} }

View File

@@ -12,14 +12,16 @@ use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')] #[ORM\Table(name: '`user`')]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')] #[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface class User implements UserInterface, PasswordAuthenticatedUserInterface
{ {
public const string EMAIL_QUOTA_DEFAULT = '1G';
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')] #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\Column(type: 'uuid', unique: true)] #[ORM\Column(type: 'uuid', unique: true, name: 'id')]
private ?Uuid $id; private ?Uuid $id;
#[ORM\Column(length: 180, unique: true)] #[ORM\Column(length: 180, unique: true)]
@@ -28,51 +30,56 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
/** /**
* @var list<string> The user roles * @var list<string> The user roles
*/ */
#[ORM\Column] #[ORM\Column(name: 'roles')]
private array $roles = []; private array $roles = [];
/** /**
* @var ?string The hashed password * @var ?string The hashed password
*/ */
#[ORM\Column] #[ORM\Column(name: 'password')]
private ?string $password = null; private ?string $password = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'email_quota')]
private ?string $emailQuota = '1G'; private ?string $emailQuota = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'alternate_email')]
private ?string $emailDeSecours = null; private ?string $alternateEmail = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'identifiant_kaz')]
private ?string $identifiantKaz = null; private ?string $identifiantKaz = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'quota')]
private ?string $quota = null; private ?string $quota = null;
#[ORM\Column] #[ORM\Column(name: 'has_nextcloud_access')]
private ?bool $hasNextcloudAccess = null; private ?bool $hasNextcloudAccess = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'nextcloud_quota')]
private ?string $nextcloudQuota = null; private ?string $nextcloudQuota = null;
#[ORM\Column] #[ORM\Column(name: 'has_mobilizon')]
private ?bool $hasMobilizon = null; private ?bool $hasMobilizon = null;
#[ORM\Column] #[ORM\Column(name: 'has_agora_access')]
private ?bool $hasAgoraAccess = null; private ?bool $hasAgoraAccess = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'last_name')]
private ?string $lastName = null; private ?string $lastName = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, name: 'first_name')]
private ?string $firstName = null; private ?string $firstName = null;
#[ORM\Column(length: 255, nullable: true)] // TODO: Modifier "photo" par "image"
#[ORM\Column(length: 255, nullable: true, name: 'photo')]
private ?string $photo = null; private ?string $photo = null;
#[ORM\Column(length: 20, nullable: true)] #[ORM\Column(length: 20, nullable: true, name: 'telephone')]
private ?string $telephone = null; private ?string $telephone = null;
public function __construct() {
$this->emailQuota = self::EMAIL_QUOTA_DEFAULT;
}
public function getId(): ?Uuid public function getId(): ?Uuid
{ {
return $this->id; return $this->id;
@@ -175,14 +182,14 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
public function getEmailDeSecours(): ?string public function getAlternateEmail(): ?string
{ {
return $this->emailDeSecours; return $this->alternateEmail;
} }
public function setEmailDeSecours(string $emailDeSecours): static public function setAlternateEmail(string $alternateEmail): static
{ {
$this->emailDeSecours = $emailDeSecours; $this->alternateEmail = $alternateEmail;
return $this; return $this;
} }
@@ -306,4 +313,19 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
public function updateFromKazUser($kazUser) : User
{
$this->setEmail($kazUser['mail']);
// Création du firstname et lastname
$name = explode(' ', $kazUser['sn']);
$this->setFirstName($name[0]);
// Récupération des valeurs du tableau moins la première
$aLastname = array_slice($name, 1);
$this->setLastName(implode(' ', $aLastname));
//TODO: Ajouter les champs manquants de l'objet User dans l'api kaz.
return $this;
}
} }

View File

@@ -31,7 +31,7 @@ class UserProfileType extends AbstractType
'label' => 'E-mail', 'label' => 'E-mail',
'disabled' => true, 'disabled' => true,
]) ])
->add('emailDeSecours', EmailType::class, ['label' => 'E-mail de secours']) ->add('alternateEmail', EmailType::class, ['label' => 'E-mail de secours'])
->add('telephone', TelType::class, [ ->add('telephone', TelType::class, [
'label'=>'Téléphone', 'label'=>'Téléphone',
'required' => false, 'required' => false,

View File

@@ -34,7 +34,7 @@ class FileUploader
public function delete(?string $fileName): void public function delete(?string $fileName): void
{ {
if ($fileName) { if ($fileName) {
$filePath = $this->getTargetDirectory() . '/' . $fileName; $filePath = $this->getTargetDirectory() . 'FileUploader.php/' . $fileName;
if (file_exists($filePath)) { if (file_exists($filePath)) {
unlink($filePath); unlink($filePath);
} }

View File

@@ -14,12 +14,18 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
class KazApiService class KazApiService
{ {
private ?string $token = null; private ?string $token = null;
private HttpClientInterface $httpClient;
public function __construct( public function __construct(
private readonly HttpClientInterface $kazApiClient, private readonly HttpClientInterface $kazApiClient,
private readonly string $apiUser, private readonly string $apiUser,
private readonly string $apiPassword private readonly string $apiPassword
) {} ) {
$this->httpClient = $kazApiClient->withOptions([
'auth_basic' => [$apiUser, $apiPassword]
]);
}
/** /**
* Récupère le token JWT via l'authentification Basic * Récupère le token JWT via l'authentification Basic
@@ -37,16 +43,14 @@ class KazApiService
return $this->token; return $this->token;
} }
$response = $this->kazApiClient->request('POST', '/get_token', [ $response = $this->httpClient->request('GET', '/get_token');
'auth_basic' => [$this->apiUser, $this->apiPassword]
]);
if ($response->getStatusCode() !== 200) { if ($response->getStatusCode() !== 200) {
throw new Exception('Impossible de récupérer le token JWT'); throw new Exception('Impossible de récupérer le token JWT'.$response->getStatusCode());
} }
$data = $response->toArray(); $data = $response->toArray();
$this->token = $data['token']; // Ajustez la clé selon le format de votre API $this->token = $data['access_token']; // Ajustez la clé selon le format de votre API
return $this->token; return $this->token;
} }
@@ -68,7 +72,6 @@ class KazApiService
public function getUserData(string $email): array public function getUserData(string $email): array
{ {
$options['headers']['Authorization'] = 'Bearer ' . $this->getToken(); $options['headers']['Authorization'] = 'Bearer ' . $this->getToken();
$response = $this->kazApiClient->request('GET', "/ldap/user/$email", $options); $response = $this->kazApiClient->request('GET', "/ldap/user/$email", $options);
if ($response->getStatusCode() !== 200) { if ($response->getStatusCode() !== 200) {

View File

@@ -110,15 +110,15 @@
{# Champ E-mail de secours #} {# Champ E-mail de secours #}
<div class="space-y-1"> <div class="space-y-1">
{{ form_label(form.emailDeSecours, 'E-mail de secours :', { {{ form_label(form.alternateEmail, 'E-mail de secours :', {
'label_attr': {'class': 'block text-sm font-semibold text-text'} 'label_attr': {'class': 'block text-sm font-semibold text-text'}
}) }} }) }}
{{ form_widget(form.emailDeSecours, { {{ form_widget(form.alternateEmail, {
'attr': {'class': 'w-full px-4 py-3 border border-gris-clair rounded-lg focus:outline-none focus:border-bouton focus:ring-1 focus:ring-bouton placeholder-gris-moyen transition-shadow'} 'attr': {'class': 'w-full px-4 py-3 border border-gris-clair rounded-lg focus:outline-none focus:border-bouton focus:ring-1 focus:ring-bouton placeholder-gris-moyen transition-shadow'}
}) }} }) }}
{# Implémentation d'un message d'errer en cas de problème #} {# Implémentation d'un message d'errer en cas de problème #}
<div class="text-red-500 text-xs mt-1 italic font-sora"> <div class="text-red-500 text-xs mt-1 italic font-sora">
{{ form_errors(form.emailDeSecours) }} {{ form_errors(form.alternateEmail) }}
</div> </div>
</div> </div>

View File

@@ -0,0 +1,11 @@
{% extends 'base.html.twig' %}
{% block title %}Accueil | {{ parent() }}{% endblock %}
{% block body %}
<div class="min-h-screen bg-bg-primaire py-8 w-full font-sora">
<div>
<span>Identifiant : {{ user.identifiantKaz }}</span>
</div>
</div>
{% endblock %}

0
true],
View File