aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/CoreBundle
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag/CoreBundle')
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php16
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php4
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php14
-rw-r--r--src/Wallabag/CoreBundle/Controller/TagController.php5
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/Configuration.php2
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php1
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php6
-rw-r--r--src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php5
-rw-r--r--src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php9
-rw-r--r--src/Wallabag/CoreBundle/Helper/ContentProxy.php74
-rw-r--r--src/Wallabag/CoreBundle/Helper/DownloadImages.php9
-rw-r--r--src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php5
-rw-r--r--src/Wallabag/CoreBundle/Helper/Redirect.php10
-rw-r--r--src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php1
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig40
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig4
17 files changed, 115 insertions, 91 deletions
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index 0d9364f6..d9608246 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -499,20 +499,18 @@ class InstallCommand extends ContainerAwareCommand
499 $output = new BufferedOutput(); 499 $output = new BufferedOutput();
500 $exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output); 500 $exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output);
501 501
502 // PDO does not always close the connection after Doctrine commands.
503 // See https://github.com/symfony/symfony/issues/11750.
504 $this->getContainer()->get('doctrine')->getManager()->getConnection()->close();
505
502 if (0 !== $exitCode) { 506 if (0 !== $exitCode) {
503 $this->getApplication()->setAutoExit(true); 507 $this->getApplication()->setAutoExit(true);
504 508
505 $this->defaultOutput->writeln(''); 509 throw new \RuntimeException(
506 $this->defaultOutput->writeln('<error>The command "'.$command.'" generates some errors: </error>'); 510 'The command "'.$command."\" generates some errors: \n\n"
507 $this->defaultOutput->writeln($output->fetch()); 511 .$output->fetch());
508
509 die();
510 } 512 }
511 513
512 // PDO does not always close the connection after Doctrine commands.
513 // See https://github.com/symfony/symfony/issues/11750.
514 $this->getContainer()->get('doctrine')->getManager()->getConnection()->close();
515
516 return $this; 514 return $this;
517 } 515 }
518 516
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
index 1a80cc1a..0e61c642 100644
--- a/src/Wallabag/CoreBundle/Controller/ConfigController.php
+++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php
@@ -250,7 +250,7 @@ class ConfigController extends Controller
250 case 'entries': 250 case 'entries':
251 // SQLite doesn't care about cascading remove, so we need to manually remove associated stuff 251 // SQLite doesn't care about cascading remove, so we need to manually remove associated stuff
252 // otherwise they won't be removed ... 252 // otherwise they won't be removed ...
253 if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) { 253 if ($this->get('doctrine')->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
254 $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId()); 254 $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId());
255 } 255 }
256 256
@@ -262,7 +262,7 @@ class ConfigController extends Controller
262 ->removeAllByUserId($this->getUser()->getId()); 262 ->removeAllByUserId($this->getUser()->getId());
263 break; 263 break;
264 case 'archived': 264 case 'archived':
265 if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) { 265 if ($this->get('doctrine')->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
266 $this->removeAnnotationsForArchivedByUserId($this->getUser()->getId()); 266 $this->removeAnnotationsForArchivedByUserId($this->getUser()->getId());
267 } 267 }
268 268
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index 8d2ac6d4..fafa49f1 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -53,22 +53,17 @@ class EntryController extends Controller
53 53
54 /** 54 /**
55 * Fetch content and update entry. 55 * Fetch content and update entry.
56 * In case it fails, entry will return to avod loosing the data. 56 * In case it fails, $entry->getContent will return an error message.
57 * 57 *
58 * @param Entry $entry 58 * @param Entry $entry
59 * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded 59 * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded
60 *
61 * @return Entry
62 */ 60 */
63 private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') 61 private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved')
64 { 62 {
65 // put default title in case of fetching content failed
66 $entry->setTitle('No title found');
67
68 $message = 'flashes.entry.notice.'.$prefixMessage; 63 $message = 'flashes.entry.notice.'.$prefixMessage;
69 64
70 try { 65 try {
71 $entry = $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); 66 $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
72 } catch (\Exception $e) { 67 } catch (\Exception $e) {
73 $this->get('logger')->error('Error while saving an entry', [ 68 $this->get('logger')->error('Error while saving an entry', [
74 'exception' => $e, 69 'exception' => $e,
@@ -79,8 +74,6 @@ class EntryController extends Controller
79 } 74 }
80 75
81 $this->get('session')->getFlashBag()->add('notice', $message); 76 $this->get('session')->getFlashBag()->add('notice', $message);
82
83 return $entry;
84 } 77 }
85 78
86 /** 79 /**
@@ -321,8 +314,7 @@ class EntryController extends Controller
321 314
322 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); 315 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
323 316
324 $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries') 317 $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')->prepare($pagerAdapter);
325 ->prepare($pagerAdapter, $page);
326 318
327 try { 319 try {
328 $entries->setCurrentPage($page); 320 $entries->setCurrentPage($page);
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php
index fb6a720b..9422bae4 100644
--- a/src/Wallabag/CoreBundle/Controller/TagController.php
+++ b/src/Wallabag/CoreBundle/Controller/TagController.php
@@ -70,7 +70,7 @@ class TagController extends Controller
70 $em->flush(); 70 $em->flush();
71 } 71 }
72 72
73 $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer')); 73 $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'), '', true);
74 74
75 return $this->redirect($redirectUrl); 75 return $this->redirect($redirectUrl);
76 } 76 }
@@ -125,8 +125,7 @@ class TagController extends Controller
125 125
126 $pagerAdapter = new ArrayAdapter($entriesByTag); 126 $pagerAdapter = new ArrayAdapter($entriesByTag);
127 127
128 $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries') 128 $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')->prepare($pagerAdapter);
129 ->prepare($pagerAdapter, $page);
130 129
131 try { 130 try {
132 $entries->setCurrentPage($page); 131 $entries->setCurrentPage($page);
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
index 75b37729..8b5b5744 100644
--- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
+++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
@@ -41,6 +41,8 @@ class Configuration implements ConfigurationInterface
41 ->end() 41 ->end()
42 ->scalarNode('fetching_error_message') 42 ->scalarNode('fetching_error_message')
43 ->end() 43 ->end()
44 ->scalarNode('fetching_error_message_title')
45 ->end()
44 ->scalarNode('action_mark_as_read') 46 ->scalarNode('action_mark_as_read')
45 ->defaultValue(1) 47 ->defaultValue(1)
46 ->end() 48 ->end()
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
index c075c19f..a2a703cb 100644
--- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
+++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
@@ -26,6 +26,7 @@ class WallabagCoreExtension extends Extension
26 $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']); 26 $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']);
27 $container->setParameter('wallabag_core.list_mode', $config['list_mode']); 27 $container->setParameter('wallabag_core.list_mode', $config['list_mode']);
28 $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']); 28 $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']);
29 $container->setParameter('wallabag_core.fetching_error_message_title', $config['fetching_error_message_title']);
29 $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']); 30 $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']);
30 31
31 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 32 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index 08a67c34..9a7dd4e7 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -550,7 +550,7 @@ class Entry
550 } 550 }
551 551
552 /** 552 /**
553 * @return ArrayCollection<Tag> 553 * @return ArrayCollection
554 */ 554 */
555 public function getTags() 555 public function getTags()
556 { 556 {
@@ -685,7 +685,7 @@ class Entry
685 } 685 }
686 686
687 /** 687 /**
688 * @return int 688 * @return string
689 */ 689 */
690 public function getHttpStatus() 690 public function getHttpStatus()
691 { 691 {
@@ -693,7 +693,7 @@ class Entry
693 } 693 }
694 694
695 /** 695 /**
696 * @param int $httpStatus 696 * @param string $httpStatus
697 * 697 *
698 * @return Entry 698 * @return Entry
699 */ 699 */
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php
index 3b4c4cf9..5e6af8cc 100644
--- a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php
+++ b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php
@@ -45,9 +45,8 @@ class SQLiteCascadeDeleteSubscriber implements EventSubscriber
45 public function preRemove(LifecycleEventArgs $args) 45 public function preRemove(LifecycleEventArgs $args)
46 { 46 {
47 $entity = $args->getEntity(); 47 $entity = $args->getEntity();
48 48 if (!$this->doctrine->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform
49 if (!$this->doctrine->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver || 49 || !$entity instanceof Entry) {
50 !$entity instanceof Entry) {
51 return; 50 return;
52 } 51 }
53 52
diff --git a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
index c712bb26..1c56fa9f 100644
--- a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
+++ b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
@@ -5,7 +5,6 @@ namespace Wallabag\CoreBundle\GuzzleSiteAuthenticator;
5use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig; 5use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig;
6use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder; 6use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder;
7use Graby\SiteConfig\ConfigBuilder; 7use Graby\SiteConfig\ConfigBuilder;
8use OutOfRangeException;
9use Psr\Log\LoggerInterface; 8use Psr\Log\LoggerInterface;
10 9
11class GrabySiteConfigBuilder implements SiteConfigBuilder 10class GrabySiteConfigBuilder implements SiteConfigBuilder
@@ -38,13 +37,7 @@ class GrabySiteConfigBuilder implements SiteConfigBuilder
38 } 37 }
39 38
40 /** 39 /**
41 * Builds the SiteConfig for a host. 40 * {@inheritdoc}
42 *
43 * @param string $host The "www." prefix is ignored
44 *
45 * @return SiteConfig
46 *
47 * @throws OutOfRangeException If there is no config for $host
48 */ 41 */
49 public function buildForHost($host) 42 public function buildForHost($host)
50 { 43 {
diff --git a/src/Wallabag/CoreBundle/Helper/ContentProxy.php b/src/Wallabag/CoreBundle/Helper/ContentProxy.php
index 4b3e6fbb..bfaa1976 100644
--- a/src/Wallabag/CoreBundle/Helper/ContentProxy.php
+++ b/src/Wallabag/CoreBundle/Helper/ContentProxy.php
@@ -31,22 +31,20 @@ class ContentProxy
31 } 31 }
32 32
33 /** 33 /**
34 * Fetch content using graby and hydrate given entry with results information. 34 * Update entry using either fetched or provided content.
35 * In case we couldn't find content, we'll try to use Open Graph data.
36 * 35 *
37 * We can also force the content, in case of an import from the v1 for example, so the function won't 36 * @param Entry $entry Entry to update
38 * fetch the content from the website but rather use information given with the $content parameter. 37 * @param string $url Url of the content
39 * 38 * @param array $content Array with content provided for import with AT LEAST keys title, html, url to skip the fetchContent from the url
40 * @param Entry $entry Entry to update 39 * @param bool $disableContentUpdate Whether to skip trying to fetch content using Graby
41 * @param string $url Url to grab content for
42 * @param array $content An array with AT LEAST keys title, html, url, language & content_type to skip the fetchContent from the url
43 *
44 * @return Entry
45 */ 40 */
46 public function updateEntry(Entry $entry, $url, array $content = []) 41 public function updateEntry(Entry $entry, $url, array $content = [], $disableContentUpdate = false)
47 { 42 {
48 // do we have to fetch the content or the provided one is ok? 43 if (!empty($content['html'])) {
49 if (empty($content) || false === $this->validateContent($content)) { 44 $content['html'] = $this->graby->cleanupHtml($content['html'], $url);
45 }
46
47 if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) {
50 $fetchedContent = $this->graby->fetchContent($url); 48 $fetchedContent = $this->graby->fetchContent($url);
51 49
52 // when content is imported, we have information in $content 50 // when content is imported, we have information in $content
@@ -56,8 +54,24 @@ class ContentProxy
56 } 54 }
57 } 55 }
58 56
57 // be sure to keep the url in case of error
58 // so we'll be able to refetch it in the future
59 $content['url'] = !empty($content['url']) ? $content['url'] : $url;
60
61 $this->stockEntry($entry, $content);
62 }
63
64 /**
65 * Stock entry with fetched or imported content.
66 * Will fall back to OpenGraph data if available.
67 *
68 * @param Entry $entry Entry to stock
69 * @param array $content Array with at least title, url & html
70 */
71 private function stockEntry(Entry $entry, array $content)
72 {
59 $title = $content['title']; 73 $title = $content['title'];
60 if (!$title && isset($content['open_graph']['og_title'])) { 74 if (!$title && !empty($content['open_graph']['og_title'])) {
61 $title = $content['open_graph']['og_title']; 75 $title = $content['open_graph']['og_title'];
62 } 76 }
63 77
@@ -65,19 +79,30 @@ class ContentProxy
65 if (false === $html) { 79 if (false === $html) {
66 $html = $this->fetchingErrorMessage; 80 $html = $this->fetchingErrorMessage;
67 81
68 if (isset($content['open_graph']['og_description'])) { 82 if (!empty($content['open_graph']['og_description'])) {
69 $html .= '<p><i>But we found a short description: </i></p>'; 83 $html .= '<p><i>But we found a short description: </i></p>';
70 $html .= $content['open_graph']['og_description']; 84 $html .= $content['open_graph']['og_description'];
71 } 85 }
72 } 86 }
73 87
74 $entry->setUrl($content['url'] ?: $url); 88 $entry->setUrl($content['url']);
75 $entry->setTitle($title); 89 $entry->setTitle($title);
76 $entry->setContent($html); 90 $entry->setContent($html);
77 $entry->setHttpStatus(isset($content['status']) ? $content['status'] : ''); 91 $entry->setHttpStatus(isset($content['status']) ? $content['status'] : '');
78 92
79 if (isset($content['date']) && null !== $content['date'] && '' !== $content['date']) { 93 if (!empty($content['date'])) {
80 $entry->setPublishedAt(new \DateTime($content['date'])); 94 $date = $content['date'];
95
96 // is it a timestamp?
97 if (filter_var($date, FILTER_VALIDATE_INT) !== false) {
98 $date = '@'.$content['date'];
99 }
100
101 try {
102 $entry->setPublishedAt(new \DateTime($date));
103 } catch (\Exception $e) {
104 $this->logger->warning('Error while defining date', ['e' => $e, 'url' => $content['url'], 'date' => $content['date']]);
105 }
81 } 106 }
82 107
83 if (!empty($content['authors'])) { 108 if (!empty($content['authors'])) {
@@ -97,12 +122,12 @@ class ContentProxy
97 $entry->setDomainName($domainName); 122 $entry->setDomainName($domainName);
98 } 123 }
99 124
100 if (isset($content['open_graph']['og_image']) && $content['open_graph']['og_image']) { 125 if (!empty($content['open_graph']['og_image'])) {
101 $entry->setPreviewPicture($content['open_graph']['og_image']); 126 $entry->setPreviewPicture($content['open_graph']['og_image']);
102 } 127 }
103 128
104 // if content is an image define as a preview too 129 // if content is an image define as a preview too
105 if (isset($content['content_type']) && in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) { 130 if (!empty($content['content_type']) && in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) {
106 $entry->setPreviewPicture($content['url']); 131 $entry->setPreviewPicture($content['url']);
107 } 132 }
108 133
@@ -110,17 +135,14 @@ class ContentProxy
110 $this->tagger->tag($entry); 135 $this->tagger->tag($entry);
111 } catch (\Exception $e) { 136 } catch (\Exception $e) {
112 $this->logger->error('Error while trying to automatically tag an entry.', [ 137 $this->logger->error('Error while trying to automatically tag an entry.', [
113 'entry_url' => $url, 138 'entry_url' => $content['url'],
114 'error_msg' => $e->getMessage(), 139 'error_msg' => $e->getMessage(),
115 ]); 140 ]);
116 } 141 }
117
118 return $entry;
119 } 142 }
120 143
121 /** 144 /**
122 * Validate that the given content as enough value to be used 145 * Validate that the given content has at least a title, an html and a url.
123 * instead of fetch the content from the url.
124 * 146 *
125 * @param array $content 147 * @param array $content
126 * 148 *
@@ -128,6 +150,6 @@ class ContentProxy
128 */ 150 */
129 private function validateContent(array $content) 151 private function validateContent(array $content)
130 { 152 {
131 return isset($content['title']) && isset($content['html']) && isset($content['url']) && isset($content['language']) && isset($content['content_type']); 153 return !empty($content['title']) && !empty($content['html']) && !empty($content['url']);
132 } 154 }
133} 155}
diff --git a/src/Wallabag/CoreBundle/Helper/DownloadImages.php b/src/Wallabag/CoreBundle/Helper/DownloadImages.php
index 0d330d2a..54e23a05 100644
--- a/src/Wallabag/CoreBundle/Helper/DownloadImages.php
+++ b/src/Wallabag/CoreBundle/Helper/DownloadImages.php
@@ -54,7 +54,7 @@ class DownloadImages
54 $crawler = new Crawler($html); 54 $crawler = new Crawler($html);
55 $result = $crawler 55 $result = $crawler
56 ->filterXpath('//img') 56 ->filterXpath('//img')
57 ->extract(array('src')); 57 ->extract(['src']);
58 58
59 $relativePath = $this->getRelativePath($entryId); 59 $relativePath = $this->getRelativePath($entryId);
60 60
@@ -66,6 +66,11 @@ class DownloadImages
66 continue; 66 continue;
67 } 67 }
68 68
69 // if image contains "&" and we can't find it in the html it might be because it's encoded as &amp;
70 if (false !== stripos($image, '&') && false === stripos($html, $image)) {
71 $image = str_replace('&', '&amp;', $image);
72 }
73
69 $html = str_replace($image, $imagePath, $html); 74 $html = str_replace($image, $imagePath, $html);
70 } 75 }
71 76
@@ -114,7 +119,7 @@ class DownloadImages
114 $ext = $this->mimeGuesser->guess($res->getHeader('content-type')); 119 $ext = $this->mimeGuesser->guess($res->getHeader('content-type'));
115 $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); 120 $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]);
116 if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) { 121 if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) {
117 $this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping '.$imagePath); 122 $this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping: '.$imagePath);
118 123
119 return false; 124 return false;
120 } 125 }
diff --git a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
index 7d3798b9..df579ebd 100644
--- a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
+++ b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
@@ -20,16 +20,15 @@ class PreparePagerForEntries
20 20
21 /** 21 /**
22 * @param AdapterInterface $adapter 22 * @param AdapterInterface $adapter
23 * @param int $page
24 * 23 *
25 * @return null|Pagerfanta 24 * @return null|Pagerfanta
26 */ 25 */
27 public function prepare(AdapterInterface $adapter, $page = 1) 26 public function prepare(AdapterInterface $adapter)
28 { 27 {
29 $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; 28 $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
30 29
31 if (null === $user || !is_object($user)) { 30 if (null === $user || !is_object($user)) {
32 return null; 31 return;
33 } 32 }
34 33
35 $entries = new Pagerfanta($adapter); 34 $entries = new Pagerfanta($adapter);
diff --git a/src/Wallabag/CoreBundle/Helper/Redirect.php b/src/Wallabag/CoreBundle/Helper/Redirect.php
index f78b7fe0..abc84d08 100644
--- a/src/Wallabag/CoreBundle/Helper/Redirect.php
+++ b/src/Wallabag/CoreBundle/Helper/Redirect.php
@@ -21,12 +21,13 @@ class Redirect
21 } 21 }
22 22
23 /** 23 /**
24 * @param string $url URL to redirect 24 * @param string $url URL to redirect
25 * @param string $fallback Fallback URL if $url is null 25 * @param string $fallback Fallback URL if $url is null
26 * @param bool $ignoreActionMarkAsRead Ignore configured action when mark as read
26 * 27 *
27 * @return string 28 * @return string
28 */ 29 */
29 public function to($url, $fallback = '') 30 public function to($url, $fallback = '', $ignoreActionMarkAsRead = false)
30 { 31 {
31 $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; 32 $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
32 33
@@ -34,7 +35,8 @@ class Redirect
34 return $url; 35 return $url;
35 } 36 }
36 37
37 if (Config::REDIRECT_TO_HOMEPAGE === $user->getConfig()->getActionMarkAsRead()) { 38 if (!$ignoreActionMarkAsRead &&
39 Config::REDIRECT_TO_HOMEPAGE === $user->getConfig()->getActionMarkAsRead()) {
38 return $this->router->generate('homepage'); 40 return $this->router->generate('homepage');
39 } 41 }
40 42
diff --git a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php
index add27db2..509d0dec 100644
--- a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php
+++ b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php
@@ -15,6 +15,7 @@ class RuleBasedTagger
15 private $rulerz; 15 private $rulerz;
16 private $tagRepository; 16 private $tagRepository;
17 private $entryRepository; 17 private $entryRepository;
18 private $logger;
18 19
19 public function __construct(RulerZ $rulerz, TagRepository $tagRepository, EntryRepository $entryRepository, LoggerInterface $logger) 20 public function __construct(RulerZ $rulerz, TagRepository $tagRepository, EntryRepository $entryRepository, LoggerInterface $logger)
20 { 21 {
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index a68b2fdc..a9b0d2d5 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -41,6 +41,7 @@ services:
41 arguments: 41 arguments:
42 - 42 -
43 error_message: '%wallabag_core.fetching_error_message%' 43 error_message: '%wallabag_core.fetching_error_message%'
44 error_message_title: '%wallabag_core.fetching_error_message_title%'
44 - "@wallabag_core.guzzle.http_client" 45 - "@wallabag_core.guzzle.http_client"
45 - "@wallabag_core.graby.config_builder" 46 - "@wallabag_core.graby.config_builder"
46 calls: 47 calls:
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig
index 174b7b54..b64e1436 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig
@@ -1,18 +1,28 @@
1<div class="card"> 1<div class="card-stacked">
2 <div class="card-stacked"> 2 <div class="preview">{% if entry.previewPicture is not null %}<img src="{{ entry.previewPicture }}" />{% endif %}</div>
3 <div class="card-content"> 3 <div class="card-content">
4 <span class="card-title dot-ellipsis dot-resize-update"> 4 <span class="card-title dot-ellipsis dot-resize-update">
5 <a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title | striptags | e('html_attr') }}"> 5 <a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title | striptags | e('html_attr') }}">
6 {{ entry.title| striptags | truncate(120, true, '…') | raw }} 6 {{ entry.title| striptags | truncate(120, true, '…') | raw }}
7 </a> 7 </a>
8 </span> 8 </span>
9 <ul class="tools-list right"> 9
10 <li> 10 <div class="metadata">
11 <a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}redo{% endif %}</i></a> 11 <a href="{{ entry.url|e }}" class="grey-text domain" target="_blank" title="{{ entry.domainName|removeWww }}">
12 <a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool grey-text" href="{{ path('star_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isStarred == 0 %}star_border{% else %}star{% endif %}</i></a> 12 <span>{{ entry.domainName|removeWww }}</span>
13 <a title="{{ 'entry.list.delete'|trans }}" onclick="return confirm('{{ 'entry.confirm.delete'|trans|escape('js') }}')" class="tool grey-text delete" href="{{ path('delete_entry', { 'id': entry.id }) }}"><i class="material-icons">delete</i></a> 13 </a>
14 </li> 14 {% for tag in entry.tags | slice(0, 3) %}
15 </ul> 15 <span class="chip hide-on-med-and-down">
16 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a>
17 </span>
18 {% endfor %}
16 </div> 19 </div>
17 </div> 20 </div>
21 <ul class="tools-list hide-on-small-only">
22 <li>
23 <a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}redo{% endif %}</i></a>
24 <a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool grey-text" href="{{ path('star_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isStarred == 0 %}star_border{% else %}star{% endif %}</i></a>
25 <a title="{{ 'entry.list.delete'|trans }}" onclick="return confirm('{{ 'entry.confirm.delete'|trans|escape('js') }}')" class="tool grey-text delete" href="{{ path('delete_entry', { 'id': entry.id }) }}"><i class="material-icons">delete</i></a>
26 </li>
27 </ul>
18</div> 28</div>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
index b2d91c9c..6f657b18 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
@@ -24,9 +24,9 @@
24 </div> 24 </div>
25 25
26 <br /> 26 <br />
27 <ul class="row data"> 27 <ul class="{% if listMode == 1 %}collection{% else %}row data{% endif %}">
28 {% for entry in entries %} 28 {% for entry in entries %}
29 <li id="entry-{{ entry.id|e }}" class="col {% if listMode == 0 %}l3 m6{% endif %} s12"> 29 <li id="entry-{{ entry.id|e }}" class="col {% if listMode == 0 %}l3 m6{% else %}collection-item{% endif %} s12">
30 {% if listMode == 1 %} 30 {% if listMode == 1 %}
31 {% include "@WallabagCore/themes/material/Entry/_card_list.html.twig" with {'entry': entry} only %} 31 {% include "@WallabagCore/themes/material/Entry/_card_list.html.twig" with {'entry': entry} only %}
32 {% elseif entry.previewPicture is null %} 32 {% elseif entry.previewPicture is null %}