feat(tuto): Ajoute gestion des tutoriels avec vidéos et PDFs.

This commit is contained in:
Serreau Jovann
2025-10-01 10:57:11 +02:00
parent ee8ba6b2df
commit 8e3b9c8ad8
8 changed files with 265 additions and 100 deletions

View File

@@ -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 Version20251001081120 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('ALTER TABLE esy_web_tuto ADD type VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE esy_web_tuto DROP type');
}
}

View File

@@ -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 Version20251001081226 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('ALTER TABLE esy_web_tuto ADD type_file VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE esy_web_tuto DROP type_file');
}
}

View File

@@ -16,49 +16,113 @@ use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
class TutoController extends AbstractController
{
#[Route(path: '/artemis/esyweb/tuto/add', name: 'artemis_esyweb_tuto_add', methods: ['GET', 'POST'])]
public function tutosAdd(Request $request,LoggerService $loggerService,EsyWebTutoRepository $esyWebTutoRepository,EntityManagerInterface $entityManager)
{
$tuto = new EsyWebTuto();
$tuto->setPos($esyWebTutoRepository->count());
$tuto->setUpdateAt(new \DateTimeImmutable());
$form = $this->createForm(TutoType::class,$tuto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($tuto);
$entityManager->flush();
$loggerService->log("SUCCESS","Crée un tutoriel");
$this->addFlash("success","Tutoriel crée un tutoriel");
return $this->redirectToRoute('artemis_esyweb_tuto');
}
return $this->render('artemis/esyweb/tuto_add.twig',[
'form' => $form->createView(),
]);
}
#[Route(path: '/artemis/esyweb/tuto', name: 'artemis_esyweb_tuto', methods: ['GET', 'POST'])]
public function tutos(KernelInterface $kernel,Request $request,UploaderHelper $uploaderHelper,LoggerService $loggerService,EsyWebTutoRepository $esyWebTutoRepository,EntityManagerInterface $entityManager)
{
if($request->query->has('idDelete')) {
$ndd = $esyWebTutoRepository->find($request->query->get('idDelete'));
$entityManager->remove($ndd);
$entityManager->flush();
$loggerService->log("DELETE","Suppression d'un tutoriel");
$this->addFlash("success","Tutoriel bien supprimer");
return $this->redirectToRoute('artemis_esyweb_tuto');
}
if($request->query->has('idView')) {
$ndd = $esyWebTutoRepository->find($request->query->get('idView'));
$path = $uploaderHelper->asset($ndd,'file');
$response = new BinaryFileResponse($kernel->getProjectDir()."/public".$path);
return $response;
}
$categories =[
'dashboard',
'custom_graphics',
'custom_colors',
'custom_colors_degrade',
'custom_fonts',
'custom_fonts_custom',
'custom_fontSize',
'custom_crops',
'custom_shape',
'custom_files',
'navbar',
'menu',
'content_management',
'footer',
'internal_page',
'modules_txtAdmin',
'modules_slider',
'modules_parallax',
'modules_pushForward',
'modules_bouton',
'modules_title',
'modules_event',
'modules_news',
'modules_partenair',
'modules_faq',
'modules_form',
'modules_socialNetwork',
'modules_maps',
'modules_newsletter',
'modules_counter',
'modules_cover',
'modules_notif',
'modules_photo',
'modules_photoLibrary',
'modules_video',
'modules_videoLibrary',
'modules_cloud',
'modules_pdfViewer',
'modules_sound',
'modules_trustpilot',
'modules_securedHoliday',
'modules_googleAdsense',
'modules_iframe',
'setting',
'setting_link',
'setting_legal',
'setting_ext',
'setting_langue',
'setting_security',
'customer',
'administrator',
'customer_group',
'customer_settings',
];
return $this->render('artemis/esyweb/tuto.twig',[
'tutos' => $esyWebTutoRepository->findAll(),
'categories' => $categories
]);
}
#[Route(path: '/artemis/esyweb/tuto/{type}', name: 'artemis_esyweb_tuto_view', methods: ['GET', 'POST'])]
public function tutoView(string $type,Request $request,EsyWebTutoRepository $esyWebTutoRepository,EntityManagerInterface $entityManager,LoggerService $loggerService)
{
$tutos = $esyWebTutoRepository->findBy(['type' => $type,'typeFile'=>'pdf'],['pos'=>'asc']);
$videos = $esyWebTutoRepository->findBy(['type' => $type,'typeFile'=>'video'],['pos'=>'asc']);
if($request->query->has('idDelete')) {
$v = $esyWebTutoRepository->find($request->query->get('idDelete'));
$entityManager->remove($v);
$entityManager->flush();
$loggerService->log('DELETE',"Suppression effectuée");
$this->addFlash('success','Suppression effectuée');
return $this->redirectToRoute('artemis_esyweb_tuto_view',['type'=>$type]);
}
$tuto = new EsyWebTuto();
$tuto->setType($type);
$form = $this->createForm(TutoType::class,$tuto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if($tuto->getFile()->getMimeType() == "application/pdf"){
$tuto->setTypeFile("pdf");
$tuto->setPos($esyWebTutoRepository->count(['type' => $type,'typeFile'=>'pdf']));
} else {
$tuto->setTypeFile("video");
$tuto->setPos($esyWebTutoRepository->count(['type' => $type,'typeFile'=>'video']));
}
$tuto->setUpdateAt(new \DateTimeImmutable());
$entityManager->persist($tuto);
$entityManager->flush();
$loggerService->log('ADD','Ajout tutoriels');
return $this->redirectToRoute('artemis_esyweb_tuto_view',['type'=>$type]);
}
return $this->render('artemis/esyweb/tuto_view.twig',[
'tutoPdf' => $tutos,
'tutoVideos' => $videos,
'type' => $type,
'form' => $form->createView()
]);
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\Account;
use App\Entity\AccountResetPasswordRequest;
use App\Form\RequestPasswordConfirmType;
use App\Form\RequestPasswordRequestType;
use App\Service\Mailer\Mailer;
use App\Service\ResetPassword\Event\ResetPasswordConfirmEvent;
use App\Service\ResetPassword\Event\ResetPasswordEvent;
use Doctrine\ORM\EntityManagerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Twig\Environment;
class TutoController extends AbstractController
{
#[Route(path: '/tuto',name: 'app_tuto',methods: ['GET', 'POST'])]
public function tuto(): Response
{
}
}

View File

@@ -40,6 +40,12 @@ class EsyWebTuto
#[ORM\Column]
private ?int $pos = null;
#[ORM\Column(length: 255)]
private ?string $type = null;
#[ORM\Column(length: 255)]
private ?string $typeFile = null;
public function getId(): ?int
{
return $this->id;
@@ -180,4 +186,28 @@ class EsyWebTuto
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
public function getTypeFile(): ?string
{
return $this->typeFile;
}
public function setTypeFile(string $typeFile): static
{
$this->typeFile = $typeFile;
return $this;
}
}

View File

@@ -19,9 +19,9 @@ class TutoType extends AbstractType
'required' => true,
])
->add('file',FileType::class,[
'label' => 'Fichier du tutoriel (mp4)',
'label' => 'Fichier du tutoriel (mp4 pdf)',
'attr' => [
'accept' => 'video/mp4'
'accept' => 'video/mp4, .pdf'
]
]);

View File

@@ -4,38 +4,20 @@
{% block content %}
<div class="flex justify-between items-center mb-6">
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Liste des tutoriels</h2>
<div>
<a href="{{ path('artemis_esyweb_tuto_add') }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
+ Crée un tutoriel
</a>
<a target="_blank" href="{{ path('app_tuto') }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
Voir la page des tutoriels
</a>
</div>
</div>
<div class="mt-2 w-full mx-auto bg-gray-800 rounded-lg shadow-lg overflow-x-auto">
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
{% for categorie in categories %}
<div class="p-6 bg-gray-800 rounded-2xl shadow-xl border border-gray-700">
<div class="flex items-center space-x-4">
<div>
<h2 class="text-xl font-semibold text-white">{{ categorie|trans }}</h2>
</div>
</div>
<div class="mt-6 flex justify-end">
<a href="{{ path('artemis_esyweb_tuto_view',{type:categorie}) }}" class="px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-xl hover:bg-indigo-700">Voir les tutoriels</a>
</div>
</div>
{% endfor %}
<table class="min-w-full divide-y divide-gray-700">
<thead class="bg-gray-700">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Titre</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-700">
{% for tuto in tutos %}
<tr class="hover:bg-gray-700 transition relative hover:bg-gray-700 transition">
<td class="px-6 py-4 text-center text-sm w-80">{{ tuto.title }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-center w-20">
<a href="{{ path('artemis_esyweb_tuto',{idView:tuto.id}) }}" target="_blank"
class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Voir</a>
<a data-turbo="false" is="confirm-modal" type="delete-esyweb-tuto"
href="{{ path('artemis_esyweb_tuto',{idDelete:tuto.id}) }}"
class="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded">Supprimer</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

View File

@@ -0,0 +1,56 @@
{% extends 'artemis/base.twig' %}
{% block title %}Tutoriel(s){% endblock %}
{% block content %}
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<h2 class="text-xl font-semibold mb-4">Vidéos</h2>
<ul class="divide-y divide-gray-300 dark:divide-gray-700 rounded border border-gray-300 dark:border-gray-700">
{% for video in tutoVideos %}
<li class="flex items-center justify-between px-4 py-3 hover:bg-gray-200 dark:hover:bg-gray-700 transition">
<a class="text-blue-500 hover:underline truncate" href="{{ vich_uploader_asset(video,'file') }}" target="_blank" title="{{ video.title }}">
{{ video.title }}
</a>
<form data-turbo="false" method="post" action="{{ path('artemis_esyweb_tuto_view', {'idDelete': video.id,type:type}) }}" onsubmit="return confirm('Confirmer la suppression ?');">
<button type="submit" class="ml-4 px-3 py-1 text-white bg-red-600 hover:bg-red-700 rounded text-sm font-semibold transition">
Supprimer
</button>
</form>
</li>
{% else %}
<li class="px-4 py-3 text-gray-500">Aucune vidéo disponible.</li>
{% endfor %}
</ul>
</div>
<div class="md:w-1/2">
<h2 class="text-xl font-semibold mb-4">PDFs</h2>
<ul class="divide-y divide-gray-300 dark:divide-gray-700 rounded border border-gray-300 dark:border-gray-700">
{% for pdf in tutoPdf %}
<li class="flex items-center justify-between px-4 py-3 hover:bg-gray-200 dark:hover:bg-gray-700 transition">
<a class="text-blue-500 hover:underline truncate" href="{{ vich_uploader_asset(pdf,'file') }}" target="_blank" title="{{ pdf.title }}">
{{ pdf.title }}
</a>
<form data-turbo="false" method="post" action="{{ path('artemis_esyweb_tuto_view', {'idDelete': pdf.id,type:type}) }}" onsubmit="return confirm('Confirmer la suppression ?');">
<button type="submit" class="ml-4 px-3 py-1 text-white bg-red-600 hover:bg-red-700 rounded text-sm font-semibold transition">
Supprimer
</button>
</form>
</li>
{% else %}
<li class="px-4 py-3 text-gray-500">Aucun PDF disponible.</li>
{% endfor %}
</ul>
</div>
</div>
<div class="mt-10 p-6 bg-gray-100 dark:bg-gray-800 rounded-lg shadow w-full">
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.file) }}
<button type="submit"
class="px-6 py-2 bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 text-white rounded transition font-semibold mt-2">
Upload
</button>
{{ form_end(form) }}
</div>
{% endblock %}