diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 73918af..1fa549b 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -8,7 +8,7 @@ security: app_account_provider: entity: class: App\Entity\Account - property: username # Utilise le champ 'username' de votre entité Account pour l'authentification + property: email # Utilise le champ 'username' de votre entité Account pour l'authentification firewalls: dev: diff --git a/config/packages/vich_uploader.yaml b/config/packages/vich_uploader.yaml index 675bce6..868b8bf 100644 --- a/config/packages/vich_uploader.yaml +++ b/config/packages/vich_uploader.yaml @@ -9,6 +9,14 @@ vich_uploader: inject_on_load: true delete_on_update: true delete_on_remove: true + members: + uri_prefix: /storage/members + upload_destination: '%kernel.project_dir%/public/storage/members' + namer: App\VichUploader\Namer\Account\AvatarName # Replaced namer + directory_namer: App\VichUploader\DirectoryNamer\Account\AvatarName + inject_on_load: true + delete_on_update: true + delete_on_remove: true #mappings: # products: # uri_prefix: /images/products diff --git a/migrations/Version20251117134224.php b/migrations/Version20251117134224.php new file mode 100644 index 0000000..522bbb3 --- /dev/null +++ b/migrations/Version20251117134224.php @@ -0,0 +1,32 @@ +addSql('CREATE TABLE members (id SERIAL NOT NULL, pseudo VARCHAR(255) NOT NULL, role VARCHAR(255) NOT NULL, cosplayer BOOLEAN NOT NULL, crosscosplayer BOOLEAN NOT NULL, trans BOOLEAN NOT NULL, orientation VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); + } + + 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('DROP TABLE members'); + } +} diff --git a/migrations/Version20251117135736.php b/migrations/Version20251117135736.php new file mode 100644 index 0000000..71732a4 --- /dev/null +++ b/migrations/Version20251117135736.php @@ -0,0 +1,43 @@ +addSql('ALTER TABLE members ADD member_file_name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE members ADD member_dimensions JSON DEFAULT NULL'); + $this->addSql('ALTER TABLE members ADD member_size VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE members ADD member_mine_type VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE members ADD member_original_name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE members ADD update_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); + $this->addSql('COMMENT ON COLUMN members.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 members DROP member_file_name'); + $this->addSql('ALTER TABLE members DROP member_dimensions'); + $this->addSql('ALTER TABLE members DROP member_size'); + $this->addSql('ALTER TABLE members DROP member_mine_type'); + $this->addSql('ALTER TABLE members DROP member_original_name'); + $this->addSql('ALTER TABLE members DROP update_at'); + } +} diff --git a/src/Controller/Admin/AdminController.php b/src/Controller/Admin/AdminController.php new file mode 100644 index 0000000..f27d2b8 --- /dev/null +++ b/src/Controller/Admin/AdminController.php @@ -0,0 +1,94 @@ + false], methods: ['GET'])] + public function adminDashboard(): Response + { + return $this->render('admin/dashboard.twig', [ + ]); + } + + #[Route(path: '/admin/members', name: 'admin_members', options: ['sitemap' => false], methods: ['GET'])] + public function adminMembers(MembersRepository $membersRepository): Response + { + + return $this->render('admin/members.twig', [ + 'members' => $membersRepository->findBy([],['id' => 'ASC']), + ]); + } + #[Route(path: '/admin/members/{id}', name: 'admin_member_edit', options: ['sitemap' => false], methods: ['GET','POST'])] + public function adminMembersEdit(?Members $members,Request $request,EntityManagerInterface $entityManager): Response + { + $form = $this->createForm(MembersType::class, $members); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->persist($members); + $entityManager->flush(); + return $this->redirectToRoute('admin_members'); + } + return $this->render('admin/member/add.twig', [ + 'form' => $form->createView(), + ]); + } + #[Route(path: '/admin/members/add', name: 'admin_member_create', options: ['sitemap' => false], methods: ['GET','POST'], priority: 5)] + public function adminMembersCreate(Request $request,EntityManagerInterface $entityManager): Response + { + $members = new Members(); + $members->setTrans(false); + $members->setCrosscosplayer(false); + $members->setCosplayer(false); + $form = $this->createForm(MembersType::class, $members); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->persist($members); + $entityManager->flush(); + return $this->redirectToRoute('admin_members'); + } + return $this->render('admin/member/add.twig', [ + 'form' => $form->createView(), + ]); + } + #[Route(path: '/admin/members/delete/{id}', name: 'admin_member_delete', options: ['sitemap' => false], methods: ['GET'])] + public function adminMembersDelete(): Response + { + + } + + #[Route(path: '/admin/events', name: 'admin_events', options: ['sitemap' => false], methods: ['GET'])] + public function adminEvents(): Response + { + return $this->render('admin/dashboard.twig', [ + ]); + } + + #[Route(path: '/admin/account', name: 'admin_accounts_list', options: ['sitemap' => false], methods: ['GET'])] + public function adminAccount(): Response + { + return $this->render('admin/dashboard.twig', [ + ]); + } +} diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index d49956c..1a1d296 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -26,6 +26,8 @@ class SecurityController extends AbstractController #[Route(path: '/connexion', name: 'app_login', options: ['sitemap' => false], methods: ['GET','POST'])] public function login(AuthenticationUtils $authenticationUtils): Response { + if($this->getUser()) + return $this->redirectToRoute('app_home'); return $this->render('security/login.twig', [ 'last_username' => $authenticationUtils->getLastUsername(), 'error' => $authenticationUtils->getLastAuthenticationError(), diff --git a/src/Entity/Members.php b/src/Entity/Members.php new file mode 100644 index 0000000..7c8723d --- /dev/null +++ b/src/Entity/Members.php @@ -0,0 +1,257 @@ +id; + } + + public function getPseudo(): ?string + { + return $this->pseudo; + } + + public function setPseudo(string $pseudo): static + { + $this->pseudo = $pseudo; + + return $this; + } + + public function getRole(): ?string + { + return $this->role; + } + + public function setRole(string $role): static + { + $this->role = $role; + + return $this; + } + + public function isCosplayer(): ?bool + { + return $this->cosplayer; + } + + public function setCosplayer(bool $cosplayer): static + { + $this->cosplayer = $cosplayer; + + return $this; + } + + public function isCrosscosplayer(): ?bool + { + return $this->crosscosplayer; + } + + public function setCrosscosplayer(bool $crosscosplayer): static + { + $this->crosscosplayer = $crosscosplayer; + + return $this; + } + + public function isTrans(): ?bool + { + return $this->trans; + } + + public function setTrans(bool $trans): static + { + $this->trans = $trans; + + return $this; + } + + public function getOrientation(): ?string + { + return $this->orientation; + } + + public function setOrientation(string $orientation): static + { + $this->orientation = $orientation; + + return $this; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getUpdateAt(): ?\DateTimeImmutable + { + return $this->updateAt; + } + + /** + * @return bool|null + */ + public function getCosplayer(): ?bool + { + return $this->cosplayer; + } + + /** + * @return bool|null + */ + public function getCrosscosplayer(): ?bool + { + return $this->crosscosplayer; + } + + /** + * @return array|null + */ + public function getMemberDimensions(): ?array + { + return $this->memberDimensions; + } + + /** + * @return string|null + */ + public function getMemberFileName(): ?string + { + return $this->memberFileName; + } + + /** + * @return string|null + */ + public function getMemberMineType(): ?string + { + return $this->memberMineType; + } + + /** + * @return string|null + */ + public function getMemberOriginalName(): ?string + { + return $this->memberOriginalName; + } + + /** + * @return File|null + */ + public function getMembers(): ?File + { + return $this->members; + } + + /** + * @return string|null + */ + public function getMemberSize(): ?string + { + return $this->memberSize; + } + + /** + * @param \DateTimeImmutable|null $updateAt + */ + public function setUpdateAt(?\DateTimeImmutable $updateAt): void + { + $this->updateAt = $updateAt; + } + + /** + * @param array|null $memberDimensions + */ + public function setMemberDimensions(?array $memberDimensions): void + { + $this->memberDimensions = $memberDimensions; + } + + /** + * @param File|null $members + */ + public function setMembers(?File $members): void + { + $this->members = $members; + } + + /** + * @param string|null $memberFileName + */ + public function setMemberFileName(?string $memberFileName): void + { + $this->memberFileName = $memberFileName; + } + + /** + * @param string|null $memberMineType + */ + public function setMemberMineType(?string $memberMineType): void + { + $this->memberMineType = $memberMineType; + } + + /** + * @param string|null $memberOriginalName + */ + public function setMemberOriginalName(?string $memberOriginalName): void + { + $this->memberOriginalName = $memberOriginalName; + } + + /** + * @param string|null $memberSize + */ + public function setMemberSize(?string $memberSize): void + { + $this->memberSize = $memberSize; + } +} diff --git a/src/Form/MembersType.php b/src/Form/MembersType.php new file mode 100644 index 0000000..439f3f0 --- /dev/null +++ b/src/Form/MembersType.php @@ -0,0 +1,94 @@ +add('members', FileType::class, [ + 'label' => 'Photo du membre (Max 2Mo)', + 'required' => false, // Rendre facultatif + 'mapped' => false, // Indiquer que ce champ n'est pas directement mappé à une propriété de l'entité + 'attr' => [ + 'placeholder' => 'Choisir un fichier...', + ] + ]) + ->add('pseudo', TextType::class, [ + 'label' => 'Pseudo du membre', + 'required' => true, + ]) + ->add('role', ChoiceType::class, [ + 'label' => 'Rôle au sein de l\'association', + 'choices' => [ + 'Président(e)' => 'Président(e)', + 'Trésorier(e)' => 'Trésorier(e)', + 'Secrétaire(e)' => 'Secrétaire(e)', + 'Vice-Président(e)' => 'Vice-Président(e)', + 'Trésorier(e) Adjoints' => 'Trésorier(e) Adjoints', + 'Secrétaire(e) Adjoints' => 'Secrétaire(e) Adjoints', + ], + ]) + ->add('orientation', ChoiceType::class, [ + 'label' => 'Orientation (Tag)', + 'choices' => [ + 'Non spécifié' => 'not_specified', + 'Asexuel(le)' => 'asexual', + 'Bisexuel(le)' => 'bisexual', + 'Demisexuel(le)' => 'demisexual', + 'Gay' => 'gay', + 'Hétérosexuel(le)' => 'heterosexual', + 'Lesbienne' => 'lesbian', + 'Pansexuel(le)' => 'pansexual', + 'Queer' => 'queer', + 'En questionnement' => 'questioning', + 'Autre' => 'other', + ], + // Optionnel : affichez-le comme une liste déroulante normale (pas expanded) + ]) + + // Les champs booléens sont mieux affichés comme des boutons radio (expanded) + ->add('crosscosplayer', ChoiceType::class, [ + 'label' => 'Crosscosplayer ?', + 'choices' => [ + 'Non' => false, + 'Oui' => true, + ], + 'expanded' => true, // Affiche comme boutons radio + 'multiple' => false, + ]) + ->add('trans', ChoiceType::class, [ + 'label' => 'Transgenre ?', + 'choices' => [ + 'Non' => false, + 'Oui' => true, + ], + 'expanded' => true, + 'multiple' => false, + ]) + ->add('cosplayer', ChoiceType::class, [ + 'label' => 'Cosplayer ?', + 'choices' => [ + 'Non' => false, + 'Oui' => true, + ], + 'expanded' => true, + 'multiple' => false, + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('data_class', Members::class); + } +} diff --git a/src/Repository/MembersRepository.php b/src/Repository/MembersRepository.php new file mode 100644 index 0000000..39342b3 --- /dev/null +++ b/src/Repository/MembersRepository.php @@ -0,0 +1,43 @@ + + */ +class MembersRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Members::class); + } + + // /** + // * @return Members[] Returns an array of Members objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('m') + // ->andWhere('m.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('m.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Members + // { + // return $this->createQueryBuilder('m') + // ->andWhere('m.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/templates/admin/base.twig b/templates/admin/base.twig new file mode 100644 index 0000000..dca911a --- /dev/null +++ b/templates/admin/base.twig @@ -0,0 +1,129 @@ +{# Assurez-vous d'utiliser une version de Tailwind CSS qui supporte ces classes #} + + +
+ + + + {# 🛑 NO INDEX DIRECTIVE #} + +| + Pseudo + | ++ Rôle + | ++ Actions + | +|
|---|---|---|---|
|
+ {{ member.pseudo }}
+ |
+ + {# Utilisation d'un badge Tailwind pour le rôle #} + + {{ member.role }} + + | ++ + Éditer + + + Supprimer + + | +|
| + Aucun membre trouvé. + | +|||