aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Wallabag/ApiBundle/Controller/TagRestController.php22
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php197
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php43
-rw-r--r--src/Wallabag/CoreBundle/Helper/EntriesExport.php10
-rw-r--r--src/Wallabag/CoreBundle/Repository/TagRepository.php53
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig4
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig4
-rw-r--r--src/Wallabag/CoreBundle/Tools/Utils.php7
-rw-r--r--src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php7
-rw-r--r--src/Wallabag/ImportBundle/Import/AbstractImport.php17
-rw-r--r--src/Wallabag/ImportBundle/Import/BrowserImport.php4
-rw-r--r--src/Wallabag/ImportBundle/Import/ChromeImport.php12
-rw-r--r--src/Wallabag/ImportBundle/Import/FirefoxImport.php12
-rw-r--r--src/Wallabag/ImportBundle/Import/InstapaperImport.php12
-rw-r--r--src/Wallabag/ImportBundle/Import/PinboardImport.php12
-rw-r--r--src/Wallabag/ImportBundle/Import/PocketImport.php12
-rw-r--r--src/Wallabag/ImportBundle/Import/ReadabilityImport.php12
-rw-r--r--src/Wallabag/ImportBundle/Import/WallabagImport.php12
18 files changed, 293 insertions, 159 deletions
diff --git a/src/Wallabag/ApiBundle/Controller/TagRestController.php b/src/Wallabag/ApiBundle/Controller/TagRestController.php
index c6d6df6a..f3498f55 100644
--- a/src/Wallabag/ApiBundle/Controller/TagRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/TagRestController.php
@@ -46,12 +46,14 @@ class TagRestController extends WallabagRestController
46 $this->validateAuthentication(); 46 $this->validateAuthentication();
47 $label = $request->get('tag', ''); 47 $label = $request->get('tag', '');
48 48
49 $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label); 49 $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser([$label], $this->getUser()->getId());
50 50
51 if (empty($tag)) { 51 if (empty($tags)) {
52 throw $this->createNotFoundException('Tag not found'); 52 throw $this->createNotFoundException('Tag not found');
53 } 53 }
54 54
55 $tag = $tags[0];
56
55 $this->getDoctrine() 57 $this->getDoctrine()
56 ->getRepository('WallabagCoreBundle:Entry') 58 ->getRepository('WallabagCoreBundle:Entry')
57 ->removeTag($this->getUser()->getId(), $tag); 59 ->removeTag($this->getUser()->getId(), $tag);
@@ -80,15 +82,7 @@ class TagRestController extends WallabagRestController
80 82
81 $tagsLabels = $request->get('tags', ''); 83 $tagsLabels = $request->get('tags', '');
82 84
83 $tags = []; 85 $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser(explode(',', $tagsLabels), $this->getUser()->getId());
84
85 foreach (explode(',', $tagsLabels) as $tagLabel) {
86 $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel);
87
88 if (!empty($tagEntity)) {
89 $tags[] = $tagEntity;
90 }
91 }
92 86
93 if (empty($tags)) { 87 if (empty($tags)) {
94 throw $this->createNotFoundException('Tags not found'); 88 throw $this->createNotFoundException('Tags not found');
@@ -120,6 +114,12 @@ class TagRestController extends WallabagRestController
120 { 114 {
121 $this->validateAuthentication(); 115 $this->validateAuthentication();
122 116
117 $tagFromDb = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser([$tag->getLabel()], $this->getUser()->getId());
118
119 if (empty($tagFromDb)) {
120 throw $this->createNotFoundException('Tag not found');
121 }
122
123 $this->getDoctrine() 123 $this->getDoctrine()
124 ->getRepository('WallabagCoreBundle:Entry') 124 ->getRepository('WallabagCoreBundle:Entry')
125 ->removeTag($this->getUser()->getId(), $tag); 125 ->removeTag($this->getUser()->getId(), $tag);
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
index 0e1510a2..8e7a1d2a 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
@@ -14,97 +14,112 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
14 */ 14 */
15 public function load(ObjectManager $manager) 15 public function load(ObjectManager $manager)
16 { 16 {
17 $entry1 = new Entry($this->getReference('admin-user')); 17 $entries = [
18 $entry1->setUrl('http://0.0.0.0/entry1'); 18 'entry1' => [
19 $entry1->setReadingTime(11); 19 'user' => 'admin-user',
20 $entry1->setDomainName('domain.io'); 20 'url' => 'http://0.0.0.0/entry1',
21 $entry1->setMimetype('text/html'); 21 'reading_time' => 11,
22 $entry1->setTitle('test title entry1'); 22 'domain' => 'domain.io',
23 $entry1->setContent('This is my content /o/'); 23 'mime' => 'text/html',
24 $entry1->setLanguage('en'); 24 'title' => 'test title entry1',
25 25 'content' => 'This is my content /o/',
26 $entry1->addTag($this->getReference('foo-tag')); 26 'language' => 'en',
27 $entry1->addTag($this->getReference('baz-tag')); 27 'tags' => ['foo-tag', 'baz-tag'],
28 28 ],
29 $manager->persist($entry1); 29 'entry2' => [
30 30 'user' => 'admin-user',
31 $this->addReference('entry1', $entry1); 31 'url' => 'http://0.0.0.0/entry2',
32 32 'reading_time' => 1,
33 $entry2 = new Entry($this->getReference('admin-user')); 33 'domain' => 'domain.io',
34 $entry2->setUrl('http://0.0.0.0/entry2'); 34 'mime' => 'text/html',
35 $entry2->setReadingTime(1); 35 'title' => 'test title entry2',
36 $entry2->setDomainName('domain.io'); 36 'content' => 'This is my content /o/',
37 $entry2->setMimetype('text/html'); 37 'origin' => 'ftp://oneftp.tld',
38 $entry2->setTitle('test title entry2'); 38 'language' => 'fr',
39 $entry2->setContent('This is my content /o/'); 39 ],
40 $entry2->setOriginUrl('ftp://oneftp.tld'); 40 'entry3' => [
41 $entry2->setLanguage('fr'); 41 'user' => 'bob-user',
42 42 'url' => 'http://0.0.0.0/entry3',
43 $manager->persist($entry2); 43 'reading_time' => 1,
44 44 'domain' => 'domain.io',
45 $this->addReference('entry2', $entry2); 45 'mime' => 'text/html',
46 46 'title' => 'test title entry3',
47 $entry3 = new Entry($this->getReference('bob-user')); 47 'content' => 'This is my content /o/',
48 $entry3->setUrl('http://0.0.0.0/entry3'); 48 'language' => 'en',
49 $entry3->setReadingTime(1); 49 'tags' => ['foo-tag', 'bar-tag', 'bob-tag'],
50 $entry3->setDomainName('domain.io'); 50 ],
51 $entry3->setMimetype('text/html'); 51 'entry4' => [
52 $entry3->setTitle('test title entry3'); 52 'user' => 'admin-user',
53 $entry3->setContent('This is my content /o/'); 53 'url' => 'http://0.0.0.0/entry4',
54 $entry3->setLanguage('en'); 54 'reading_time' => 12,
55 55 'domain' => 'domain.io',
56 $entry3->addTag($this->getReference('foo-tag')); 56 'mime' => 'text/html',
57 $entry3->addTag($this->getReference('bar-tag')); 57 'title' => 'test title entry4',
58 58 'content' => 'This is my content /o/',
59 $manager->persist($entry3); 59 'language' => 'en',
60 60 'tags' => ['foo-tag', 'bar-tag'],
61 $this->addReference('entry3', $entry3); 61 ],
62 62 'entry5' => [
63 $entry4 = new Entry($this->getReference('admin-user')); 63 'user' => 'admin-user',
64 $entry4->setUrl('http://0.0.0.0/entry4'); 64 'url' => 'http://0.0.0.0/entry5',
65 $entry4->setReadingTime(12); 65 'reading_time' => 12,
66 $entry4->setDomainName('domain.io'); 66 'domain' => 'domain.io',
67 $entry4->setMimetype('text/html'); 67 'mime' => 'text/html',
68 $entry4->setTitle('test title entry4'); 68 'title' => 'test title entry5',
69 $entry4->setContent('This is my content /o/'); 69 'content' => 'This is my content /o/',
70 $entry4->setLanguage('en'); 70 'language' => 'fr',
71 71 'starred' => true,
72 $entry4->addTag($this->getReference('foo-tag')); 72 'preview' => 'http://0.0.0.0/image.jpg',
73 $entry4->addTag($this->getReference('bar-tag')); 73 ],
74 74 'entry6' => [
75 $manager->persist($entry4); 75 'user' => 'admin-user',
76 76 'url' => 'http://0.0.0.0/entry6',
77 $this->addReference('entry4', $entry4); 77 'reading_time' => 12,
78 78 'domain' => 'domain.io',
79 $entry5 = new Entry($this->getReference('admin-user')); 79 'mime' => 'text/html',
80 $entry5->setUrl('http://0.0.0.0/entry5'); 80 'title' => 'test title entry6',
81 $entry5->setReadingTime(12); 81 'content' => 'This is my content /o/',
82 $entry5->setDomainName('domain.io'); 82 'language' => 'de',
83 $entry5->setMimetype('text/html'); 83 'archived' => true,
84 $entry5->setTitle('test title entry5'); 84 'tags' => ['bar-tag'],
85 $entry5->setContent('This is my content /o/'); 85 ],
86 $entry5->setStarred(true); 86 ];
87 $entry5->setLanguage('fr'); 87
88 $entry5->setPreviewPicture('http://0.0.0.0/image.jpg'); 88 foreach ($entries as $reference => $item) {
89 89 $entry = new Entry($this->getReference($item['user']));
90 $manager->persist($entry5); 90 $entry->setUrl($item['url']);
91 91 $entry->setReadingTime($item['reading_time']);
92 $this->addReference('entry5', $entry5); 92 $entry->setDomainName($item['domain']);
93 93 $entry->setMimetype($item['mime']);
94 $entry6 = new Entry($this->getReference('admin-user')); 94 $entry->setTitle($item['title']);
95 $entry6->setUrl('http://0.0.0.0/entry6'); 95 $entry->setContent($item['content']);
96 $entry6->setReadingTime(12); 96 $entry->setLanguage($item['language']);
97 $entry6->setDomainName('domain.io'); 97
98 $entry6->setMimetype('text/html'); 98 if (isset($item['tags'])) {
99 $entry6->setTitle('test title entry6'); 99 foreach ($item['tags'] as $tag) {
100 $entry6->setContent('This is my content /o/'); 100 $entry->addTag($this->getReference($tag));
101 $entry6->setArchived(true); 101 }
102 $entry6->setLanguage('de'); 102 }
103 $entry6->addTag($this->getReference('bar-tag')); 103
104 104 if (isset($item['origin'])) {
105 $manager->persist($entry6); 105 $entry->setOriginUrl($item['origin']);
106 106 }
107 $this->addReference('entry6', $entry6); 107
108 if (isset($item['starred'])) {
109 $entry->setStarred($item['starred']);
110 }
111
112 if (isset($item['archived'])) {
113 $entry->setArchived($item['archived']);
114 }
115
116 if (isset($item['preview'])) {
117 $entry->setPreviewPicture($item['preview']);
118 }
119
120 $manager->persist($entry);
121 $this->addReference($reference, $entry);
122 }
108 123
109 $manager->flush(); 124 $manager->flush();
110 } 125 }
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
index 0ecfd18b..485445c1 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
@@ -14,33 +14,22 @@ class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
14 */ 14 */
15 public function load(ObjectManager $manager) 15 public function load(ObjectManager $manager)
16 { 16 {
17 $tag1 = new Tag(); 17 $tags = [
18 $tag1->setLabel('foo bar'); 18 'foo-bar-tag' => 'foo bar', //tag used for EntryControllerTest
19 19 'bar-tag' => 'bar',
20 $manager->persist($tag1); 20 'baz-tag' => 'baz', // tag used for ExportControllerTest
21 21 'foo-tag' => 'foo',
22 $this->addReference('foo-bar-tag', $tag1); 22 'bob-tag' => 'bob', // tag used for TagRestControllerTest
23 23 ];
24 $tag2 = new Tag(); 24
25 $tag2->setLabel('bar'); 25 foreach ($tags as $reference => $label) {
26 26 $tag = new Tag();
27 $manager->persist($tag2); 27 $tag->setLabel($label);
28 28
29 $this->addReference('bar-tag', $tag2); 29 $manager->persist($tag);
30 30
31 $tag3 = new Tag(); 31 $this->addReference($reference, $tag);
32 $tag3->setLabel('baz'); 32 }
33
34 $manager->persist($tag3);
35
36 $this->addReference('baz-tag', $tag3);
37
38 $tag4 = new Tag();
39 $tag4->setLabel('foo');
40
41 $manager->persist($tag4);
42
43 $this->addReference('foo-tag', $tag4);
44 33
45 $manager->flush(); 34 $manager->flush();
46 } 35 }
diff --git a/src/Wallabag/CoreBundle/Helper/EntriesExport.php b/src/Wallabag/CoreBundle/Helper/EntriesExport.php
index cbf1037b..6082f6b9 100644
--- a/src/Wallabag/CoreBundle/Helper/EntriesExport.php
+++ b/src/Wallabag/CoreBundle/Helper/EntriesExport.php
@@ -150,8 +150,6 @@ class EntriesExport
150 */ 150 */
151 151
152 $book->setTitle($this->title); 152 $book->setTitle($this->title);
153 // Could also be the ISBN number, prefered for published books, or a UUID.
154 $book->setIdentifier($this->title, EPub::IDENTIFIER_URI);
155 // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc. 153 // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc.
156 $book->setLanguage($this->language); 154 $book->setLanguage($this->language);
157 $book->setDescription('Some articles saved on my wallabag'); 155 $book->setDescription('Some articles saved on my wallabag');
@@ -174,6 +172,8 @@ class EntriesExport
174 $book->setCoverImage('Cover.png', file_get_contents($this->logoPath), 'image/png'); 172 $book->setCoverImage('Cover.png', file_get_contents($this->logoPath), 'image/png');
175 } 173 }
176 174
175 $entryIds = [];
176
177 /* 177 /*
178 * Adding actual entries 178 * Adding actual entries
179 */ 179 */
@@ -192,8 +192,14 @@ class EntriesExport
192 $book->addChapter('Title', 'Title.html', $titlepage, true, EPub::EXTERNAL_REF_ADD); 192 $book->addChapter('Title', 'Title.html', $titlepage, true, EPub::EXTERNAL_REF_ADD);
193 $chapter = $content_start . $entry->getContent() . $bookEnd; 193 $chapter = $content_start . $entry->getContent() . $bookEnd;
194 $book->addChapter($entry->getTitle(), htmlspecialchars($filename) . '.html', $chapter, true, EPub::EXTERNAL_REF_ADD); 194 $book->addChapter($entry->getTitle(), htmlspecialchars($filename) . '.html', $chapter, true, EPub::EXTERNAL_REF_ADD);
195
196 $entryIds[] = $entry->getId();
195 } 197 }
196 198
199 // Could also be the ISBN number, prefered for published books, or a UUID.
200 $hash = sha1(sprintf('%s:%s', $this->wallabagUrl, implode(',', $entryIds)));
201 $book->setIdentifier(sprintf('urn:wallabag:%s', $hash), EPub::IDENTIFIER_URI);
202
197 $book->buildTOC(); 203 $book->buildTOC();
198 204
199 return Response::create( 205 return Response::create(
diff --git a/src/Wallabag/CoreBundle/Repository/TagRepository.php b/src/Wallabag/CoreBundle/Repository/TagRepository.php
index 3ae9d414..8464a6a5 100644
--- a/src/Wallabag/CoreBundle/Repository/TagRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/TagRepository.php
@@ -3,6 +3,7 @@
3namespace Wallabag\CoreBundle\Repository; 3namespace Wallabag\CoreBundle\Repository;
4 4
5use Doctrine\ORM\EntityRepository; 5use Doctrine\ORM\EntityRepository;
6use Doctrine\ORM\QueryBuilder;
6use Wallabag\CoreBundle\Entity\Tag; 7use Wallabag\CoreBundle\Entity\Tag;
7 8
8class TagRepository extends EntityRepository 9class TagRepository extends EntityRepository
@@ -45,12 +46,8 @@ class TagRepository extends EntityRepository
45 */ 46 */
46 public function findAllTags($userId) 47 public function findAllTags($userId)
47 { 48 {
48 $ids = $this->createQueryBuilder('t') 49 $ids = $this->getQueryBuilderByUser($userId)
49 ->select('t.id') 50 ->select('t.id')
50 ->leftJoin('t.entries', 'e')
51 ->where('e.user = :userId')->setParameter('userId', $userId)
52 ->groupBy('t.id')
53 ->orderBy('t.slug')
54 ->getQuery() 51 ->getQuery()
55 ->getArrayResult(); 52 ->getArrayResult();
56 53
@@ -71,18 +68,30 @@ class TagRepository extends EntityRepository
71 */ 68 */
72 public function findAllFlatTagsWithNbEntries($userId) 69 public function findAllFlatTagsWithNbEntries($userId)
73 { 70 {
74 return $this->createQueryBuilder('t') 71 return $this->getQueryBuilderByUser($userId)
75 ->select('t.id, t.label, t.slug, count(e.id) as nbEntries') 72 ->select('t.id, t.label, t.slug, count(e.id) as nbEntries')
76 ->distinct(true) 73 ->distinct(true)
77 ->leftJoin('t.entries', 'e')
78 ->where('e.user = :userId')
79 ->groupBy('t.id')
80 ->orderBy('t.slug')
81 ->setParameter('userId', $userId)
82 ->getQuery() 74 ->getQuery()
83 ->getArrayResult(); 75 ->getArrayResult();
84 } 76 }
85 77
78 public function findByLabelsAndUser($labels, $userId)
79 {
80 $qb = $this->getQueryBuilderByUser($userId)
81 ->select('t.id');
82
83 $ids = $qb->andWhere($qb->expr()->in('t.label', $labels))
84 ->getQuery()
85 ->getArrayResult();
86
87 $tags = [];
88 foreach ($ids as $id) {
89 $tags[] = $this->find($id);
90 }
91
92 return $tags;
93 }
94
86 /** 95 /**
87 * Used only in test case to get a tag for our entry. 96 * Used only in test case to get a tag for our entry.
88 * 97 *
@@ -101,13 +110,9 @@ class TagRepository extends EntityRepository
101 110
102 public function findForArchivedArticlesByUser($userId) 111 public function findForArchivedArticlesByUser($userId)
103 { 112 {
104 $ids = $this->createQueryBuilder('t') 113 $ids = $this->getQueryBuilderByUser($userId)
105 ->select('t.id') 114 ->select('t.id')
106 ->leftJoin('t.entries', 'e')
107 ->where('e.user = :userId')->setParameter('userId', $userId)
108 ->andWhere('e.isArchived = true') 115 ->andWhere('e.isArchived = true')
109 ->groupBy('t.id')
110 ->orderBy('t.slug')
111 ->getQuery() 116 ->getQuery()
112 ->getArrayResult(); 117 ->getArrayResult();
113 118
@@ -118,4 +123,20 @@ class TagRepository extends EntityRepository
118 123
119 return $tags; 124 return $tags;
120 } 125 }
126
127 /**
128 * Retrieve a sorted list of tags used by a user.
129 *
130 * @param int $userId
131 *
132 * @return QueryBuilder
133 */
134 private function getQueryBuilderByUser($userId)
135 {
136 return $this->createQueryBuilder('t')
137 ->leftJoin('t.entries', 'e')
138 ->where('e.user = :userId')->setParameter('userId', $userId)
139 ->groupBy('t.id')
140 ->orderBy('t.slug');
141 }
121} 142}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
index cfc6644b..832112be 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
@@ -99,8 +99,8 @@
99 {% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %} 99 {% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %}
100 {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %} 100 {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %}
101 {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %} 101 {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %}
102 {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %} 102 {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %}
103 {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %} 103 {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %}
104 {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %} 104 {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %}
105 {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %} 105 {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %}
106 </ul> 106 </ul>
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 a137f3c3..742dd330 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
@@ -68,8 +68,8 @@
68 {% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %} 68 {% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %}
69 {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %} 69 {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %}
70 {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %} 70 {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %}
71 {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %} 71 {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %}
72 {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %} 72 {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %}
73 {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %} 73 {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %}
74 {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %} 74 {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %}
75 </ul> 75 </ul>
diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php
index 46bb1dc5..e56e251e 100644
--- a/src/Wallabag/CoreBundle/Tools/Utils.php
+++ b/src/Wallabag/CoreBundle/Tools/Utils.php
@@ -20,15 +20,14 @@ class Utils
20 } 20 }
21 21
22 /** 22 /**
23 * For a given text, we calculate reading time for an article 23 * For a given text, we calculate reading time for an article based on 200 words per minute.
24 * based on 200 words per minute.
25 * 24 *
26 * @param $text 25 * @param string $text
27 * 26 *
28 * @return float 27 * @return float
29 */ 28 */
30 public static function getReadingTime($text) 29 public static function getReadingTime($text)
31 { 30 {
32 return floor(\count(preg_split('~[^\p{L}\p{N}\']+~u', strip_tags($text))) / 200); 31 return floor(\count(preg_split('~([^\p{L}\p{N}\']+|(\p{Han}|\p{Hiragana}|\p{Katakana}|\p{Hangul}){1,2})~u', strip_tags($text))) / 200);
33 } 32 }
34} 33}
diff --git a/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php b/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php
index b035f5cc..e4bfbdf0 100644
--- a/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php
+++ b/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php
@@ -52,6 +52,13 @@ abstract class AbstractConsumer
52 52
53 $this->import->setUser($user); 53 $this->import->setUser($user);
54 54
55 if (false === $this->import->validateEntry($storedEntry)) {
56 $this->logger->warning('Entry is invalid', ['entry' => $storedEntry]);
57
58 // return true to skip message
59 return true;
60 }
61
55 $entry = $this->import->parseEntry($storedEntry); 62 $entry = $this->import->parseEntry($storedEntry);
56 63
57 if (null === $entry) { 64 if (null === $entry) {
diff --git a/src/Wallabag/ImportBundle/Import/AbstractImport.php b/src/Wallabag/ImportBundle/Import/AbstractImport.php
index 58a234f4..d39d71b6 100644
--- a/src/Wallabag/ImportBundle/Import/AbstractImport.php
+++ b/src/Wallabag/ImportBundle/Import/AbstractImport.php
@@ -119,6 +119,15 @@ abstract class AbstractImport implements ImportInterface
119 abstract public function parseEntry(array $importedEntry); 119 abstract public function parseEntry(array $importedEntry);
120 120
121 /** 121 /**
122 * Validate that an entry is valid (like has some required keys, etc.).
123 *
124 * @param array $importedEntry
125 *
126 * @return bool
127 */
128 abstract public function validateEntry(array $importedEntry);
129
130 /**
122 * Fetch content from the ContentProxy (using graby). 131 * Fetch content from the ContentProxy (using graby).
123 * If it fails return the given entry to be saved in all case (to avoid user to loose the content). 132 * If it fails return the given entry to be saved in all case (to avoid user to loose the content).
124 * 133 *
@@ -141,9 +150,9 @@ abstract class AbstractImport implements ImportInterface
141 /** 150 /**
142 * Parse and insert all given entries. 151 * Parse and insert all given entries.
143 * 152 *
144 * @param $entries 153 * @param array $entries
145 */ 154 */
146 protected function parseEntries($entries) 155 protected function parseEntries(array $entries)
147 { 156 {
148 $i = 1; 157 $i = 1;
149 $entryToBeFlushed = []; 158 $entryToBeFlushed = [];
@@ -153,6 +162,10 @@ abstract class AbstractImport implements ImportInterface
153 $importedEntry = $this->setEntryAsRead($importedEntry); 162 $importedEntry = $this->setEntryAsRead($importedEntry);
154 } 163 }
155 164
165 if (false === $this->validateEntry($importedEntry)) {
166 continue;
167 }
168
156 $entry = $this->parseEntry($importedEntry); 169 $entry = $this->parseEntry($importedEntry);
157 170
158 if (null === $entry) { 171 if (null === $entry) {
diff --git a/src/Wallabag/ImportBundle/Import/BrowserImport.php b/src/Wallabag/ImportBundle/Import/BrowserImport.php
index 225f1791..4678ae0c 100644
--- a/src/Wallabag/ImportBundle/Import/BrowserImport.php
+++ b/src/Wallabag/ImportBundle/Import/BrowserImport.php
@@ -149,9 +149,9 @@ abstract class BrowserImport extends AbstractImport
149 /** 149 /**
150 * Parse and insert all given entries. 150 * Parse and insert all given entries.
151 * 151 *
152 * @param $entries 152 * @param array $entries
153 */ 153 */
154 protected function parseEntries($entries) 154 protected function parseEntries(array $entries)
155 { 155 {
156 $i = 1; 156 $i = 1;
157 $entryToBeFlushed = []; 157 $entryToBeFlushed = [];
diff --git a/src/Wallabag/ImportBundle/Import/ChromeImport.php b/src/Wallabag/ImportBundle/Import/ChromeImport.php
index 09183abe..eccee698 100644
--- a/src/Wallabag/ImportBundle/Import/ChromeImport.php
+++ b/src/Wallabag/ImportBundle/Import/ChromeImport.php
@@ -33,6 +33,18 @@ class ChromeImport extends BrowserImport
33 /** 33 /**
34 * {@inheritdoc} 34 * {@inheritdoc}
35 */ 35 */
36 public function validateEntry(array $importedEntry)
37 {
38 if (empty($importedEntry['url'])) {
39 return false;
40 }
41
42 return true;
43 }
44
45 /**
46 * {@inheritdoc}
47 */
36 protected function prepareEntry(array $entry = []) 48 protected function prepareEntry(array $entry = [])
37 { 49 {
38 $data = [ 50 $data = [
diff --git a/src/Wallabag/ImportBundle/Import/FirefoxImport.php b/src/Wallabag/ImportBundle/Import/FirefoxImport.php
index 73269fe1..8999e3f3 100644
--- a/src/Wallabag/ImportBundle/Import/FirefoxImport.php
+++ b/src/Wallabag/ImportBundle/Import/FirefoxImport.php
@@ -33,6 +33,18 @@ class FirefoxImport extends BrowserImport
33 /** 33 /**
34 * {@inheritdoc} 34 * {@inheritdoc}
35 */ 35 */
36 public function validateEntry(array $importedEntry)
37 {
38 if (empty($importedEntry['uri'])) {
39 return false;
40 }
41
42 return true;
43 }
44
45 /**
46 * {@inheritdoc}
47 */
36 protected function prepareEntry(array $entry = []) 48 protected function prepareEntry(array $entry = [])
37 { 49 {
38 $data = [ 50 $data = [
diff --git a/src/Wallabag/ImportBundle/Import/InstapaperImport.php b/src/Wallabag/ImportBundle/Import/InstapaperImport.php
index e4f0970c..5a18c7c0 100644
--- a/src/Wallabag/ImportBundle/Import/InstapaperImport.php
+++ b/src/Wallabag/ImportBundle/Import/InstapaperImport.php
@@ -108,6 +108,18 @@ class InstapaperImport extends AbstractImport
108 /** 108 /**
109 * {@inheritdoc} 109 * {@inheritdoc}
110 */ 110 */
111 public function validateEntry(array $importedEntry)
112 {
113 if (empty($importedEntry['url'])) {
114 return false;
115 }
116
117 return true;
118 }
119
120 /**
121 * {@inheritdoc}
122 */
111 public function parseEntry(array $importedEntry) 123 public function parseEntry(array $importedEntry)
112 { 124 {
113 $existingEntry = $this->em 125 $existingEntry = $this->em
diff --git a/src/Wallabag/ImportBundle/Import/PinboardImport.php b/src/Wallabag/ImportBundle/Import/PinboardImport.php
index 110b0464..995d1f2c 100644
--- a/src/Wallabag/ImportBundle/Import/PinboardImport.php
+++ b/src/Wallabag/ImportBundle/Import/PinboardImport.php
@@ -83,6 +83,18 @@ class PinboardImport extends AbstractImport
83 /** 83 /**
84 * {@inheritdoc} 84 * {@inheritdoc}
85 */ 85 */
86 public function validateEntry(array $importedEntry)
87 {
88 if (empty($importedEntry['href'])) {
89 return false;
90 }
91
92 return true;
93 }
94
95 /**
96 * {@inheritdoc}
97 */
86 public function parseEntry(array $importedEntry) 98 public function parseEntry(array $importedEntry)
87 { 99 {
88 $existingEntry = $this->em 100 $existingEntry = $this->em
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php
index c1b35b7e..d3643389 100644
--- a/src/Wallabag/ImportBundle/Import/PocketImport.php
+++ b/src/Wallabag/ImportBundle/Import/PocketImport.php
@@ -170,6 +170,18 @@ class PocketImport extends AbstractImport
170 170
171 /** 171 /**
172 * {@inheritdoc} 172 * {@inheritdoc}
173 */
174 public function validateEntry(array $importedEntry)
175 {
176 if (empty($importedEntry['resolved_url']) && empty($importedEntry['given_url'])) {
177 return false;
178 }
179
180 return true;
181 }
182
183 /**
184 * {@inheritdoc}
173 * 185 *
174 * @see https://getpocket.com/developer/docs/v3/retrieve 186 * @see https://getpocket.com/developer/docs/v3/retrieve
175 */ 187 */
diff --git a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
index 002b27f4..a5f3798e 100644
--- a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
+++ b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
@@ -83,6 +83,18 @@ class ReadabilityImport extends AbstractImport
83 /** 83 /**
84 * {@inheritdoc} 84 * {@inheritdoc}
85 */ 85 */
86 public function validateEntry(array $importedEntry)
87 {
88 if (empty($importedEntry['article__url'])) {
89 return false;
90 }
91
92 return true;
93 }
94
95 /**
96 * {@inheritdoc}
97 */
86 public function parseEntry(array $importedEntry) 98 public function parseEntry(array $importedEntry)
87 { 99 {
88 $existingEntry = $this->em 100 $existingEntry = $this->em
diff --git a/src/Wallabag/ImportBundle/Import/WallabagImport.php b/src/Wallabag/ImportBundle/Import/WallabagImport.php
index c64ccd64..350d0600 100644
--- a/src/Wallabag/ImportBundle/Import/WallabagImport.php
+++ b/src/Wallabag/ImportBundle/Import/WallabagImport.php
@@ -89,6 +89,18 @@ abstract class WallabagImport extends AbstractImport
89 /** 89 /**
90 * {@inheritdoc} 90 * {@inheritdoc}
91 */ 91 */
92 public function validateEntry(array $importedEntry)
93 {
94 if (empty($importedEntry['url'])) {
95 return false;
96 }
97
98 return true;
99 }
100
101 /**
102 * {@inheritdoc}
103 */
92 public function parseEntry(array $importedEntry) 104 public function parseEntry(array $importedEntry)
93 { 105 {
94 $existingEntry = $this->em 106 $existingEntry = $this->em