X-Git-Url: https://git.rapsys.eu/treebundle/blobdiff_plain/d3798da0c79794f2355b3002b36faf7e8e8fc95e..e7f0a62a00c056d3aacddb031e16cbe7a93eb1c4:/Controller/TreeController.php diff --git a/Controller/TreeController.php b/Controller/TreeController.php index 54bc44f..7c2a38f 100644 --- a/Controller/TreeController.php +++ b/Controller/TreeController.php @@ -17,7 +17,9 @@ use Psr\Container\ContainerInterface; use Rapsys\PackBundle\Util\FacebookUtil; use Rapsys\TreeBundle\Entity\Album; +use Rapsys\TreeBundle\Entity\Element; use Rapsys\TreeBundle\RapsysTreeBundle; +use Rapsys\UserBundle\RapsysUserBundle; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\SecurityBundle\Security; @@ -36,6 +38,11 @@ use Twig\Environment; * {@inheritdoc} */ class TreeController extends AbstractController { + /** + * Alias string + */ + protected string $alias; + /** * Config array */ @@ -92,7 +99,7 @@ class TreeController extends AbstractController { */ function __construct(protected AuthorizationCheckerInterface $checker, protected ContainerInterface $container, protected ManagerRegistry $doctrine, protected FacebookUtil $facebook, protected RouterInterface $router, protected Security $security, protected RequestStack $stack, protected TranslatorInterface $translator, protected Environment $twig, protected int $limit = 5) { //Retrieve config - $this->config = $container->getParameter(RapsysTreeBundle::getAlias()); + $this->config = $container->getParameter($this->alias = RapsysTreeBundle::getAlias()); //Get main request $this->request = $this->stack->getMainRequest(); @@ -183,6 +190,273 @@ class TreeController extends AbstractController { ]; } + /** + * The album page + * + * Display album + * + * @param Request $request The request instance + * @param int $id The album id + * @param string $path The album path + * @param string $slug The album slug + * @return Response The rendered view + */ + public function album(Request $request, int $id, string $path, string $slug): Response { + //Get user + $user = $this->security->getUser(); + + //Check admin role + if (!$this->checker->isGranted('ROLE_'.strtoupper($this->container->getParameter(RapsysUserBundle::getAlias().'.default.admin')))) { + //Throw access denied + //XXX: prevent slugger reverse engineering by not displaying decoded mail + throw $this->createAccessDeniedException($this->translator->trans('Unable to access album', [], $this->alias)); + } + + //Without album + if (!($this->context['album'] = $this->doctrine->getRepository(Album::class)->findOneByIdPathAsArray($id, $path))) { + //Throw 404 + throw $this->createNotFoundException($this->translator->trans('Unable to find album')); + } + + //With slug not matching + if ($this->context['album']['slug'] !== $slug) { + //Redirect on clean slug + return $this->redirectToRoute($this->route, [ 'slug' => $this->context['album']['slug'] ]+$this->routeParams); + } + + //Set modified + $this->modified = $this->context['album']['modified']; + + //Create response + $response = new Response(); + + //With logged user + if ($this->checker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { + //Set last modified + $response->setLastModified(new \DateTime('-1 year')); + + //Set as private + $response->setPrivate(); + //Without logged user + } else { + //Set etag + //XXX: only for public to force revalidation by last modified + $response->setEtag(md5(serialize($this->context['album']))); + + //Set last modified + $response->setLastModified($this->modified); + + //Set as public + $response->setPublic(); + + //Without role and modification + if ($response->isNotModified($request)) { + //Return 304 response + return $response; + } + } + + //Set keywords + /*$this->context['head']['keywords'] = implode( + ', ', + //Use closure to extract each unique article keywords sorted + (function ($t) { + //Return array + $r = []; + + //Iterate on articles + foreach($t as $a) { + //Non empty keywords + if (!empty($a['keywords'])) { + //Iterate on keywords + foreach($a['keywords'] as $k) { + //Set keyword + $r[$k['title']] = $k['title']; + } + } + } + + //Sort array + sort($r); + + //Return array + return $r; + })($this->context['articles']) + ); + //Get albums + $this->context['albums'] = $this->config['albums'];*/ + + //Return rendered response + return $this->render('@RapsysTree/album.html.twig', $this->context, $response); + } + + + /** + * The element page + * + * Display element + * + * @param Request $request The request instance + * @param int $id The element id + * @param ?string $path The element path + * @return Response The rendered view + */ + public function element(Request $request, int $id, string $path): Response { + //Get user + $user = $this->security->getUser(); + + //Without element + if (!($this->context['element'] = $this->doctrine->getRepository(Element::class)->findOneByUidIdPathAsArray($user?->getId(), $id, $path))) { + //Throw 404 + throw $this->createNotFoundException($this->translator->trans('Unable to find element')); + } + + //With realpath not matching path + //XXX: extra slashes removed by rewrite rule + if (($this->context['path'] = substr($this->context['element']['realpath'], strlen($this->context['element']['album']['path'])+1)) !== $path) { + //Redirect on clean path + return $this->redirectToRoute($this->route, [ 'path' => $this->context['path'] ]+$this->routeParams); + } + + //Set modified + $this->modified = $this->context['element']['modified']; + + //Create response + $response = new Response(); + + //With logged user + if ($this->checker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { + //Set last modified + $response->setLastModified(new \DateTime('-1 year')); + + //Set as private + $response->setPrivate(); + //Without logged user + } else { + //Set etag + //XXX: only for public to force revalidation by last modified + $response->setEtag(md5(serialize($this->context['element']))); + + //Set last modified + $response->setLastModified($this->modified); + + //Set as public + $response->setPublic(); + + //Without role and modification + if ($response->isNotModified($request)) { + //Return 304 response + return $response; + } + } + + //TODO: move that in a shared function to use in album member function too + + /* + //With directory + if (is_dir($realpath)) { + //Set element directories + $this->context['element'] += [ + //Directories + 'directories' => [], + //Files + 'files' => [] + ]; + + //Iterate on directory + foreach(array_diff(scandir($realpath), ['.', '..']) as $item) { + //Check item + if ( + //Without item realpath + !($itempath = realpath($realpath.'/'.$item)) || + //With item realpath not matching element path + ( + $this->context['element']['album']['path'].$this->context['element']['path'] !== + substr($itempath, 0, strlen($this->context['element']['album']['path'].$this->context['element']['path'])) + ) + ) { + //Skip + continue; + } + + //With directory + if (is_dir($itempath)) { + //Append directory + $this->context['element']['directories'][$item] = $this->router->generate($this->route, [ 'path' => $this->context['path'].'/'.$item ]+$this->routeParams); + //With file + } elseif (is_file($itempath)) { + //Append file + $this->context['element']['files'][$item] = [ + //Set mime + 'mime' => mime_content_type($itempath), + //Set size + 'size' => filesize($itempath), + //Set link + 'link' => $this->router->generate($this->route, [ 'path' => $this->context['path'].'/'.$item ]+$this->routeParams) + ]; + //With unknown type + } else { + //Throw 404 + throw $this->createNotFoundException($this->translator->trans('Unable to process element')); + } + } + //With file + } elseif (is_file($realpath)) { + //Append file + $this->context['element']['file'] = [ + //Set mime + 'mime' => mime_content_type($realpath), + //Set size + 'size' => filesize($realpath), + //TODO: extra fields ? (preview, miniature, etc ?) + ]; + //TODO: mimetype decided extra fields ? (.pdf for doc, webm preview, img preview, etc ?) + //TODO: XXX: finish this !!! + //With unknown type + } else { + //Throw 404 + throw $this->createNotFoundException($this->translator->trans('Unable to process element')); + } + */ + + //Set keywords + /*$this->context['head']['keywords'] = implode( + ', ', + //Use closure to extract each unique article keywords sorted + (function ($t) { + //Return array + $r = []; + + //Iterate on articles + foreach($t as $a) { + //Non empty keywords + if (!empty($a['keywords'])) { + //Iterate on keywords + foreach($a['keywords'] as $k) { + //Set keyword + $r[$k['title']] = $k['title']; + } + } + } + + //Sort array + sort($r); + + //Return array + return $r; + })($this->context['articles']) + ); + //Get albums + $this->context['albums'] = $this->config['albums'];*/ + + #header('Content-Type: text/plain'); + #var_dump($this->context['element']); + #exit; + + //Return rendered response + return $this->render('@RapsysTree/element.html.twig', $this->context, $response); + } + /** * The index page * @@ -196,13 +470,13 @@ class TreeController extends AbstractController { $user = $this->security->getUser(); //With not enough albums - if (($this->count = $this->doctrine->getRepository(Album::class)->findCountAsInt($user?->getId())) < $this->page * $this->limit) { + if (($this->count = $this->doctrine->getRepository(Album::class)->countByUidAsInt($user?->getId())) < $this->page * $this->limit) { //Throw 404 throw $this->createNotFoundException($this->translator->trans('Unable to find albums')); } //Get albums - if ($this->context['albums'] = $this->doctrine->getRepository(Album::class)->findAllAsArray($user?->getId(), $this->page, $this->limit)) { + if ($this->context['albums'] = $this->doctrine->getRepository(Album::class)->findByUidAsArray($user?->getId(), $this->page, $this->limit)) { //Set modified $this->modified = max(array_map(function ($v) { return $v['modified']; }, $this->context['albums'])); //Without albums @@ -211,10 +485,6 @@ class TreeController extends AbstractController { $this->modified = new \DateTime('-1 year'); } - /*header('Content-Type: text/plain'); - var_dump($this->context['albums']); - exit;*/ - //Create response $response = new Response();