Browse Source

Merge branch 'develop' into features/background

François Drouhard 2 years ago
parent
commit
866a521084

+ 1 - 1
README.md

@@ -14,7 +14,7 @@ Depuis un compte enregistré, on peut :
 Technique
 ===
 
-Le projet s'appuie sur Symfony 5.4 et utilise Bootstrap 5, JQuery, JQuery-ui, Font-Awesome, bootstrap-star-rating et Yarn.
+Le projet s'appuie sur Symfony 6.1 et utilise Bootstrap 5, JQuery, JQuery-ui, Font-Awesome, bootstrap-star-rating et Yarn.
 
 La partie intégration de vidéos et presque intégralement reprise de https://www.zirolis.com/tuto/integrer-une-video-externe-avec-symfony-et-php
 

+ 31 - 29
composer.json

@@ -11,45 +11,47 @@
         "doctrine/doctrine-bundle": "^2.7",
         "doctrine/doctrine-migrations-bundle": "^3.2",
         "doctrine/orm": "^2.13",
+        "league/commonmark": "^2.3",
         "phpdocumentor/reflection-docblock": "^5.3",
         "sensio/framework-extra-bundle": "^6.2",
         "symfony/apache-pack": "^1.0",
-        "symfony/asset": "^5.4",
-        "symfony/console": "^5.4",
-        "symfony/dotenv": "^5.4",
-        "symfony/expression-language": "^5.4",
+        "symfony/asset": "6.1.*",
+        "symfony/console": "6.1.*",
+        "symfony/dotenv": "6.1.*",
+        "symfony/expression-language": "6.1.*",
         "symfony/flex": "^2.2",
-        "symfony/form": "^5.4",
-        "symfony/framework-bundle": "^5.4",
-        "symfony/http-client": "5.4.*",
-        "symfony/mailer": "5.4.*",
+        "symfony/form": "6.1.*",
+        "symfony/framework-bundle": "6.1.*",
+        "symfony/http-client": "6.1.*",
+        "symfony/mailer": "6.1.*",
         "symfony/monolog-bundle": "^3.1",
-        "symfony/process": "^5.4",
-        "symfony/property-access": "5.4.*",
-        "symfony/property-info": "5.4.*",
-        "symfony/proxy-manager-bridge": "5.4.*",
-        "symfony/runtime": "5.4.*",
-        "symfony/security-bundle": "^5.4",
-        "symfony/serializer": "5.4.*",
-        "symfony/translation": "^5.4",
-        "symfony/twig-bundle": "^5.4",
-        "symfony/validator": "^5.4",
-        "symfony/web-link": "^5.4",
+        "symfony/process": "6.1.*",
+        "symfony/property-access": "6.1.*",
+        "symfony/property-info": "6.1.*",
+        "symfony/proxy-manager-bridge": "6.1.*",
+        "symfony/runtime": "6.1.*",
+        "symfony/security-bundle": "6.1.*",
+        "symfony/serializer": "6.1.*",
+        "symfony/translation": "6.1.*",
+        "symfony/twig-bundle": "6.1.*",
+        "symfony/validator": "6.1.*",
+        "symfony/web-link": "6.1.*",
         "symfony/webpack-encore-bundle": "^1.12",
-        "symfony/yaml": "^5.4",
-        "twig/extra-bundle": "^2.12|^3.0",
+        "symfony/yaml": "6.1.*",
+        "twig/extra-bundle": "^3.4",
+        "twig/markdown-extra": "^3.4",
         "twig/twig": "^2.12|^3.0"
     },
     "require-dev": {
         "phpunit/phpunit": "^9.5",
-        "symfony/browser-kit": "^5.4",
-        "symfony/css-selector": "^5.4",
-        "symfony/debug-bundle": "^5.4",
+        "symfony/browser-kit": "6.1.*",
+        "symfony/css-selector": "6.1.*",
+        "symfony/debug-bundle": "6.1.*",
         "symfony/maker-bundle": "^1.47",
-        "symfony/phpunit-bridge": "^5.4",
-        "symfony/stopwatch": "^5.4",
-        "symfony/var-dumper": "^5.4",
-        "symfony/web-profiler-bundle": "^5.4"
+        "symfony/phpunit-bridge": "6.1.*",
+        "symfony/stopwatch": "6.1.*",
+        "symfony/var-dumper": "6.1.*",
+        "symfony/web-profiler-bundle": "6.1.*"
     },
     "config": {
         "platform":{
@@ -100,7 +102,7 @@
     "extra": {
         "symfony": {
             "allow-contrib": false,
-            "require": "5.4.*"
+            "require": "6.1.*"
         }
     }
 }

File diff suppressed because it is too large
+ 531 - 111
composer.lock


+ 2 - 1
config/packages/doctrine_migrations.yaml

@@ -2,4 +2,5 @@ doctrine_migrations:
     migrations_paths:
         # namespace is arbitrary but should be different from App\Migrations
         # as migrations classes should NOT be autoloaded
-        'DoctrineMigrations': '%kernel.project_dir%/migrations'
+        'DoctrineMigrations': '%kernel.project_dir%/migrations'
+    enable_profiler: false

+ 5 - 0
config/packages/framework.yaml

@@ -27,6 +27,11 @@ framework:
                 headers:
                     Authorization: 'Bearer %env(TMDB_APIKEY_V4)%'
                     Content-Type: 'application/json;charset=utf-8'
+            mattermost.client:
+                base_uri: '%env(resolve:MATTERMOST_URL)%'
+                headers:
+                    Authorization: 'Bearer %env(MATTERMOST_TOKEN)%'
+                    Content-Type: 'application/json;charset=utf-8'
 
 when@test:
     framework:

+ 2 - 1
config/packages/security.yaml

@@ -48,9 +48,10 @@ security:
     # Easy way to control access for large sections of your site
     # Note: Only the *first* access control that matches will be used
     access_control:
-        - { path: ^/(login$|register$|motdepasseoublie$|resetpassword/token=|activate/token=|fichefilm/|$|liste-by/|liste-by_real/|recherche|prochaines-sorties$) , roles: PUBLIC_ACCESS }
+        - { path: ^/(login$|register$|motdepasseoublie$|resetpassword/token=|activate/token=|attente$|fichefilm/|$|liste-by/|liste-by_real/|recherche|prochaines-sorties$|p/about$) , roles: PUBLIC_ACCESS }
         - { path: ^/admin, roles: ROLE_ADMIN }
         - { path: ^/genre, roles: ROLE_MODERATEUR }
+        - { path: ^/p/edit, roles: ROLE_ADMIN }
         - { path: ^/, roles: IS_AUTHENTICATED_REMEMBERED }
 
 

+ 3 - 1
config/packages/web_profiler.yaml

@@ -4,7 +4,9 @@ when@dev:
         intercept_redirects: false
 
     framework:
-        profiler: { only_exceptions: false }
+        profiler:
+            only_exceptions: false
+            collect_serializer_data: true
 
 when@test:
     web_profiler:

+ 3 - 3
config/routes.yaml

@@ -1,3 +1,3 @@
-#index:
-#    path: /
-#    controller: App\Controller\DefaultController::index
+controllers:
+    resource: ../src/Controller/
+    type: attribute

+ 0 - 7
config/routes/annotations.yaml

@@ -1,7 +0,0 @@
-controllers:
-    resource: ../../src/Controller/
-    type: annotation
-
-kernel:
-    resource: ../../src/Kernel.php
-    type: annotation

+ 2 - 4
config/services.yaml

@@ -34,10 +34,8 @@ services:
     
     App\Service\Mattermost:
         arguments:
-            - '%env(MATTERMOST_URL)%'
-            - '%env(MATTERMOST_TOKEN)%'
-            - '%env(MATTERMOST_CHANNEL_ID)%'
-            - '%env(MATTERMOST_CHANNEL_ID_ADMIN)%'
+            $channelId: '%env(MATTERMOST_CHANNEL_ID)%'
+            $channelIdAdmin: '%env(MATTERMOST_CHANNEL_ID_ADMIN)%'
 
     App\Service\FilmCreationListener:
         arguments:

+ 32 - 0
migrations/Version20221115121723.php

@@ -0,0 +1,32 @@
+<?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 Version20221115121723 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 page (name VARCHAR(255) NOT NULL, content LONGTEXT NOT NULL, PRIMARY KEY(name)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+        $this->addSql('INSERT INTO page (name, content) VALUES ("about", "Modifier cette page à propos")');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('DROP TABLE page');
+    }
+}

+ 1 - 1
package.json

@@ -6,7 +6,7 @@
         "@popperjs/core": "^2.10.2",
         "@symfony/stimulus-bridge": "^3.2.1",
         "@symfony/webpack-encore": "^4.0.0",
-        "bootstrap": "^5.1.3",
+        "bootstrap": "^5.2.2",
         "bootstrap-star-rating": "^4.1.2",
         "core-js": "^3.23.0",
         "font-awesome": "^4.7.0",

+ 49 - 0
src/Controller/PageController.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Controller;
+
+use App\Entity\Page;
+use App\Form\PageType;
+use App\Repository\PageRepository;
+use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Annotation\Route;
+
+class PageController extends AbstractController
+{
+    #[Route('/p/{name}', name: 'app_page_show', methods: ['GET'])]
+    public function showPage(PageRepository $pageRepository, string $name): Response
+    {
+        $page = $pageRepository->find($name);
+        if (!$page) {
+            throw $this->createNotFoundException('La page ' . $name . ' n\'existe pas.');
+        }
+
+        return $this->render('page/index.html.twig', [
+            'page'   => $page
+        ]);
+    }
+
+    #[Route('/p/edit/{name}', name: 'app_page_edit', methods: ['GET', 'POST'])]
+    public function editPage(Request $request, Page $page, EntityManagerInterface $em): Response
+    {
+        $form = $this->createForm(PageType::class, $page);
+
+        $form->handleRequest($request);
+
+        if ($form->isSubmitted() && $form->isValid()) {
+            $em->flush();
+
+            $this->addFlash('success', 'Contenu modifié');
+            return $this->redirectToRoute('app_page_show', ['name' => $page->getName()]);
+        }
+
+        return $this->renderForm('page/edit.html.twig', [
+            'title' => $page->getName(),
+            'form'  => $form
+        ]);
+
+    }
+}

+ 16 - 8
src/Controller/SecurityController.php

@@ -132,17 +132,25 @@ class SecurityController extends AbstractController
         {
             $userManager->register($user);
 
-            $adresse = $this->generateUrl('security_activate', array('token'=>$user->getToken()), UrlGeneratorInterface::ABSOLUTE_URL);
-
-            $mail->sendMailActivation($user, $adresse);
-
-            $this->addFlash('success', 'Votre compte a été créé. Un mail vient d\'être envoyé pour l\'activation du compte');
-            return $this->redirectToRoute('app_login');
+            //$adresse = $this->generateUrl('security_activate', array('token'=>$user->getToken()), UrlGeneratorInterface::ABSOLUTE_URL);
+            //$mail->sendMailActivation($user, $adresse);
+            
+            $adresse = $this->generateUrl('admin_edituser', ['id' => $user->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
+            $mail->sendMailDemandeActivation($user, $adresse);
+
+            $this->addFlash('success', 'Votre compte a été créé. Un mail a été envoyé à l\'administrateur pour l\'activation du compte');
+            return $this->redirectToRoute('security_attente');
         }
 
-        return $this->renderForm('security/register.html.twig', array(
+        return $this->renderForm('security/register.html.twig', [
             'form'  => $form
-        ));
+        ]);
+    }
+
+    #[Route("/attente", name: "security_attente")]
+    public function attenteActivation(): Response
+    {
+        return $this->render('security/attente.html.twig');
     }
 
     #[Route("/motdepasseoublie", name: "security_envoyertoken")]

+ 13 - 12
src/Entity/Commentaire.php

@@ -13,27 +13,28 @@ class Commentaire
     #[ORM\Id]
     #[ORM\GeneratedValue(strategy: "AUTO")]
 
-    private $id;
+    private ?int $id = null;
 
     #[ORM\Column(name: "contenu", type: "text", length: 191, nullable: true)]
-    private $contenu;
+    
+    private ?string $contenu = null;
 
     #[ORM\Column(name: "note", type: "integer", nullable: true)]
 
-    private $note;
+    private ?int $note = null;
 
     #[ORM\ManyToOne(targetEntity: Film::class, inversedBy: "commentaires")]
     #[ORM\JoinColumn(nullable: false)]
 
-    private $film;
+    private ?Film $film = null;
 
     #[ORM\ManyToOne(targetEntity: User::class)]
     #[ORM\JoinColumn(nullable: false)]
 
-    private $user;
+    private ?User $user = null;
 
     #[ORM\Column(type: "datetime", nullable: true)]
-    private $dateSubmitted;
+    private ?\DateTimeInterface $dateSubmitted = null;
 
     public function __construct ()
     {
@@ -45,7 +46,7 @@ class Commentaire
         return $this->id;
     }
 
-    public function setContenu($contenu): self
+    public function setContenu(?string $contenu): self
     {
         $this->contenu = $contenu;
 
@@ -62,33 +63,33 @@ class Commentaire
         return $this->note;
     }
 
-    public function setNote($note): self
+    public function setNote(?int $note): self
     {
         $this->note = $note;
 
         return $this;
     }
 
-    public function setFilm(\App\Entity\Film $film): self
+    public function setFilm(?Film $film): self
     {
         $this->film = $film;
 
         return $this;
     }
 
-    public function getFilm(): Film
+    public function getFilm(): ?Film
     {
         return $this->film;
     }
 
-    public function setUser(\App\Entity\User $user): self
+    public function setUser(?User $user): self
     {
         $this->user = $user;
 
         return $this;
     }
 
-    public function getUser(): User
+    public function getUser(): ?User
     {
         return $this->user;
     }

+ 40 - 24
src/Entity/Film.php

@@ -14,58 +14,74 @@ class Film
     #[ORM\Column(name: "id", type: "integer")]
     #[ORM\Id]
     #[ORM\GeneratedValue(strategy: "AUTO")]
-    private $id;
+    
+    private ?int $id = null;
 
     #[ORM\Column(name: "titre", type: "string", length: 191)]
-    private $titre;
+    
+    private ?string $titre = null;
 
     #[ORM\Column(name: "annee", type: "date", nullable: true)]
-    private $annee;
+    
+    private ?\DateTimeInterface $annee = null;
 
     #[ORM\Column(name: "date_submited", type: "datetime", nullable: true)]
-    private $dateSubmited;
+    
+    private ?\DateTimeInterface $dateSubmited = null;
 
     #[ORM\Column(name: "lien", type: "string", length: 191, nullable: true)]
     #[Assert\Url()]
-    private $lien;
+    
+    private ?string $lien = null;
 
     #[ORM\Column(name: "note", type: "float", nullable: true)]
-    private $note;
+    
+    private ?float $note = null;
 
     #[ORM\Column(name: "nb_coms", type: "integer", nullable: true)]
-    private $nbComs;
+    
+    private ?int $nbComs = null;
 
     #[Assert\Valid()]
     #[ORM\OneToOne(targetEntity: MediaVideo::class, cascade: ["persist","remove"])]
     #[ORM\JoinColumn(nullable: true)]
-    private $mediaVideo;
+    
+    private ?MediaVideo $mediaVideo = null;
 
     #[ORM\ManyToMany(targetEntity: Realisateur::class, inversedBy: "films", cascade: ["persist"])]
-    private $realisateurs;
+    
+    private ?Collection $realisateurs = null;
 
     #[ORM\OneToMany(targetEntity: Commentaire::class, mappedBy: "film", orphanRemoval: true)]
-    private $commentaires;
+    
+    private ?Collection $commentaires = null;
 
     #[ORM\ManyToOne(targetEntity: User::class)]
     #[ORM\JoinColumn(nullable: true)]
-    private $authered;
+    
+    private ?User $authered = null;
 
     #[ORM\ManyToMany(targetEntity: User::class, inversedBy: "films")]
     #[ORM\JoinTable(name: "filmsavoir_users")]
-    private $usersWantToView;
+    
+    private ?Collection $usersWantToView = null;
 
     #[ORM\ManyToMany(targetEntity: User::class, inversedBy: "filmsVus")]
     #[ORM\JoinTable(name: "filmsvus_users")]
-    private $usersWhoSeen;
+    
+    private ?Collection $usersWhoSeen = null;
 
     #[ORM\ManyToMany(targetEntity: Genre::class, cascade: ["persist"])]
-    private $genres;
+    
+    private ?Collection $genres = null;
 
     #[ORM\Column(type: "text", nullable: true)]
-    private $information;
+    
+    private ?string $information = null;
 
     #[ORM\Column(type: "date", nullable: true)]
-    private $dateSortie;
+    
+    private ?\DateTimeInterface $dateSortie = null;
 
     public function __construct()
     {
@@ -94,14 +110,14 @@ class Film
         return $this->id;
     }
 
-    public function setTitre($titre): self
+    public function setTitre(?string $titre): self
     {
         $this->titre = $titre;
 
         return $this;
     }
 
-    public function getTitre(): string
+    public function getTitre(): ?string
     {
         return $this->titre;
     }
@@ -135,27 +151,27 @@ class Film
         return $this->dateSubmited;
     }
 
-    public function setDateSubmited(?\DateTime $dateSubmited): self
+    public function setDateSubmited(?\DateTimeInterface $dateSubmited): self
     {
         $this->dateSubmited = $dateSubmited;
 
         return $this;
     }
 
-    public function isNew(): bool
+    public function isNew(): ?bool
     {
         $finNew = (new \DateTime($this->getDateSubmited()->format("Y/m/d")))->modify('+1 day');
         return (new \DateTime('now') < $finNew);
     }
 
-    public function addCommentaire(\App\Entity\Commentaire $commentaire): self
+    public function addCommentaire(Commentaire $commentaire): self
     {
         $this->commentaires[] = $commentaire;
 
         return $this;
     }
 
-    public function removeCommentaire(\App\Entity\Commentaire $commentaire): self
+    public function removeCommentaire(Commentaire $commentaire): self
     {
         $this->commentaires->removeElement($commentaire);
 
@@ -250,7 +266,7 @@ class Film
         return $this->note;
     }
 
-    public function setNote($note): self
+    public function setNote(?float $note): self
     {
         $this->note = $note;
 
@@ -262,7 +278,7 @@ class Film
         return $this->nbComs;
     }
 
-    public function setNbComs($nbComs): self
+    public function setNbComs(?int $nbComs): self
     {
         $this->nbComs = $nbComs;
 

+ 6 - 4
src/Entity/Genre.php

@@ -13,24 +13,26 @@ class Genre
     #[ORM\Column(name: "id", type: "integer")]
     #[ORM\Id]
     #[ORM\GeneratedValue(strategy: "AUTO")]
-    private $id;
+    
+    private ?int $id = null;
 
     #[ORM\Column(name: "name", type: "string", length: 191, unique: true)]
-    private $name;
+    
+    private ?string $name = null;
 
     public function getId(): ?int
     {
         return $this->id;
     }
 
-    public function setName($name): self
+    public function setName(?string $name): self
     {
         $this->name = $name;
 
         return $this;
     }
 
-    public function getName(): string
+    public function getName(): ?string
     {
         return $this->name;
     }

+ 12 - 18
src/Entity/MediaVideo.php

@@ -12,25 +12,19 @@ use Symfony\Component\Validator\Constraints as Assert;
 
 class MediaVideo
 {
-    
-
     #[ORM\Column(name: "id", type: "integer")]
     #[ORM\Id]
     #[ORM\GeneratedValue(strategy: "AUTO")]
     
-    private $id;
-
-    
+    private ?int $id = null;
 
     #[ORM\Column(name: "type", type: "string", length: 191)]
     
-    private $type;
-
-    
+    private ?string $type = null;
 
     #[ORM\Column(name: "identif", type: "string", length: 191)]
     
-    private $identif;
+    private ?string $identif = null;
 
     #[Assert\Regex(
         pattern: "#^(http|https)://(youtu.be|www.youtube.com|www.dailymotion.com|vimeo.com|video.fdlibre.eu)/#",
@@ -38,7 +32,7 @@ class MediaVideo
         message: "L'url doit correspondre à l'url d'une vidéo Youtube, DailyMotion, Vimeo ou Peertube(fdlibre)"
     )]
     
-    private $url;
+    private ?string $url = null;
 
     public function setFromTmdb(string $type, string $identif): void
     {
@@ -56,7 +50,7 @@ class MediaVideo
         return $this->url();
     }
 
-    public function setUrl(string $url): self
+    public function setUrl(?string $url): self
     {
         $this->url = $url;
         $this->extractIdentif();
@@ -64,7 +58,7 @@ class MediaVideo
         return $this;
     }
     
-    public function setType(string $type): self
+    public function setType(?string $type): self
     {
         $this->type = $type;
 
@@ -76,7 +70,7 @@ class MediaVideo
         return $this->type;
     }
     
-    public function setIdentif(string $identif): self
+    public function setIdentif(?string $identif): self
     {
         $this->identif = $identif;
 
@@ -90,7 +84,7 @@ class MediaVideo
 
     /////////////////////
     // Méthodes
-    private function peertubeId($url): void
+    private function peertubeId(string $url): void
     {
         $tableau = explode("/", $url);
         $id = $tableau[count($tableau)-1];
@@ -98,7 +92,7 @@ class MediaVideo
         $this->setType('peertube');
     }
     
-    private function youtubeId($url): void
+    private function youtubeId(string $url): void
     {
         $tableaux = explode("=", $url);  // découpe l’url en deux  avec le signe ‘=’
 
@@ -106,7 +100,7 @@ class MediaVideo
         $this->setType('youtube');  // signale qu’il s’agit d’une video youtube et l’inscrit dans l’attribut $type
     }
 
-    private function youtubeCourteId($url): void
+    private function youtubeCourteId(string $url): void
     {
         $tableaux = explode("/", $url);  // on découpe l’url grâce au « / »
         $id = $tableaux[count($tableaux)-1];  // on retient la dernière partie qui contient l’identifiant
@@ -114,7 +108,7 @@ class MediaVideo
         $this->setType('youtube');  // signale qu’il s’agit d’une video youtube et l’inscrit dans l’attribut $type
     }
 
-    private function dailymotionId($url): void
+    private function dailymotionId(string $url): void
     {
         $cas = explode("/", $url); // On sépare la première partie de l'url des 2 autres
         $idb = $cas[4];  // On récupère la partie qui nous intéressent
@@ -125,7 +119,7 @@ class MediaVideo
         $this->setType('dailymotion'); // signale qu’il s’agit d’une video dailymotion et l’inscrit dans l’attribut $type
     }
 
-    private function vimeoId($url): void
+    private function vimeoId(string $url): void
     {
         $tableaux = explode("/", $url);  // on découpe l’url grâce au « / »
         $id = $tableaux[count($tableaux)-1];  // on reticent la dernière partie qui contient l’identifiant

+ 43 - 0
src/Entity/Page.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Entity;
+
+use App\Repository\PageRepository;
+use Doctrine\DBAL\Types\Types;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity(repositoryClass: PageRepository::class)]
+class Page
+{
+    #[ORM\Id]
+    #[ORM\Column(type: Types::STRING, length: 255)]
+
+    private ?string $name = null;
+
+    #[ORM\Column(type: Types::TEXT)]
+    private ?string $content = null;
+
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    public function setName(string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    public function getContent(): ?string
+    {
+        return $this->content;
+    }
+
+    public function setContent(string $content): self
+    {
+        $this->content = $content;
+
+        return $this;
+    }
+}

+ 5 - 5
src/Entity/Profile.php

@@ -15,18 +15,18 @@ class Profile
     #[ORM\GeneratedValue]
     #[ORM\Column(type: "integer")]
 
-    private $id;
+    private ?int $id = null;
 
 
     #[ORM\OneToOne(targetEntity: User::class, inversedBy: "profile", cascade: ["persist", "remove"])]
     #[ORM\JoinColumn(nullable: false)]
 
-    private $user;
+    private ?User $user = null;
 
 
     #[ORM\Column(type: "integer")]
 
-    private $view;
+    private ?int $view = null;
 
     public function __construct()
     {
@@ -43,7 +43,7 @@ class Profile
         return $this->user;
     }
 
-    public function setUser(User $user): self
+    public function setUser(?User $user): self
     {
         $this->user = $user;
 
@@ -55,7 +55,7 @@ class Profile
         return $this->view;
     }
 
-    public function setView(int $view): self
+    public function setView(?int $view): self
     {
         $this->view = $view;
 

+ 9 - 6
src/Entity/Realisateur.php

@@ -15,13 +15,16 @@ class Realisateur
     #[ORM\Column(name: "id", type: "integer")]
     #[ORM\Id]
     #[ORM\GeneratedValue(strategy: "AUTO")]
-    private $id;
+    
+    private ?int $id = null;
 
     #[ORM\Column(name: "nom_complet", type: "string", length: 191, unique: true)]
-    private $nomComplet;
+    
+    private ?string $nomComplet = null;
 
     #[ORM\ManyToMany(targetEntity: Film::class, mappedBy: "realisateurs", cascade: ["persist"])]
-    private $films;
+    
+    private ?Collection $films = null;
 
     public function getId(): ?int
     {
@@ -33,14 +36,14 @@ class Realisateur
         $this->films = new \Doctrine\Common\Collections\ArrayCollection();
     }
 
-    public function addFilm(\App\Entity\Film $film): self
+    public function addFilm(Film $film): self
     {
         $this->films[] = $film;
 
         return $this;
     }
 
-    public function removeFilm(\App\Entity\Film $film): self
+    public function removeFilm(Film $film): self
     {
         $this->films->removeElement($film);
 
@@ -57,7 +60,7 @@ class Realisateur
         return $this->nomComplet;
     }
 
-    public function setNomComplet($nom): self
+    public function setNomComplet(?string $nom): self
     {
         $this->nomComplet = $nom;
 

+ 41 - 41
src/Entity/User.php

@@ -22,53 +22,53 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
     #[ORM\Column(name: "id", type: "integer")]
     #[ORM\Id]
     #[ORM\GeneratedValue(strategy: "AUTO")]
-    private $id;
+    private ?int $id = null;
 
     #[ORM\Column(name: "username", type: "string", length: 191, unique: true)]
-    private $username;
+    private ?string $username = null;
 
     #[ORM\Column(name: "prenom", type: "string", length: 191, nullable: true)]
-    private $prenom;
+    private ?string $prenom = null;
 
     #[ORM\Column(name: "nom", type: "string", length: 191, nullable: true)]
-    private $nom;
+    private ?string $nom = null;
 
     #[ORM\Column(name: "mail", type: "string", length: 191, unique: true)]
     #[Assert\Email()]
-    private $mail;
+    private ?string $mail = null;
 
     #[ORM\Column(name: "password", type: "string", length: 191)]
-    private $password;
+    private ?string $password = null;
 
     #[ORM\Column(name: "token", type: "string", length: 191, unique: true)]
 
-    private $token;
+    private ?string $token = null;
 
     #[ORM\Column(name: "token_validity", type: "datetime")]
     #[Assert\Type("DateTime")]
-    private $tokenValidity;
+    private ?\DateTimeInterface $tokenValidity = null;
 
     #[ORM\Column(name: "salt", type: "string", length: 191, nullable: true)]
-    private $salt;
+    private ?string $salt = null;
 
     #[ORM\Column(name: "is_active", type: "boolean")]
-    private $isActive;
+    private ?bool $isActive = null;
 
     #[ORM\Column(name: "roles", type: "array")]
-    private $roles = array();
+    private ?array $roles = array();
 
     #[ORM\ManyToMany(targetEntity: Film::class, mappedBy: "usersWantToView")]
-    private $films;
+    private ?Collection $films = null;
 
     #[ORM\ManyToMany(targetEntity: Film::class, mappedBy: "usersWhoSeen")]
-    private $filmsVus;
+    private ?Collection $filmsVus = null;
 
     #[ORM\OneToOne(targetEntity: Profile::class, mappedBy: "user", cascade: ["persist", "remove"])]
-    private $profile;
+    private ?Profile $profile = null;
 
     #[ORM\Column(name: "last_activity", type: "datetime")]
     #[Assert\Type("DateTime")]
-    private $lastActivity;
+    private ?\DateTimeInterface $lastActivity = null;
 
     public function getLastActivity(): ?\DateTimeInterface
     {
@@ -82,7 +82,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this;
     }
 
-    public function isActiveNow(): bool
+    public function isActiveNow(): ?bool
     {
         $delay = new \DateTime('5 minutes ago');
 
@@ -94,7 +94,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->id;
     }
 
-    public function setUsername($username): self
+    public function setUsername(?string $username): self
     {
         $this->username = $username;
 
@@ -106,19 +106,19 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return (string) $this->username;
     }
 
-    public function getUserIdentifier(): ?string
+    public function getUserIdentifier(): string
     {
         return $this->username;
     }
 
-    public function setActivated($activated): self
+    public function setActivated(?bool $activated): self
     {
         $this->isActive = $activated;
 
         return $this;
     }
 
-    public function getActivated(): bool
+    public function getActivated(): ?bool
     {
         return $this->isActive;
     }
@@ -128,7 +128,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->prenom;
     }
 
-    public function setPrenom($prenom): self
+    public function setPrenom(?string $prenom): self
     {
         $this->prenom = $prenom;
 
@@ -140,7 +140,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->nom;
     }
 
-    public function setNom($nom): self
+    public function setNom(?string $nom): self
     {
         $this->nom = $nom;
 
@@ -152,14 +152,14 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->mail;
     }
 
-    public function setMail($mail): self
+    public function setMail(?string $mail): self
     {
         $this->mail = $mail;
 
         return $this;
     }
 
-    public function setPassword($password): self
+    public function setPassword(?string $password): self
     {
         $this->password = $password;
 
@@ -171,7 +171,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->password;
     }
 
-    public function setSalt($salt): self
+    public function setSalt(?string $salt): self
     {
         $this->salt = $salt;
 
@@ -188,7 +188,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->token;
     }
 
-    public function setToken($token): self
+    public function setToken(?string $token): self
     {
         //$this->token = hash("sha512", uniqid());
         $this->token = $token;
@@ -202,14 +202,14 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->tokenValidity;
     }
 
-    private function setTokenValidity(\DateTimeInterface $tokenValidity): self
+    private function setTokenValidity(?\DateTimeInterface $tokenValidity): self
     {
         $this->tokenValidity = $tokenValidity;
 
         return $this;
     }
 
-    public function isValidToken(): bool
+    public function isValidToken(): ?bool
     {
         $expire = (new \DateTime($this->getTokenValidity()->format("Y-m-d H:i:s")))->modify('+1 hour');
         dump($expire);
@@ -217,7 +217,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return ( $expire > new \DateTime('now') );
     }
 
-    public function setRoles($roles): self
+    public function setRoles(?array $roles): self
     {
         $this->roles = $roles;
 
@@ -249,14 +249,14 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
 
     ///////////////////////////////////////////////////////////////
    
-    public function addFilm(\App\Entity\Film $film): self
+    public function addFilm(Film $film): self
     {
         $this->films[] = $film;
 
         return $this;
     }
 
-    public function removeFilm(\App\Entity\Film $film): self
+    public function removeFilm(Film $film): self
     {
         $this->films->removeElement($film);
 
@@ -270,14 +270,14 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
 
     ///////////////////////////////////////////////////////////////////////////
 
-    public function addFilmVu(\App\Entity\Film $film): self
+    public function addFilmVu(Film $film): self
     {
         $this->filmsVus[] = $film;
 
         return $this;
     }
 
-    public function removeFilmVu(\App\Entity\Film $film): self
+    public function removeFilmVu(Film $film): self
     {
         $this->filmsVus->removeElement($film);
 
@@ -298,22 +298,22 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->getPrenom()." ".$this->getNom();
     }
 
-    public function isAccountNonExpired(): bool
+    public function isAccountNonExpired(): ?bool
     {
         return true;
     }
 
-    public function isAccountNonLocked(): bool
+    public function isAccountNonLocked(): ?bool
     {
         return true;
     }
 
-    public function isCredentialsNonExpired(): bool
+    public function isCredentialsNonExpired(): ?bool
     {
         return true;
     }
 
-    public function isEnabled(): bool
+    public function isEnabled(): ?bool
     {
         return $this->isActive;
     }
@@ -330,7 +330,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         ));
     }
 
-    public function unserialize($serialized):void 
+    public function unserialize(?string $serialized):void 
     {
         list (
             $this->id,
@@ -343,12 +343,12 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
             ) = unserialize($serialized, array('allowed_classes' => false));
     }
 
-    public function wantToSee(Film $film): bool
+    public function wantToSee(Film $film): ?bool
     {
         return $this->getFilms()->contains($film);
     }
 
-    public function haveSeen(Film $film): bool
+    public function haveSeen(Film $film): ?bool
     {
         return $this->getFilmsVus()->contains($film);
     }
@@ -358,7 +358,7 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->profile;
     }
 
-    public function setProfile(Profile $profile): self
+    public function setProfile(?Profile $profile): self
     {
         // set the owning side of the relation if necessary
         if ($profile->getUser() !== $this) {

+ 20 - 15
src/Form/CommentaireType.php

@@ -2,6 +2,7 @@
 
 namespace App\Form;
 
+use App\Entity\Commentaire;
 use Symfony\Component\Form\Extension\Core\Type\NumberType;
 use Symfony\Component\Form\AbstractType;
 use Symfony\Component\Form\Extension\Core\Type\TextareaType;
@@ -15,13 +16,13 @@ class CommentaireType extends AbstractType
     /**
      * {@inheritdoc}
      */
-    public function buildForm(FormBuilderInterface $builder, array $options)
+    public function buildForm(FormBuilderInterface $builder, array $options): void
     {
 	    $builder
-            ->add('note', NumberType::class, array (
+            ->add('note', NumberType::class, [
                 'required'  => false,
                 'label'       => false,
-                'attr'      => array (
+                'attr'      => [
                     'min'   => 0,
                     'max'   => 5,
                     'class' => "rating",
@@ -30,27 +31,31 @@ class CommentaireType extends AbstractType
                     'data-show-caption' => "false",
                     'data-size'         => "sm",
                     'data-theme'          => "krajee-fa"
-                )
-            ))
-            ->add('contenu', TextareaType::class, array(
+                ]
+            ])
+            ->add('contenu', TextareaType::class, [
                 'required' => false,
-                'label' => false
-            ))
-		    ->add('save', SubmitType::class, array(
+                'label' => false,
+                'attr'  => [
+                    'rows'  => 10
+                ]
+            ])
+            ->add('save', SubmitType::class, [
 		        'label' => 'Enregistrer le commentaire',
-                'attr'=>array(
+                'attr' => [
                     'class'  =>  'btn-primary'
-                )));
+                ]
+            ]);
     }
     
     /**
      * {@inheritdoc}
      */
-    public function configureOptions(OptionsResolver $resolver)
+    public function configureOptions(OptionsResolver $resolver): void
     {
-        $resolver->setDefaults(array(
-            'data_class' => 'App\Entity\Commentaire'
-        ));
+        $resolver->setDefaults([
+            'data_class' => Commentaire::class,
+        ]);
     }
 
     /**

+ 33 - 0
src/Form/PageType.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Form;
+
+use App\Entity\Page;
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class PageType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options): void
+    {
+        $builder
+            //->add('name')
+            ->add('content', TextareaType::class, [
+                'attr'  => [
+                    'rows'  => 30
+                ]
+            ])
+            ->add('Enregistrer', SubmitType::class)
+        ;
+    }
+
+    public function configureOptions(OptionsResolver $resolver): void
+    {
+        $resolver->setDefaults([
+            'data_class' => Page::class,
+        ]);
+    }
+}

+ 66 - 0
src/Repository/PageRepository.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Repository;
+
+use App\Entity\Page;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @extends ServiceEntityRepository<Page>
+ *
+ * @method Page|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Page|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Page[]    findAll()
+ * @method Page[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class PageRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, Page::class);
+    }
+
+    public function save(Page $entity, bool $flush = false): void
+    {
+        $this->getEntityManager()->persist($entity);
+
+        if ($flush) {
+            $this->getEntityManager()->flush();
+        }
+    }
+
+    public function remove(Page $entity, bool $flush = false): void
+    {
+        $this->getEntityManager()->remove($entity);
+
+        if ($flush) {
+            $this->getEntityManager()->flush();
+        }
+    }
+
+//    /**
+//     * @return Page[] Returns an array of Page objects
+//     */
+//    public function findByExampleField($value): array
+//    {
+//        return $this->createQueryBuilder('p')
+//            ->andWhere('p.exampleField = :val')
+//            ->setParameter('val', $value)
+//            ->orderBy('p.id', 'ASC')
+//            ->setMaxResults(10)
+//            ->getQuery()
+//            ->getResult()
+//        ;
+//    }
+
+//    public function findOneBySomeField($value): ?Page
+//    {
+//        return $this->createQueryBuilder('p')
+//            ->andWhere('p.exampleField = :val')
+//            ->setParameter('val', $value)
+//            ->getQuery()
+//            ->getOneOrNullResult()
+//        ;
+//    }
+}

+ 2 - 0
src/Service/CommentaireManager.php

@@ -26,6 +26,7 @@ class CommentaireManager {
 
     public function addCommentaire (Commentaire $commentaire, Film $film): void
     {
+        $commentaire->setContenu(htmlspecialchars($commentaire->getContenu()));
         $commentaire->setUser($this->user);
         $commentaire->setFilm(($film));
         $film->addCommentaire($commentaire);
@@ -35,6 +36,7 @@ class CommentaireManager {
 
     public function editCommentaire(Commentaire $commentaire): void
     {
+        $commentaire->setContenu(htmlspecialchars($commentaire->getContenu()));
         $this->em->flush();
     }
 

+ 15 - 5
src/Service/Mail.php

@@ -2,6 +2,7 @@
 
 namespace App\Service;
 
+use App\Entity\User;
 use Symfony\Component\Mailer\MailerInterface;
 use Symfony\Component\Mime\Address;
 use Symfony\Component\Mime\Email;
@@ -31,7 +32,7 @@ class Mail
 
     }
 
-    protected function sendMessage($subject, $to, $body): void
+    protected function sendMessage(string $subject, string $to, string $body): void
     {
         $mail = (new Email())
             ->from(new Address($this->from, $this->name))
@@ -43,21 +44,30 @@ class Mail
         $this->mailer->send($mail);
     }
 
-    public function sendMailActivation(\App\Entity\User $user, $lien): void
+    public function sendMailActivation(User $user, string $lien): void
     {
         $subject = "Activation de votre compte";
         $template = 'security/mail_activate.html.twig';
         $to = $user->getMail();
-        $body = $this->templating->render($template, array('user' => $user, 'lien'  => $lien));
+        $body = $this->templating->render($template, ['user' => $user, 'lien'  => $lien]);
         $this->sendMessage($subject, $to, $body);
     }
 
-    public function sendMailTokenMp(\App\Entity\User $user, $lien): void
+    public function sendMailDemandeActivation(User $user, string $lien): void
+    {
+        $subject = "Demande d'activation";
+        $template = 'security/mail_demande_activation.html.twig';
+        $to = $this->from;
+        $body = $this->templating->render($template, ['user' => $user, 'lien' => $lien]);
+        $this->sendMessage($subject, $to, $body);
+    }
+
+    public function sendMailTokenMp(User $user, string $lien): void
     {
         $subject = "Mot de passe perdu";
         $template = 'security/mail_tokenmdp.html.twig';
         $to = $user->getMail();
-        $body = $this->templating->render($template, array('user' => $user, 'lien'  => $lien));
+        $body = $this->templating->render($template, ['user' => $user, 'lien'  => $lien]);
         $this->sendMessage($subject, $to, $body);
     }
 }

+ 21 - 30
src/Service/Mattermost.php

@@ -5,8 +5,10 @@ namespace App\Service;
 
 use App\Entity\Film;
 use App\Entity\User;
-use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
-use Symfony\Component\Routing\Generator\UrlGeneratorInterface;;
+use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
 
 /**
  * Envoi notifs mattermost
@@ -17,44 +19,33 @@ class Mattermost
      * Mattermost Manager
      */
     public function __construct(
-        protected string $url,
-        protected string $token,
+        protected HttpClientInterface $mattermostClient,
         protected string $channelId,
         protected string $channelIdAdmin,
         protected UrlGeneratorInterface $router,
-        protected FlashBagInterface $flashBagInterface)
+        protected RequestStack $requestStack
+    )
     {
-        $this->url = $url . "/api/v4/posts";
     }
 
-    protected function SendNotif($message, $isChanAdmin = False) :void
+    protected function SendNotif(string $message, bool $isChanAdmin = False) :void
     {
         try {
-            if (function_exists("curl_init")) {
-            // crée une nouvelle ressource cURL
-                $ch = curl_init();
-            } else {
-                throw new \Exception("Curl n'est pas installé.", 500);
-            }
-
-            // fixe l'URL et les autres options appropriées
-            $options = array(
-                CURLOPT_URL => $this->url,
-                CURLOPT_HTTPHEADER => array('Content-Type: application/json', 'Authorization: Bearer ' . $this->token),
-                CURLOPT_POSTFIELDS  =>  '{"channel_id": "' . ($isChanAdmin ? $this->channelIdAdmin : $this->channelId) . '", "message": "' . $message . '"}'
+            $response = $this->mattermostClient->request(
+                'POST',
+                'api/v4/posts', [
+                    'json'  => [
+                        "channel_id" => ($isChanAdmin ? $this->channelIdAdmin : $this->channelId),
+                        "message"    => $message
+                    ]
+                ]
             );
+            // Appeler au moins une méthode pour déclencher l'exception en cas d'erreur réseau
+            $response->getHeaders();
 
-            curl_setopt_array($ch, $options);
-
-            // attrape l'URL et la passe au navigateur
-            curl_exec($ch);
-
-            // ferme la ressource cURL et libère les ressources systèmes
-            curl_close($ch);
-        } catch (\Exception $e) {
-            $this->flashBagInterface->add('error', "L'envoi vers mattermost a échoué.");
+        } catch (TransportExceptionInterface $e) {
+            $this->requestStack->getSession()->getFlashBag()->add('error', "L'envoi vers mattermost a échoué.");
         }
-        
     }
 
     public function sendNouveauFilm(Film $film) :void
@@ -86,7 +77,7 @@ class Mattermost
         $this->SendNotif($message);
     }
 
-    public function sendNewUser($userName) : void
+    public function sendNewUser(string $userName) : void
     {
         $message =
         ":warning: Un utilisateur vient de s'enregistrer dans la [vidéothèque]("

+ 1 - 1
src/Service/UserManager.php

@@ -51,7 +51,7 @@ class UserManager
 
     public function resetPassword(User $user): void
     {
-        $user->setActivated($user);
+        //$user->setActivated(true);
         $this->enregistrerUser($user);
     }
     public function enregistrerUser (User $user): void

+ 25 - 0
src/Twig/Extension/ShowLinksExtension.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Twig\Extension;
+
+use Twig\Extension\AbstractExtension;
+use Twig\TwigFilter;
+use Twig\TwigFunction;
+
+class ShowLinksExtension extends AbstractExtension
+{
+    public function getFilters(): array
+    {
+        return [
+            // If your filter generates SAFE HTML, you should add a third
+            // parameter: ['is_safe' => ['html']]
+            // Reference: https://twig.symfony.com/doc/3.x/advanced.html#automatic-escaping
+            new TwigFilter('show_links', [$this, 'showLinks']),
+        ];
+    }
+
+    public function showLinks(string $texte): string
+    {
+        return preg_replace('#((https?|ftp)://(\S*?\.\S*?))([\s)\[\]{},;"\':<]|\.\s|$)#i', "<a href=\"$1\" target=\"_blank\">$1</a>$4", $texte);
+    }
+}

+ 17 - 28
symfony.lock

@@ -7,12 +7,10 @@
         "recipe": {
             "repo": "github.com/symfony/recipes",
             "branch": "main",
-            "version": "1.0",
-            "ref": "a2759dd6123694c8d901d0ec80006e044c2e6457"
+            "version": "1.10",
+            "ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05"
         },
-        "files": [
-            "config/routes/annotations.yaml"
-        ]
+        "files": []
     },
     "doctrine/cache": {
         "version": "v1.8.0"
@@ -44,16 +42,16 @@
         ]
     },
     "doctrine/doctrine-migrations-bundle": {
-        "version": "1.2",
+        "version": "3.2",
         "recipe": {
             "repo": "github.com/symfony/recipes",
-            "branch": "master",
-            "version": "1.2",
-            "ref": "c1431086fec31f17fbcfe6d6d7e92059458facc1"
+            "branch": "main",
+            "version": "3.1",
+            "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
         },
         "files": [
             "config/packages/doctrine_migrations.yaml",
-            "src/Migrations/.gitignore"
+            "migrations/.gitignore"
         ]
     },
     "doctrine/event-manager": {
@@ -431,15 +429,9 @@
     "symfony/polyfill-php72": {
         "version": "v1.11.0"
     },
-    "symfony/polyfill-php73": {
-        "version": "v1.11.0"
-    },
     "symfony/polyfill-php80": {
         "version": "v1.17.1"
     },
-    "symfony/polyfill-php81": {
-        "version": "v1.23.0"
-    },
     "symfony/process": {
         "version": "v4.2.8"
     },
@@ -453,12 +445,12 @@
         "version": "v5.1.11"
     },
     "symfony/routing": {
-        "version": "5.4",
+        "version": "6.1",
         "recipe": {
             "repo": "github.com/symfony/recipes",
             "branch": "main",
-            "version": "5.3",
-            "ref": "85de1d8ae45b284c3c84b668171d2615049e698f"
+            "version": "6.1",
+            "ref": "a44010c0d06989bd4f154aa07d2542d47caf5b83"
         },
         "files": [
             "config/packages/routing.yaml",
@@ -466,12 +458,12 @@
         ]
     },
     "symfony/security-bundle": {
-        "version": "5.4",
+        "version": "6.1",
         "recipe": {
             "repo": "github.com/symfony/recipes",
             "branch": "main",
-            "version": "5.3",
-            "ref": "98f1f2b0d635908c2b40f3675da2d23b1a069d30"
+            "version": "6.0",
+            "ref": "8a5b112826f7d3d5b07027f93786ae11a1c7de48"
         },
         "files": [
             "config/packages/security.yaml"
@@ -483,9 +475,6 @@
     "symfony/security-csrf": {
         "version": "v4.2.8"
     },
-    "symfony/security-guard": {
-        "version": "v4.2.8"
-    },
     "symfony/security-http": {
         "version": "v4.2.8"
     },
@@ -555,12 +544,12 @@
         "version": "v4.2.8"
     },
     "symfony/web-profiler-bundle": {
-        "version": "5.4",
+        "version": "6.1",
         "recipe": {
             "repo": "github.com/symfony/recipes",
             "branch": "main",
-            "version": "5.3",
-            "ref": "24bbc3d84ef2f427f82104f766014e799eefcc3e"
+            "version": "6.1",
+            "ref": "e42b3f0177df239add25373083a564e5ead4e13a"
         },
         "files": [
             "config/packages/web_profiler.yaml",

+ 62 - 72
templates/navbar.html.twig

@@ -4,60 +4,51 @@
     </button>
     <a class="navbar-brand" href="{{ path('videotheque_liste') }}">Videothèque</a>
     <div class="collapse navbar-collapse" id="navbarSupportedContent">
-        {% if not is_granted('IS_AUTHENTICATED_REMEMBERED') %}
-            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
-                <li class="nav-item">
-                    <a class="nav-link
-                    {% if app.request.attributes.get('_route') == 'videotheque_liste' %}active{% endif %}"
-                    href="{{ path('videotheque_liste') }}">Liste des films</a>
-                </li>
-                <li class="nav-item">
-                    <a class="nav-link
-                    {% if app.request.attributes.get('_route') == 'prochaines_sorties' %}active{% endif %}"
-                    href="{{ path('prochaines_sorties') }}">Prochaines sorties</a>
-                </li>
-            </ul>
-        {% endif %}
-        {%  if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
         <ul class="navbar-nav me-auto mb-2 mb-lg-0">
+            {%  if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
             <li class="nav-item">
                 <a class="nav-link 
                 {% if app.request.attributes.get('_route') == 'videothequepersonnelle_maliste' %}active{% endif %}"
                 href="{{ path('videothequepersonnelle_maliste') }}">Ma liste à voir</a>
             </li>
+            {% endif %}
             <li class="nav-item">
                 <a class="nav-link
                 {% if app.request.attributes.get('_route') == 'videotheque_liste' %}active{% endif %}"
-                href="{{ path('videotheque_liste') }}">Films</a>
+                href="{{ path('videotheque_liste') }}">Liste des films</a>
             </li>
             <li class="nav-item">
                 <a class="nav-link
                 {% if app.request.attributes.get('_route') == 'prochaines_sorties' %}active{% endif %}"
                 href="{{ path('prochaines_sorties') }}">Prochaines sorties</a>
             </li>
+            {% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
             <li class="nav-item">
                 <a class="nav-link
                 {% if app.request.attributes.get('_route') == 'realisateur_liste' %}active{% endif %}"
                 href="{{ path('realisateur_liste') }}">Réalisateurs</a>
             </li>
+            {% endif %}
             {%  if is_granted('ROLE_MODERATEUR') %}
-                <ul class="navbar-nav">
-                    <li class="nav-item dropdown">
-                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownAdmin" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                            Administration
-                        </a>
-                        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
-                            {% if is_granted('ROLE_ADMIN') %}
-                                <a class="dropdown-item" href="{{ path('admin_index') }}">Utilisateurs</a>
-                                <div class="dropdown-divider"></div>
-                            {% endif %}
-                            <a class="dropdown-item" href="{{ path('genre_liste') }}">Liste des genres</a>
-                        </div>
-                    </li>
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownAdmin" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                    Administration
+                </a>
+                <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
+                    {% if is_granted('ROLE_ADMIN') %}
+                        <li><a class="dropdown-item" href="{{ path('admin_index') }}">Utilisateurs</a></li>
+                        <li><hr class="dropdown-divider"></li>
+                    {% endif %}
+                    <li><a class="dropdown-item" href="{{ path('genre_liste') }}">Liste des genres</a></li>
                 </ul>
-            {%  endif %}
+            </li>
+            {%  endif %}           
+            <li class="nav-item">
+                <a class="nav-link
+                {% if app.request.attributes.get('_route') == 'app_page_show' and app.request.attributes.get('_route_params')['name'] == 'about' %}active{% endif %}"
+                href="{{path('app_page_show', {'name': 'about'}) }}">A propos</a>
+            </li>
         </ul>
-        {% endif %}
         <ul class="navbar-nav">
             <li class="nav-item">
                 <form class="me-auto" action="{{ path('search_recherche') }}">
@@ -68,42 +59,7 @@
                 </form>
             </li>
         </ul>
-        <ul class="navbar-nav">
-        
-            <li class="nav-item">
-                <a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#modalWindow"><i class="fa fa-info-circle fa-lg text-light nav-link" aria-hidden="true"></i></a>
-            <li>
-        </ul>
-        {% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
-        <ul class="navbar-nav">
-            <li class="nav-item dropdown">
-                <a class="nav-link dropdown-toggle" href="#" id="navbarHelpDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                    <i class="fa fa-question-circle fa-lg"></i>
-                </a>
-                    <div class="dropdown-menu dropdown-menu-end p-4" aria-labelledby="navbarHelpDropdown" style="width: 400px;">
-                            <p><i class="fa fa-bookmark fa-lg text-primary"></i> : Films que l'on souhaite voir. On les retrouve dans "Liste de mes films"</p>
-                            <p><i class="fa fa-eye fa-lg text-success"></i> : Film qu'on a vu</p>
-                            <p><i class="fa fa-eye-slash fa-lg text-secondary"></i> : Film qu'on n'a pas vu</p>
-                    </div>
-            </li>
-        </ul>
-        {% endif %}
-        <ul class="navbar-nav">
-            <li class="nav-item dropdown">
-                <a class="nav-link dropdown-toggle" href="#" id="navbarBellDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                    <i class="fa fa-bell fa-lg"></i>
-                </a>
-                <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarBellDropdown" style="width: 400px;">
-                    <div class="list-group px-4 py-3">
-                        {{ afficheNouveautes() | raw }}
-                    </div>
-                </div>
-            </li>
-        </ul>
-        
-        {#{% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}#}
         
-        {#{% endif %}#}
         {%  if not is_granted('IS_AUTHENTICATED_REMEMBERED') %}
             <ul class="navbar-nav">
                 <li class="nav-item"><a class="nav-link" href="{{ path('app_login') }}">Se connecter</a></li>
@@ -114,14 +70,48 @@
                     <a class="nav-link dropdown-toggle" href="#" id="navbarUserDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                         {{ app.user.nomComplet }}
                     </a>
-                    <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarUserDropdown">
-                        <a class="dropdown-item" href="{{ path('user_profil') }}"><i class="fa fa-user"></i> Profil</a>
-                        <a class="dropdown-item" href="{{ path('user_preferences') }}"><i class="fa fa-cog"></i> Préférences</a>
-                        <div class="dropdown-divider"></div>
-                        <a class="dropdown-item" href="{{ path('app_logout') }}"><i class="fa fa-sign-out"></i> Se déconnecter</a>
-                    </div>
+                    <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarUserDropdown">
+                        <li><a class="dropdown-item" href="{{ path('user_profil') }}"><i class="fa fa-user"></i> Profil</a></li>
+                        <li><a class="dropdown-item" href="{{ path('user_preferences') }}"><i class="fa fa-cog"></i> Préférences</a></li>
+                        <li><hr class="dropdown-divider"></li>
+                        <li><a class="dropdown-item" href="{{ path('app_logout') }}"><i class="fa fa-sign-out"></i> Se déconnecter</a></li>
+                    </ul>
                 </li>
             </ul>
         {% endif %}
     </div>
+    {# Icones qui ne sont pas dans le collapse #}
+    <ul class="navbar-nav">
+        <li class="nav-item">
+            <a href="#" class="nav-link me-3" data-bs-toggle="modal" data-bs-target="#modalWindow"><i class="fa fa-info-circle fa-lg text-light" aria-hidden="true"></i></a>
+        <li>
+    </ul>
+    {% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
+    <ul class="navbar-nav">
+        <li class="nav-item dropdown">
+            <a class="nav-link dropdown-toggle" href="#" id="navbarHelpDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <i class="fa fa-question-circle fa-lg"></i>
+            </a>
+            <div class="dropdown-menu dropdown-menu-end p-4" aria-labelledby="navbarHelpDropdown" style="width: 400px;">
+                    <p><i class="fa fa-bookmark fa-lg text-primary"></i> : Films que l'on souhaite voir. On les retrouve dans "Liste de mes films"</p>
+                    <p><i class="fa fa-eye fa-lg text-success"></i> : Film qu'on a vu</p>
+                    <p><i class="fa fa-eye-slash fa-lg text-secondary"></i> : Film qu'on n'a pas vu</p>
+            </div>
+        </li>
+    </ul>
+    {% endif %}
+    <ul class="navbar-nav">
+        <li class="nav-item dropdown">
+            <a class="nav-link dropdown-toggle" href="#" id="navbarBellDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <i class="fa fa-bell fa-lg"></i>
+            </a>
+            <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarBellDropdown" style="width: 400px;">
+                <div class="list-group px-4 py-3">
+                    {{ afficheNouveautes() | raw }}
+                </div>
+            </div>
+        </li>
+    </ul>
+
+
 </nav>

+ 6 - 0
templates/page/edit.html.twig

@@ -0,0 +1,6 @@
+{% extends 'base.html.twig' %}
+
+{% block body %}
+    <h1>{{ "modifier_page" | trans }} "{{ title }}"</h1>
+    {{ form(form) }}
+{% endblock %}

+ 11 - 0
templates/page/index.html.twig

@@ -0,0 +1,11 @@
+{% extends 'base.html.twig' %}
+
+{% block body %}
+    {% if is_granted('ROLE_ADMIN') %}
+        <a href="{{ path('app_page_edit', {'name': page.name}) }}" class="btn btn-primary mb-3"><i class="fa fa-edit"></i> {{ "edit_page" | trans }}</a>
+    {% endif %}
+    
+    {% apply markdown_to_html %}
+        {{ page.content }}
+    {% endapply %}
+{% endblock %}

+ 11 - 0
templates/security/attente.html.twig

@@ -0,0 +1,11 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}En attente{% endblock %}
+
+{% block body %}
+    <h1>En attente de validation</h1>
+    <p>Votre demande d'activation a été envoyé à l'administrateur qui la prendra en charge rapidement.</p>
+    <p>Pour rappel, cette application est réservée à mes connaissances, je me réserve donc le droit de refuser l'activation du compte.</p>
+    <p>Merci de votre compréhension.</p>
+    <a href="{{ path('videotheque_liste') }}" class="btn btn-link">Retour à la liste des films</a>
+{% endblock %}

+ 13 - 0
templates/security/mail_demande_activation.html.twig

@@ -0,0 +1,13 @@
+Bonjour,
+
+L'utilisateur {{ user.username }} vient de s'enregistrer sur la vidéothèque.
+Veuillez vérifier les informations ci-dessous et vous assurer qu'il s'agit d'une connaissance.
+
+Nom : {{ user.nom }}
+Prénom : {{ user.prenom }}
+Mail : {{ user.mail }}
+
+Accéder au compte utilisateur : {{ lien }}
+
+-- 
+L'administrateur tout puissant

+ 4 - 4
templates/videotheque/form.html.twig

@@ -27,10 +27,10 @@
                         <button type="button" id="add_genre" class="btn btn-link add-another-collection-widget mb-3" data-path="{{ path('videotheque_ajax_genres') }}" data-list-selector="#genre-fields-list">Ajouter un genre</button>
                         <ul id="genre-fields-list"
                             data-prototype="{{ form_widget(form.genres.vars.prototype)|e }}"
-                            data-widget-tags="{{ '<li class="list-group-item"></li>'|e }}"
+                            data-widget-tags="{{ '<li class="list-group-item mb-3"></li>'|e }}"
                             data-widget-counter="{{ form.children|length }}">
                             {% for genreField in form.genres %}
-                            <li class="list-group-item">
+                            <li class="list-group-item mb-3">
                                 {{ form_widget(genreField) }}
                                 {{ form_errors(genreField) }}
                             </li>
@@ -51,10 +51,10 @@
                         <button type="button" id="add_realisateur" class="btn btn-link add-another-collection-widget mb-3" data-path="{{ path('videotheque_ajax_realisateurs') }}" data-list-selector="#realisateur-fields-list">Ajouter un réalisateur</button>
                         <ul id="realisateur-fields-list"
                             data-prototype="{{ form_widget(form.realisateurs.vars.prototype)|e }}"
-                            data-widget-tags="{{ '<li class="list-group-item"></li>'|e }}"
+                            data-widget-tags="{{ '<li class="list-group-item mb-3"></li>'|e }}"
                             data-widget-counter="{{ form.children|length }}">
                             {% for realisateurField in form.realisateurs %}
-                            <li class="list-group-item">
+                            <li class="list-group-item mb-3">
                                 {{ form_widget(realisateurField) }}
                                 {{ form_errors(realisateurField) }}
                             </li>

+ 1 - 1
templates/videotheque/voirfilm.html.twig

@@ -174,7 +174,7 @@
                                            value="{{ commentaire.note }}">
                                 {% endif %}
                                 {% if commentaire.contenu != "" %}
-                                    <p class="mb-1">{{ commentaire.contenu | nl2br }}</p>
+                                    <p>{{ commentaire.contenu | show_links | raw | nl2br }}</p>
                                 {%  endif %}
                             </div>
                         {% endfor %}

+ 3 - 0
translations/messages.fr.yaml

@@ -17,6 +17,9 @@ repeat-password: Répéter le mot de passe
 Recherche: Recherche
 Rechercher: Rechercher
 search_in_tmdb: Rechercher un titre de film sur TheMovieDB.org
+modifier_page: Modifier la page
+Content: Contenu de la page
+edit_page: Editer la page
 
 Username: Nom d'utilisateur
 Prenom: Prénom

+ 4 - 4
yarn.lock

@@ -1787,10 +1787,10 @@ bootstrap-star-rating@^4.1.2:
   dependencies:
     opencollective-postinstall "^2.0.2"
 
-bootstrap@^5.1.3:
-  version "5.1.3"
-  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34"
-  integrity sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==
+bootstrap@^5.2.2:
+  version "5.2.2"
+  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.2.tgz#834e053eed584a65e244d8aa112a6959f56e27a0"
+  integrity sha512-dEtzMTV71n6Fhmbg4fYJzQsw1N29hJKO1js5ackCgIpDcGid2ETMGC6zwSYw09v05Y+oRdQ9loC54zB1La3hHQ==
 
 brace-expansion@^1.1.7:
   version "1.1.11"

Some files were not shown because too many files changed in this diff