diff --git a/assets/images/project_not_found.jpg b/assets/images/project_not_found.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65bfcbf0ba70ae5d9fa17f1a4820d582845ce217 Binary files /dev/null and b/assets/images/project_not_found.jpg differ diff --git a/src/Controller/CapsuleController.php b/src/Controller/CapsuleController.php index 039087a3d5f81f33da31b630c650cd968b005a61..dbf0c440a63e0778bbef6ccd949dd8609eb4f226 100644 --- a/src/Controller/CapsuleController.php +++ b/src/Controller/CapsuleController.php @@ -22,10 +22,14 @@ use Symfony\Contracts\Translation\TranslatorInterface; class CapsuleController extends AbstractController { + private CapsuleRepository $capsule_repository; private TranslatorInterface $translator; - public function __construct(TranslatorInterface $translator) - { + public function __construct( + CapsuleRepository $capsule_repository, + TranslatorInterface $translator + ) { + $this->capsule_repository = $capsule_repository; $this->translator = $translator; } @@ -94,7 +98,7 @@ class CapsuleController extends AbstractController { $file_path = '../legacy/' . $path; if (!file_exists($file_path)) { - return $this->render('capsule/capsule_not_found.html.twig'); + return $this->render('project/project_not_found.html.twig'); } $url = $this->getParameter('app.legacy_external_prefix') . '/' . $path . "/?w=1"; @@ -108,7 +112,7 @@ class CapsuleController extends AbstractController /** * @Route("capsule/edit/{path}", name="edit_capsule") */ - public function edit(string $path, CapsuleRepository $capsuleRepository, TranslatorInterface $translator): Response + public function edit(string $path): Response { $current_user = $this->getUser(); @@ -116,21 +120,20 @@ class CapsuleController extends AbstractController return $this->redirectToRoute('app_logout'); } - $capsule = $capsuleRepository->findOneBy(['link_path' => $path]); - + $capsule = $this->capsule_repository->findOneBy(['link_path' => $path]); if (null === $capsule) { - $this->addFlash('warning', $translator->trans('capsule.edit.not_found')); + $this->addFlash('warning', $this->translator->trans('capsule.edit.not_found')); return $this->redirectToRoute('capsule_list'); } if (! $capsule->getEditors()->contains($current_user)) { - $this->addFlash('warning', $translator->trans('capsule.edit.not_allowed')); + $this->addFlash('warning', $this->translator->trans('capsule.edit.not_allowed')); return $this->redirectToRoute('capsule_list'); } $file_path = '../legacy/' . $path; if (!file_exists($file_path)) { - return $this->render('capsule/capsule_not_found.html.twig'); + return $this->render('project/project_not_found.html.twig'); } $url = $this->getParameter('app.legacy_external_prefix') . '/' . $capsule->getEditionLink(); diff --git a/src/Entity/Capsule.php b/src/Entity/Capsule.php index 4e5249f4215ec05acdd33bcf933604fc6bf5bdaa..08ff123ce5e6625d0200dfc0cfdd0a2760e4d94f 100644 --- a/src/Entity/Capsule.php +++ b/src/Entity/Capsule.php @@ -3,10 +3,12 @@ namespace App\Entity; use App\Entity\User; +use App\Retriever\ProjectRetriever; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Security\Core\User\UserInterface; /** @@ -209,4 +211,24 @@ class Capsule { return $this->editors; } + + + public function getVideoPreviewImageLink(): ?string + { + $file_system = new Filesystem(); + + if (! $file_system->exists('../legacy/' . $this->getLinkPath())) { + return null; + } + + $project_retriever = new ProjectRetriever($this); + $video_url = $project_retriever->getVideoUrl(); + $video_id = $project_retriever->getVideoId($video_url); + + if (strpos($video_url, 'yout') !== false) { + return 'https://img.youtube.com/vi/' . $video_id . '/maxresdefault.jpg'; + } + + return 'https://vumbnail.com/' . $video_id . '.jpg'; + } } diff --git a/src/Retriever/ProjectRetriever.php b/src/Retriever/ProjectRetriever.php new file mode 100644 index 0000000000000000000000000000000000000000..28e70537f7783401cd249e1b3e1a79b7c522b1e5 --- /dev/null +++ b/src/Retriever/ProjectRetriever.php @@ -0,0 +1,71 @@ +<?php + +namespace App\Retriever; + +use App\Entity\Capsule; + +class ProjectRetriever +{ + private Capsule $capsule; + + public function __construct(Capsule $capsule) + { + $this->capsule = $capsule; + } + + private static function getDomDocument(): \DOMDocument + { + chdir('../legacy/'); + + $dom_xml = new \DOMDocument(); + $dom_xml->preserveWhiteSpace = false; + return $dom_xml; + } + + public function getVideoUrl(): string + { + $dom_xml = self::getDomDocument(); + + $dom_xml->load($this->capsule->getLinkPath() . '/file/project.xml'); + $video_node = $dom_xml->getElementsByTagName('video')->item(0); + + if ($video_node === null) { + throw new \Exception("Video node could not be found in XML project file"); + } + + return $video_node->getAttribute('url'); + } + + public function getVideoId(string $video_url): string + { + if (strpos($video_url, "vimeo")) { + return $this->getVimeoVideoIdFromUrl($video_url); + } + return $this->getYoutubeVideoIdFromUrl($video_url); + } + + private function getYoutubeVideoIdFromUrl(string $video_url): string + { + $pattern = "#(?<=v=|v\/|vi=|vi\/|youtu.be\/)[a-zA-Z0-9_-]{11}#"; + $result = preg_match($pattern, $video_url, $matches); + + $video_id = ""; + + if (false !== $result) { + $video_id = $matches[0]; + } + + return $video_id; + } + + private function getVimeoVideoIdFromUrl(string $video_url): string + { + $video_id = ""; + $pattern = "/https?:\/\/(?:www\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|)(\d+)(?:$|\/|\?)/"; //phpcs:ignore + + if (preg_match($pattern, $video_url, $id)) { + $video_id = $id[3]; + } + return $video_id; + } +} diff --git a/templates/capsule/capsule_not_found.html.twig b/templates/capsule/capsule_not_found.html.twig deleted file mode 100644 index 8a1484e9239e7201d119404934760ae0005bae8a..0000000000000000000000000000000000000000 --- a/templates/capsule/capsule_not_found.html.twig +++ /dev/null @@ -1,28 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <meta charset="UTF-8"> - <title>{% block title %}MemoRekall{% endblock %}</title> - - {% block stylesheets %} - {{ encore_entry_link_tags('app') }} - {% endblock %} - - {% block javascripts %} - {{ encore_entry_script_tags('app') }} - {% endblock %} - - <link rel="icon" type="image/x-icon" href="{{ asset('build/images/favicon.ico') }}" /> - -</head> - -<body class="container col-10 col-md-8 col-lg-6 m-auto"> - <div class="position-relative d-flex flex-row align-items-center justify-content-center mb-5"> - <img id="header-memorekall-logo" class="memorekall-logo" src="{{ asset('build/images/MemoRekall.png') }}"> - </div> - <div class="m-auto d-flex flex-row align-items-center justify-content-center mb-5 alert alert-warning" role="status"> - <span class="p-5">{{ 'capsule.not_found' | trans }}</span> - </div> - -</body> -</html> diff --git a/templates/capsule/index.html.twig b/templates/capsule/index.html.twig index f12717ee5238959b9032b5fd571041eb9a115c1d..24c3d22ac50d87f75ee65a19e0f80327b8b69087 100644 --- a/templates/capsule/index.html.twig +++ b/templates/capsule/index.html.twig @@ -54,17 +54,17 @@ </div> </div> - <div class="d-flex flex-column flex-md-row justify-content-center align-items-center"> - <div class="m-4 ratio ratio-16x9"> - <iframe - src="/capsule/preview/{{ capsule.getLinkPath() }}" - allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" - allowfullscreen> - </iframe> - </div> + <div class="d-flex flex-column flex-md-row justify-content-center align-items-center"> + <div class="m-4 ratio ratio-16x9"> + {% if capsule.getVideoPreviewImageLink() is null %} + <img src="{{ asset('build/images/project_not_found.jpg') }}" alt="video preview"> + {% else %} + <img src="{{ capsule.getVideoPreviewImageLink() }}" alt="video preview"> + {% endif %} + </div> - <div class="d-flex flex-column justify-content-center m-2 pe-2"> - <i class="fa-thin fa-gears"></i> + <div class="d-flex flex-column justify-content-center m-2 pe-2"> + <i class="fa-thin fa-gears"></i> <div class="list-item text-nowrap"> <a href="/capsule/{{ capsule.getId() }}/editors" class="links text-decoration-none"> diff --git a/templates/project/project_not_found.html.twig b/templates/project/project_not_found.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..05a7eba826a994468a07e77d0ead33934138e4c0 --- /dev/null +++ b/templates/project/project_not_found.html.twig @@ -0,0 +1,13 @@ +{% extends 'layout.html.twig' %} + +{% block title %} + {{ 'project.not_exist'|trans }} + - + {{ parent() }} +{% endblock %} + +{% block body %} + <div class="col-10 col-md-8 col-lg-6 col-xl-5 col-xxl-6 m-auto d-flex flex-row align-items-center justify-content-center mb-5 alert alert-warning" role="status"> + <span class="p-5">{{ 'project.not_exist' | trans }}</span> + </div> +{% endblock %} \ No newline at end of file diff --git a/tests/functional/CapsuleControllerTest.php b/tests/functional/CapsuleControllerTest.php index 96c813689e90cac2d62731df13d7defe7f4e2ce2..2282b8c4d4b3835cdc135f744c64f8ca4cf71a11 100644 --- a/tests/functional/CapsuleControllerTest.php +++ b/tests/functional/CapsuleControllerTest.php @@ -45,7 +45,7 @@ class CapsuleControllerTest extends WebTestCase $submit_button = $crawler->selectButton('Create a capsule'); $form = $submit_button->form(); - $video_url = "https://TestUrl"; + $video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"; $form['create_capsule_form[name]'] = self::CAPSULE_NAME; $form['create_capsule_form[video_url]'] = $video_url; diff --git a/tests/functional/ProjectControllerTest.php b/tests/functional/ProjectControllerTest.php index 04168284371b13473a79b8586e269c4c3c1bcf16..7db3e685f9b301063081f5f4ad7000b24f91192f 100644 --- a/tests/functional/ProjectControllerTest.php +++ b/tests/functional/ProjectControllerTest.php @@ -86,7 +86,7 @@ class ProjectControllerTest extends WebTestCase $submit_button = $crawler->selectButton('Create a capsule'); $this->form = $submit_button->form(); - $video_url = "https://TestUrl"; + $video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"; $this->form['create_capsule_form[name]'] = self::CAPSULE_NAME; $this->form['create_capsule_form[video_url]'] = $video_url; @@ -123,7 +123,7 @@ class ProjectControllerTest extends WebTestCase $video_url_in_xml_file = $video_node->getAttribute('url'); - $this->assertEquals($video_url, $video_url_in_xml_file); + $this->assertEquals($video_url, htmlspecialchars_decode($video_url_in_xml_file)); $this->assertSame(self::CAPSULE_NAME, $capsule_name_in_db); } @@ -293,7 +293,7 @@ class ProjectControllerTest extends WebTestCase $submit_button = $crawler->selectButton('Create a capsule'); $this->form = $submit_button->form(); - $video_url = "https://TestUrl"; + $video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"; $this->form['create_capsule_form[name]'] = self::CAPSULE_NAME; $this->form['create_capsule_form[video_url]'] = $video_url; diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index dca9f64e3b542dc44664919219c6ea725cb0c09b..ad0f150076247179414da7228ca4caec93ae8a1b 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -113,47 +113,4 @@ user: change_password: Change password updated_success: The password has been updated edit_profile: Edit my profile - edit_password: Edit my password - -editors: - title: Editors - title_name: Editors of capsule %capsule_name% - add_email_address: Add new editor with email address - current_editors_title: Current editors - pending_editors_title: Pending editors - user_not_editor_error: You are not editor of the capsule - add: - pending_editor: - success: The user user_email has been added to pending editor list. - He will receive an email to invite him register on MemoRekall and to inform him he has been added as an editor of this capsule. - already_added: The user user_email has already been added to pending editor list - email: - title: Invitation to edit a MemoRekall capsule - text: You have been added by %user_name% as editor of the capsule "%capsule_name%". - In order to access and edit it, you first need to register on MemoRekall. Please follow this link to - link: https://project.memorekall.com/register/ - link_name: register - user: - success: The user user_email is now an editor of the capsule capsule_name. - He will receive an email to inform him he has been added as an editor of this capsule. - already_added: The user user_email is already an editor of this capsule - email: - title: New capsule on your list - text: You have been add by %user_name% as editor of the capsule "%capsule_name%". - You can now access and edit it. You will find the capsule in your capsule list. - link: Go to capsule edition page - remove: - button: Remove - pending_editor: - title: Remove pending editor - text: Do you really want to delete pending editor %editor_email%? - link: Remove pending editor - error: The email address has already been removed from pending editors of the capsule capsule_name - success: The email address pending_editor_email has been successfully removed from pending editors of the capsule capsule_name - editor: - title: Remove editor - text: Do you really want to delete editor %editor_email%? - link: Remove editor - success: User editor_email is no longer and editor of the capsule capsule_name - error: You can't remove yourself as editor of your own capsule. - If you want to remove the capsule from your list, go to the capsule list page and click on "delete capsule" \ No newline at end of file + edit_password: Edit my password \ No newline at end of file diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index a6502ad168de0a1998946982b5345b0e7fe95e2b..f9bee5fd65ef2b32435672c1bf5662a50ea9087a 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -62,6 +62,7 @@ capsule: created_success: La capsule capsule_name a été créée no_edition_access: Pas d'accès au mode édition contact_capsule_author_for_access: Veuillez contacter l'auteur de la capsule pour lui demander son accès en mode édition + not_found: Le projet n'existe pas edit_permissions: link: Modifier les permissions edit: