diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index 19c06ac839..d985ae8e64 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -65,175 +65,175 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; return call_user_func(function($environment = null) { - $app = new PhraseaApplication($environment); + $app = new PhraseaApplication($environment); - $app->before(function () use ($app) { - $app['firewall']->requireSetup(); - }); + $app->before(function () use ($app) { + $app['firewall']->requireSetup(); + }); - $app->before(function(Request $request) use ($app) { - if ($request->cookies->has('persistent') && !$app->isAuthenticated()) { - try { - $auth = new \Session_Authentication_PersistentCookie($app, $request->cookies->get('persistent')); - $app->openAccount($auth, $auth->getSessionId()); - } catch (\Exception $e) { + $app->before(function(Request $request) use ($app) { + if ($request->cookies->has('persistent') && !$app->isAuthenticated()) { + try { + $auth = new \Session_Authentication_PersistentCookie($app, $request->cookies->get('persistent')); + $app->openAccount($auth, $auth->getSessionId()); + } catch (\Exception $e) { - } } - }); + } + }); - $app->get('/', function(PhraseaApplication $app) { - if ($app['browser']->isMobile()) { - return $app->redirect("/login/?redirect=lightbox"); - } elseif ($app['browser']->isNewGeneration()) { - return $app->redirect("/login/?redirect=prod"); + $app->get('/', function(PhraseaApplication $app) { + if ($app['browser']->isMobile()) { + return $app->redirect("/login/?redirect=lightbox"); + } elseif ($app['browser']->isNewGeneration()) { + return $app->redirect("/login/?redirect=prod"); + } else { + return $app->redirect("/login/?redirect=client"); + } + }); + + $app->get('/robots.txt', function(PhraseaApplication $app) { + + if ($app['phraseanet.registry']->get('GV_allow_search_engine') === true) { + $buffer = "User-Agent: *\n" . "Allow: /\n"; + } else { + $buffer = "User-Agent: *\n" . "Disallow: /\n"; + } + + return new Response($buffer, 200, array('Content-Type' => 'text/plain')); + })->bind('robots'); + + $app->mount('/feeds/', new RSSFeeds()); + $app->mount('/account/', new Account()); + $app->mount('/login/', new Login()); + $app->mount('/developers/', new Developers()); + $app->mount('/lightbox/', new Lightbox()); + + $app->mount('/datafiles/', new Datafiles()); + $app->mount('/permalink/', new Permalink()); + + $app->mount('/admin/', new Root()); + $app->mount('/admin/dashboard', new Dashboard()); + $app->mount('/admin/collection', new Collection()); + $app->mount('/admin/databox', new Databox()); + $app->mount('/admin/databoxes', new Databoxes()); + $app->mount('/admin/setup', new Setup()); + $app->mount('/admin/sphinx', new Sphinx()); + $app->mount('/admin/connected-users', new ConnectedUsers()); + $app->mount('/admin/publications', new Publications()); + $app->mount('/admin/users', new Users()); + $app->mount('/admin/fields', new Fields()); + $app->mount('/admin/task-manager', new TaskManager()); + $app->mount('/admin/subdefs', new Subdefs()); + $app->mount('/admin/description', new Description()); + $app->mount('/admin/tests/connection', new ConnectionTest()); + $app->mount('/admin/tests/pathurl', new PathFileTest()); + + $app->mount('/prod/query/', new Query()); + $app->mount('/prod/order/', new Order()); + $app->mount('/prod/baskets', new Basket()); + $app->mount('/prod/story', new Story()); + $app->mount('/prod/WorkZone', new WorkZone()); + $app->mount('/prod/lists', new UsrLists()); + $app->mount('/prod/MustacheLoader', new MustacheLoader()); + $app->mount('/prod/records/edit', new Edit()); + $app->mount('/prod/records/property', new Property()); + $app->mount('/prod/records/movecollection', new MoveCollection()); + $app->mount('/prod/bridge/', new Bridge()); + $app->mount('/prod/push/', new Push()); + $app->mount('/prod/printer/', new Printer()); + $app->mount('/prod/share/', new Share()); + $app->mount('/prod/export/', new Export()); + $app->mount('/prod/TOU/', new TOU()); + $app->mount('/prod/feeds', new Feed()); + $app->mount('/prod/tooltip', new Tooltip()); + $app->mount('/prod/language', new Language()); + $app->mount('/prod/tools/', new Tools()); + $app->mount('/prod/lazaret/', new Lazaret()); + $app->mount('/prod/upload/', new Upload()); + $app->mount('/prod/share/', new Share()); + $app->mount('/prod/', new Prod()); + + $app->mount('/user/preferences/', new Preferences()); + $app->mount('/user/notifications/', new Notifications()); + + $app->error(function(\Exception $e) use ($app) { + $request = $app['request']; + + if ($e instanceof \Bridge_Exception) { + $params = array( + 'message' => $e->getMessage() + , 'file' => $e->getFile() + , 'line' => $e->getLine() + , 'r_method' => $request->getMethod() + , 'r_action' => $request->getRequestUri() + , 'r_parameters' => ($request->getMethod() == 'GET' ? array() : $request->request->all()) + ); + + if ($e instanceof \Bridge_Exception_ApiConnectorNotConfigured) { + $params = array_merge($params, array('account' => $app['current_account'])); + + $response = new Response($app['twig']->render('/prod/actions/Bridge/notconfigured.html.twig', $params), 200, array('X-Status-Code' => 200)); + } elseif ($e instanceof \Bridge_Exception_ApiConnectorNotConnected) { + $params = array_merge($params, array('account' => $app['current_account'])); + + $response = new Response($app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); + } elseif ($e instanceof \Bridge_Exception_ApiConnectorAccessTokenFailed) { + $params = array_merge($params, array('account' => $app['current_account'])); + + $response = new Response($app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); + } elseif ($e instanceof \Bridge_Exception_ApiDisabled) { + $params = array_merge($params, array('api' => $e->get_api())); + + $response = new Response($app['twig']->render('/prod/actions/Bridge/deactivated.html.twig', $params), 200, array('X-Status-Code' => 200)); } else { - return $app->redirect("/login/?redirect=client"); - } - }); - - $app->get('/robots.txt', function(PhraseaApplication $app) { - - if ($app['phraseanet.registry']->get('GV_allow_search_engine') === true) { - $buffer = "User-Agent: *\n" . "Allow: /\n"; - } else { - $buffer = "User-Agent: *\n" . "Disallow: /\n"; + $response = new Response($app['twig']->render('/prod/actions/Bridge/error.html.twig', $params), 200, array('X-Status-Code' => 200)); } - return new Response($buffer, 200, array('Content-Type' => 'text/plain')); - })->bind('robots'); + $response->headers->set('Phrasea-StatusCode', 200); - $app->mount('/feeds/', new RSSFeeds()); - $app->mount('/account/', new Account()); - $app->mount('/login/', new Login()); - $app->mount('/developers/', new Developers()); - $app->mount('/lightbox/', new Lightbox()); + return $response; + } - $app->mount('/datafiles/', new Datafiles()); - $app->mount('/permalink/', new Permalink()); + if ($request->getRequestFormat() == 'json') { + $datas = array( + 'success' => false + , 'message' => $e->getMessage() + ); - $app->mount('/admin/', new Root()); - $app->mount('/admin/dashboard', new Dashboard()); - $app->mount('/admin/collection', new Collection()); - $app->mount('/admin/databox', new Databox()); - $app->mount('/admin/databoxes', new Databoxes()); - $app->mount('/admin/setup', new Setup()); - $app->mount('/admin/sphinx', new Sphinx()); - $app->mount('/admin/connected-users', new ConnectedUsers()); - $app->mount('/admin/publications', new Publications()); - $app->mount('/admin/users', new Users()); - $app->mount('/admin/fields', new Fields()); - $app->mount('/admin/task-manager', new TaskManager()); - $app->mount('/admin/subdefs', new Subdefs()); - $app->mount('/admin/description', new Description()); - $app->mount('/admin/tests/connection', new ConnectionTest()); - $app->mount('/admin/tests/pathurl', new PathFileTest()); + return $app->json($datas, 200, array('X-Status-Code' => 200)); + } - $app->mount('/prod/query/', new Query()); - $app->mount('/prod/order/', new Order()); - $app->mount('/prod/baskets', new Basket()); - $app->mount('/prod/story', new Story()); - $app->mount('/prod/WorkZone', new WorkZone()); - $app->mount('/prod/lists', new UsrLists()); - $app->mount('/prod/MustacheLoader', new MustacheLoader()); - $app->mount('/prod/records/edit', new Edit()); - $app->mount('/prod/records/property', new Property()); - $app->mount('/prod/records/movecollection', new MoveCollection()); - $app->mount('/prod/bridge/', new Bridge()); - $app->mount('/prod/push/', new Push()); - $app->mount('/prod/printer/', new Printer()); - $app->mount('/prod/share/', new Share()); - $app->mount('/prod/export/', new Export()); - $app->mount('/prod/TOU/', new TOU()); - $app->mount('/prod/feeds', new Feed()); - $app->mount('/prod/tooltip', new Tooltip()); - $app->mount('/prod/language', new Language()); - $app->mount('/prod/tools/', new Tools()); - $app->mount('/prod/lazaret/', new Lazaret()); - $app->mount('/prod/upload/', new Upload()); - $app->mount('/prod/share/', new Share()); - $app->mount('/prod/', new Prod()); + if ($e instanceof HttpExceptionInterface) { + $headers = $e->getHeaders(); - $app->mount('/user/preferences/', new Preferences()); - $app->mount('/user/notifications/', new Notifications()); - - $app->error(function(\Exception $e) use ($app) { - $request = $app['request']; - - if ($e instanceof \Bridge_Exception) { - $params = array( - 'message' => $e->getMessage() - , 'file' => $e->getFile() - , 'line' => $e->getLine() - , 'r_method' => $request->getMethod() - , 'r_action' => $request->getRequestUri() - , 'r_parameters' => ($request->getMethod() == 'GET' ? array() : $request->request->all()) - ); - - if ($e instanceof \Bridge_Exception_ApiConnectorNotConfigured) { - $params = array_merge($params, array('account' => $app['current_account'])); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/notconfigured.html.twig', $params), 200, array('X-Status-Code' => 200)); - } elseif ($e instanceof \Bridge_Exception_ApiConnectorNotConnected) { - $params = array_merge($params, array('account' => $app['current_account'])); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); - } elseif ($e instanceof \Bridge_Exception_ApiConnectorAccessTokenFailed) { - $params = array_merge($params, array('account' => $app['current_account'])); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); - } elseif ($e instanceof \Bridge_Exception_ApiDisabled) { - $params = array_merge($params, array('api' => $e->get_api())); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/deactivated.html.twig', $params), 200, array('X-Status-Code' => 200)); - } else { - $response = new Response($app['twig']->render('/prod/actions/Bridge/error.html.twig', $params), 200, array('X-Status-Code' => 200)); - } - - $response->headers->set('Phrasea-StatusCode', 200); - - return $response; + if (isset($headers['X-Phraseanet-Redirect'])) { + return new RedirectResponse($headers['X-Phraseanet-Redirect'], 302, array('X-Status-Code' => 302)); } + } - if ($request->getRequestFormat() == 'json') { - $datas = array( - 'success' => false - , 'message' => $e->getMessage() - ); + if ($e instanceof \Exception_BadRequest) { + return new Response('Bad Request', 400, array('X-Status-Code' => 400)); + } + if ($e instanceof \Exception_Forbidden) { + return new Response('Forbidden', 403, array('X-Status-Code' => 403)); + } - return $app->json($datas, 200, array('X-Status-Code' => 200)); - } + if ($e instanceof \Exception_Session_NotAuthenticated) { + $code = 403; + $message = 'Forbidden'; + } elseif ($e instanceof \Exception_NotAllowed) { + $code = 403; + $message = 'Forbidden'; + } elseif ($e instanceof \Exception_NotFound) { + $code = 404; + $message = 'Not Found'; + } else { + throw $e; + } - if ($e instanceof HttpExceptionInterface) { - $headers = $e->getHeaders(); + return new Response($message, $code, array('X-Status-Code' => $code)); + }); - if (isset($headers['X-Phraseanet-Redirect'])) { - return new RedirectResponse($headers['X-Phraseanet-Redirect'], 302, array('X-Status-Code' => 302)); - } - } - - if ($e instanceof \Exception_BadRequest) { - return new Response('Bad Request', 400, array('X-Status-Code' => 400)); - } - if ($e instanceof \Exception_Forbidden) { - return new Response('Forbidden', 403, array('X-Status-Code' => 403)); - } - - if ($e instanceof \Exception_Session_NotAuthenticated) { - $code = 403; - $message = 'Forbidden'; - } elseif ($e instanceof \Exception_NotAllowed) { - $code = 403; - $message = 'Forbidden'; - } elseif ($e instanceof \Exception_NotFound) { - $code = 404; - $message = 'Not Found'; - } else { - throw $e; - } - - return new Response($message, $code, array('X-Status-Code' => $code)); - }); - - return $app; - }, isset($environment) ? $environment : null); + return $app; +}, isset($environment) ? $environment : null); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Export.php b/lib/Alchemy/Phrasea/Controller/Prod/Export.php index 5ab679fd20..530b8b685d 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Export.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Export.php @@ -200,7 +200,7 @@ class Export implements ControllerProviderInterface return $app->json(array( 'success' => false, - 'message' => _('Something went wrong') . $e->getMessage() + 'message' => _('Something went wrong') )); } } @@ -219,11 +219,14 @@ class Export implements ControllerProviderInterface session_write_close(); ignore_user_abort(true); + $lst = $request->request->get('lst', ''); + $ssttid = $request->request->get('ssttid', ''); + //prepare export - $download = new \set_export($app, $request->get('lst', ''), $request->get('ssttid', '')); - $list = $download->prepare_export($app['phraseanet.user'], $app['filesystem'], $request->get('obj'), $request->get("type") == "title" ? : false, $request->get('businessfields')); + $download = new \set_export($app, $lst, $ssttid); + $list = $download->prepare_export($app['phraseanet.user'], $app['filesystem'], $request->request->get('obj'), $request->request->get("type") == "title" ? : false, $request->request->get('businessfields')); $list['export_name'] = sprintf("%s.zip", $download->getExportName()); - $list['email'] = $request->get("destmail", ""); + $list['email'] = $request->request->get("destmail", ""); $destMails = array(); //get destination mails @@ -233,8 +236,8 @@ class Export implements ControllerProviderInterface } else { $app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', array( 'usr_id' => $app['phraseanet.user']->get_id(), - 'lst' => $request->get('lst', ''), - 'ssttid' => $request->get('ssttid', ''), + 'lst' => $lst, + 'ssttid' => $ssttid, 'dest' => $mail, 'reason' => \eventsmanager_notify_downloadmailfail::MAIL_NO_VALID )); @@ -260,7 +263,7 @@ class Export implements ControllerProviderInterface //send mails foreach ($destMails as $key => $mail) { - if (\mail::send_documents($app, trim($mail), $url, $from, $endDateObject, $request->get('textmail'), $request->get('reading_confirm') == '1' ? : false)) { + if (\mail::send_documents($app, trim($mail), $url, $from, $endDateObject, $request->request->get('textmail'), $request->request->get('reading_confirm') == '1' ? : false)) { unset($remaingEmails[$key]); } } @@ -270,8 +273,8 @@ class Export implements ControllerProviderInterface foreach ($remaingEmails as $mail) { $app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', array( 'usr_id' => $app['phraseanet.user']->get_id(), - 'lst' => $request->get('lst', ''), - 'ssttid' => $request->get('ssttid', ''), + 'lst' => $lst, + 'ssttid' => $ssttid, 'dest' => $mail, 'reason' => \eventsmanager_notify_downloadmailfail::MAIL_FAIL )); @@ -281,8 +284,8 @@ class Export implements ControllerProviderInterface foreach ($destMails as $mail) { $app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', array( 'usr_id' => $app['phraseanet.user']->get_id(), - 'lst' => $request->get('lst', ''), - 'ssttid' => $request->get('ssttid', ''), + 'lst' => $lst, + 'ssttid' => $ssttid, 'dest' => $mail, 'reason' => 0 )); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Query.php b/lib/Alchemy/Phrasea/Controller/Prod/Query.php index 9155a8cbe7..97464cf85e 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Query.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Query.php @@ -101,7 +101,7 @@ class Query implements ControllerProviderInterface $options = new \searchEngine_options(); - $bas = is_array($request->request->get('bas')) ? $request->request->get('bas') : array_keys($user->ACL()->get_granted_base()); + $bas = is_array($request->request->get('bas')) ? $request->request->get('bas') : array_keys($app['phraseanet.user']->ACL()->get_granted_base()); if ($app['phraseanet.user']->ACL()->has_right('modifyrecord')) { $options->set_business_fields(array()); @@ -279,7 +279,7 @@ class Query implements ControllerProviderInterface $searchEngine->set_options($options); } - $pos = $request->request->get('pos'); + $pos = (int) $request->request->get('pos'); $query = $request->request->get('query', ''); $record = new \record_preview($app, 'RESULT', $pos, '', '', $searchEngine, $query); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php b/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php index 8669f14da8..d536553f89 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php @@ -34,10 +34,7 @@ class Property implements ControllerProviderInterface $controllers = $app['controllers_factory']; $controllers->before(function(Request $request) use ($app) { - $response = $app['firewall']->requireNotGuest(); - if ($response instanceof Response) { - return $response; - } + $app['firewall']->requireNotGuest(); }); /** diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Records.php b/lib/Alchemy/Phrasea/Controller/Prod/Records.php new file mode 100644 index 0000000000..ad2e4ced10 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Prod/Records.php @@ -0,0 +1,182 @@ +before(function(Request $request) use ($app) { + $response = $app['firewall']->requireNotGuest(); + if ($response instanceof Response) { + return $response; + } + }); + + /** + * Delete a record or a list of records + * + * name : record_delete + * + * description : Delete a record or a list of records + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/', $this->call('deleteRecord')) + ->bind('record_delete'); + + /** + * Verify if I can delete records + * + * name : record_what_can_i_delete + * + * description : Save CSS preferences + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->get('/', $this->call('whatCanIDelete')) + ->bind('record_what_can_i_delete'); + + /** + * Renew a record URL + * + * name : record_renew_url + * + * description : Renew a record URL + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/renew-url/', $this->call('renewUrl')) + ->bind('record_renew_url'); + + return $controllers; + } + + /** + * Delete a record or a list of records + * + * @param Application $app + * @param Request $request + * @return HtmlResponse + */ + public function deleteRecord(Application $app, Request $request) + { + $records = RecordsRequest::fromRequest($app, $request, !!$app->request->get('del_children'), array( + 'candeleterecord' + )); + + $basketElementsRepository = $app['EM']->getRepository('\Entities\BasketElement'); + $deleted = array(); + + foreach ($records as $record) { + try { + $basketElements = $basketElementsRepository->findElementsByRecord($record); + + foreach ($basketElements as $element) { + $app['EM']->remove($element); + $deleted[] = $element->getRecord($app)->get_serialize_key(); + } + + $record->delete(); + $deleted[] = $record->get_serialize_key(); + } catch (\Exception $e) { + + } + } + + $app['EM']->flush(); + + return $app->json($deleted); + } + + /** + * Delete a record or a list of records + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function whatICanDelete(Application $app, Request $request) + { + $records = RecordsRequest::fromRequest($app, $request, !!$app->request->get('del_children'), array( + 'candeleterecord' + )); + + return $app['twig']->render('prod/actions/delete_records_confirm.html.twig', array( + 'lst' => explode(';', $records->serializedList()), + 'groupings' => $records->stories()->count(), + )); + } + + /** + * Renew url list of records + * + * @param Application $app + * @param Request $request + * @param integer $databox_id + * @param integer $record_id + * @return JsonResponse + */ + public function renewUrl(Application $app, Request $request) + { + $records = RecordsRequest::fromRequest($app, $request, !!$app->request->get('renew_children_url')); + + $renewed = array(); + foreach ($records as $record) { + $renewed[] = array( + $record->get_serialized_key() => $record->get_preview()->renew_url(), + ); + }; + + return $app->json($renewed); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/Alchemy/Phrasea/Controller/User/Notifications.php b/lib/Alchemy/Phrasea/Controller/User/Notifications.php index 4fce2b5a37..923b337612 100644 --- a/lib/Alchemy/Phrasea/Controller/User/Notifications.php +++ b/lib/Alchemy/Phrasea/Controller/User/Notifications.php @@ -82,12 +82,12 @@ class Notifications implements ControllerProviderInterface if (!$request->isXmlHttpRequest()) { $app->abort(400); } - + try { $app['events-manager']->read(explode('_', (string) $request->request->get('notifications')), $app['phraseanet.user']->get_id()); return $app->json(array('success' => true, 'message' => '')); - } catch (Exception $e) { + } catch (\Exception $e) { return $app->json(array('success' => false, 'message' => $e->getMessage())); } diff --git a/lib/Alchemy/Phrasea/Controller/User/Preferences.php b/lib/Alchemy/Phrasea/Controller/User/Preferences.php index f98efbfd9d..f3ec8371d4 100644 --- a/lib/Alchemy/Phrasea/Controller/User/Preferences.php +++ b/lib/Alchemy/Phrasea/Controller/User/Preferences.php @@ -16,11 +16,6 @@ use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\JsonResponse; -/** - * - * @license http://opensource.org/licenses/gpl-3.0 GPLv3 - * @link www.phraseanet.com - */ class Preferences implements ControllerProviderInterface { @@ -85,13 +80,15 @@ class Preferences implements ControllerProviderInterface $prop = $request->request->get('prop'); $value = $request->request->get('value'); $success = false; + $msg = _('Error while saving preference'); if ($prop && $value) { $app['session']->set('pref.' . $prop, $value); $success = true; + $msg = _('Preference saved !'); } - return new JsonResponse(array('success' => $success)); + return new JsonResponse(array('success' => $success, 'message' => $msg)); } /** diff --git a/templates/web/prod/Share/record.html.twig b/templates/web/prod/Share/record.html.twig index 9442eb2744..72c0f988bc 100644 --- a/templates/web/prod/Share/record.html.twig +++ b/templates/web/prod/Share/record.html.twig @@ -1,79 +1,76 @@ {% set preview = record.get_preview()%} -{% set permalink = preview.get_permalink() %} {% if preview is iterable %}
{% trans 'No preview available.' %}
-{% elseif permalink is none %} +{% elseif preview.get_permalink() is none %}{% trans 'No permalink available.' %}
{% else %} {% set type = record.get_type() %} - {% set url = permalink.get_url() %} -