diff options
author | Jeremy Benoist <jeremy.benoist@gmail.com> | 2016-08-19 23:52:19 +0200 |
---|---|---|
committer | Jeremy Benoist <jeremy.benoist@gmail.com> | 2016-08-20 01:17:26 +0200 |
commit | 19d9efab32b5c6403e9ee95fb70a2ce56a27f14b (patch) | |
tree | 325d2724ae5e5988b2ab77a33cf3f4cfe88c3647 | |
parent | e408d7e895e784271a55c3a200666034db0af80a (diff) | |
download | wallabag-19d9efab32b5c6403e9ee95fb70a2ce56a27f14b.tar.gz wallabag-19d9efab32b5c6403e9ee95fb70a2ce56a27f14b.tar.zst wallabag-19d9efab32b5c6403e9ee95fb70a2ce56a27f14b.zip |
Avoid breaking import when fetching fail
graby will throw an Exception in some case (like a bad url, a restricted url or a secured pdf).
Import doesn't handle that case and break the whole import.
With that commit the import isn't stopped but the entry is just skipped.
Also, as a bonus, I've added extra test on WallabagImportV2 when the json is empty.
6 files changed, 154 insertions, 32 deletions
diff --git a/src/Wallabag/ImportBundle/Import/AbstractImport.php b/src/Wallabag/ImportBundle/Import/AbstractImport.php new file mode 100644 index 00000000..14377a35 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/AbstractImport.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ImportBundle\Import; | ||
4 | |||
5 | use Psr\Log\LoggerInterface; | ||
6 | use Psr\Log\NullLogger; | ||
7 | use Doctrine\ORM\EntityManager; | ||
8 | use Wallabag\CoreBundle\Helper\ContentProxy; | ||
9 | use Wallabag\CoreBundle\Entity\Entry; | ||
10 | |||
11 | abstract class AbstractImport implements ImportInterface | ||
12 | { | ||
13 | protected $em; | ||
14 | protected $logger; | ||
15 | protected $contentProxy; | ||
16 | |||
17 | public function __construct(EntityManager $em, ContentProxy $contentProxy) | ||
18 | { | ||
19 | $this->em = $em; | ||
20 | $this->logger = new NullLogger(); | ||
21 | $this->contentProxy = $contentProxy; | ||
22 | } | ||
23 | |||
24 | public function setLogger(LoggerInterface $logger) | ||
25 | { | ||
26 | $this->logger = $logger; | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * Fetch content from the ContentProxy (using graby). | ||
31 | * If it fails return false instead of the updated entry. | ||
32 | * | ||
33 | * @param Entry $entry Entry to update | ||
34 | * @param string $url Url to grab content for | ||
35 | * @param array $content An array with AT LEAST keys title, html, url, language & content_type to skip the fetchContent from the url | ||
36 | * | ||
37 | * @return Entry|false | ||
38 | */ | ||
39 | protected function fetchContent(Entry $entry, $url, array $content = []) | ||
40 | { | ||
41 | try { | ||
42 | return $this->contentProxy->updateEntry($entry, $url, $content); | ||
43 | } catch (\Exception $e) { | ||
44 | return false; | ||
45 | } | ||
46 | } | ||
47 | } | ||
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 29361a32..678d016a 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ImportBundle\Import; | 3 | namespace Wallabag\ImportBundle\Import; |
4 | 4 | ||
5 | use Psr\Log\LoggerInterface; | ||
6 | use Psr\Log\NullLogger; | 5 | use Psr\Log\NullLogger; |
7 | use Doctrine\ORM\EntityManager; | 6 | use Doctrine\ORM\EntityManager; |
8 | use GuzzleHttp\Client; | 7 | use GuzzleHttp\Client; |
@@ -12,12 +11,9 @@ use Wallabag\CoreBundle\Entity\Entry; | |||
12 | use Wallabag\CoreBundle\Helper\ContentProxy; | 11 | use Wallabag\CoreBundle\Helper\ContentProxy; |
13 | use Craue\ConfigBundle\Util\Config; | 12 | use Craue\ConfigBundle\Util\Config; |
14 | 13 | ||
15 | class PocketImport implements ImportInterface | 14 | class PocketImport extends AbstractImport |
16 | { | 15 | { |
17 | private $user; | 16 | private $user; |
18 | private $em; | ||
19 | private $contentProxy; | ||
20 | private $logger; | ||
21 | private $client; | 17 | private $client; |
22 | private $consumerKey; | 18 | private $consumerKey; |
23 | private $skippedEntries = 0; | 19 | private $skippedEntries = 0; |
@@ -34,11 +30,6 @@ class PocketImport implements ImportInterface | |||
34 | $this->logger = new NullLogger(); | 30 | $this->logger = new NullLogger(); |
35 | } | 31 | } |
36 | 32 | ||
37 | public function setLogger(LoggerInterface $logger) | ||
38 | { | ||
39 | $this->logger = $logger; | ||
40 | } | ||
41 | |||
42 | /** | 33 | /** |
43 | * {@inheritdoc} | 34 | * {@inheritdoc} |
44 | */ | 35 | */ |
@@ -219,7 +210,13 @@ class PocketImport implements ImportInterface | |||
219 | } | 210 | } |
220 | 211 | ||
221 | $entry = new Entry($this->user); | 212 | $entry = new Entry($this->user); |
222 | $entry = $this->contentProxy->updateEntry($entry, $url); | 213 | $entry = $this->fetchContent($entry, $url); |
214 | |||
215 | // jump to next entry in case of problem while getting content | ||
216 | if (false === $entry) { | ||
217 | ++$this->skippedEntries; | ||
218 | continue; | ||
219 | } | ||
223 | 220 | ||
224 | // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted | 221 | // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted |
225 | if ($pocketEntry['status'] == 1 || $this->markAsRead) { | 222 | if ($pocketEntry['status'] == 1 || $this->markAsRead) { |
diff --git a/src/Wallabag/ImportBundle/Import/WallabagImport.php b/src/Wallabag/ImportBundle/Import/WallabagImport.php index 65803823..a1cc085b 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagImport.php +++ b/src/Wallabag/ImportBundle/Import/WallabagImport.php | |||
@@ -2,19 +2,12 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ImportBundle\Import; | 3 | namespace Wallabag\ImportBundle\Import; |
4 | 4 | ||
5 | use Psr\Log\LoggerInterface; | ||
6 | use Psr\Log\NullLogger; | ||
7 | use Doctrine\ORM\EntityManager; | ||
8 | use Wallabag\CoreBundle\Entity\Entry; | 5 | use Wallabag\CoreBundle\Entity\Entry; |
9 | use Wallabag\UserBundle\Entity\User; | 6 | use Wallabag\UserBundle\Entity\User; |
10 | use Wallabag\CoreBundle\Helper\ContentProxy; | ||
11 | 7 | ||
12 | abstract class WallabagImport implements ImportInterface | 8 | abstract class WallabagImport extends AbstractImport |
13 | { | 9 | { |
14 | protected $user; | 10 | protected $user; |
15 | protected $em; | ||
16 | protected $logger; | ||
17 | protected $contentProxy; | ||
18 | protected $skippedEntries = 0; | 11 | protected $skippedEntries = 0; |
19 | protected $importedEntries = 0; | 12 | protected $importedEntries = 0; |
20 | protected $filepath; | 13 | protected $filepath; |
@@ -35,18 +28,6 @@ abstract class WallabagImport implements ImportInterface | |||
35 | '', | 28 | '', |
36 | ]; | 29 | ]; |
37 | 30 | ||
38 | public function __construct(EntityManager $em, ContentProxy $contentProxy) | ||
39 | { | ||
40 | $this->em = $em; | ||
41 | $this->logger = new NullLogger(); | ||
42 | $this->contentProxy = $contentProxy; | ||
43 | } | ||
44 | |||
45 | public function setLogger(LoggerInterface $logger) | ||
46 | { | ||
47 | $this->logger = $logger; | ||
48 | } | ||
49 | |||
50 | /** | 31 | /** |
51 | * We define the user in a custom call because on the import command there is no logged in user. | 32 | * We define the user in a custom call because on the import command there is no logged in user. |
52 | * So we can't retrieve user from the `security.token_storage` service. | 33 | * So we can't retrieve user from the `security.token_storage` service. |
@@ -159,12 +140,18 @@ abstract class WallabagImport implements ImportInterface | |||
159 | 140 | ||
160 | $data = $this->prepareEntry($importedEntry, $this->markAsRead); | 141 | $data = $this->prepareEntry($importedEntry, $this->markAsRead); |
161 | 142 | ||
162 | $entry = $this->contentProxy->updateEntry( | 143 | $entry = $this->fetchContent( |
163 | new Entry($this->user), | 144 | new Entry($this->user), |
164 | $importedEntry['url'], | 145 | $importedEntry['url'], |
165 | $data | 146 | $data |
166 | ); | 147 | ); |
167 | 148 | ||
149 | // jump to next entry in case of problem while getting content | ||
150 | if (false === $entry) { | ||
151 | ++$this->skippedEntries; | ||
152 | continue; | ||
153 | } | ||
154 | |||
168 | if (array_key_exists('tags', $data)) { | 155 | if (array_key_exists('tags', $data)) { |
169 | $this->contentProxy->assignTagsToEntry( | 156 | $this->contentProxy->assignTagsToEntry( |
170 | $entry, | 157 | $entry, |
diff --git a/tests/Wallabag/ImportBundle/Import/PocketImportTest.php b/tests/Wallabag/ImportBundle/Import/PocketImportTest.php index 41f9b51f..8534e1c8 100644 --- a/tests/Wallabag/ImportBundle/Import/PocketImportTest.php +++ b/tests/Wallabag/ImportBundle/Import/PocketImportTest.php | |||
@@ -390,4 +390,55 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase | |||
390 | $this->assertContains('PocketImport: Failed to import', $records[0]['message']); | 390 | $this->assertContains('PocketImport: Failed to import', $records[0]['message']); |
391 | $this->assertEquals('ERROR', $records[0]['level_name']); | 391 | $this->assertEquals('ERROR', $records[0]['level_name']); |
392 | } | 392 | } |
393 | |||
394 | public function testImportWithExceptionFromGraby() | ||
395 | { | ||
396 | $client = new Client(); | ||
397 | |||
398 | $mock = new Mock([ | ||
399 | new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))), | ||
400 | new Response(200, ['Content-Type' => 'application/json'], Stream::factory(' | ||
401 | { | ||
402 | "status": 1, | ||
403 | "list": { | ||
404 | "229279689": { | ||
405 | "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview" | ||
406 | } | ||
407 | } | ||
408 | } | ||
409 | ')), | ||
410 | ]); | ||
411 | |||
412 | $client->getEmitter()->attach($mock); | ||
413 | |||
414 | $pocketImport = $this->getPocketImport(); | ||
415 | |||
416 | $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository') | ||
417 | ->disableOriginalConstructor() | ||
418 | ->getMock(); | ||
419 | |||
420 | $entryRepo->expects($this->once()) | ||
421 | ->method('findByUrlAndUserId') | ||
422 | ->will($this->onConsecutiveCalls(false, true)); | ||
423 | |||
424 | $this->em | ||
425 | ->expects($this->once()) | ||
426 | ->method('getRepository') | ||
427 | ->willReturn($entryRepo); | ||
428 | |||
429 | $entry = new Entry($this->user); | ||
430 | |||
431 | $this->contentProxy | ||
432 | ->expects($this->once()) | ||
433 | ->method('updateEntry') | ||
434 | ->will($this->throwException(new \Exception())); | ||
435 | |||
436 | $pocketImport->setClient($client); | ||
437 | $pocketImport->authorize('wunderbar_code'); | ||
438 | |||
439 | $res = $pocketImport->import(); | ||
440 | |||
441 | $this->assertTrue($res); | ||
442 | $this->assertEquals(['skipped' => 1, 'imported' => 0], $pocketImport->getSummary()); | ||
443 | } | ||
393 | } | 444 | } |
diff --git a/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php b/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php index 8ec66b12..4a45e0f0 100644 --- a/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php +++ b/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php | |||
@@ -143,4 +143,44 @@ class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase | |||
143 | $this->assertContains('WallabagImport: user is not defined', $records[0]['message']); | 143 | $this->assertContains('WallabagImport: user is not defined', $records[0]['message']); |
144 | $this->assertEquals('ERROR', $records[0]['level_name']); | 144 | $this->assertEquals('ERROR', $records[0]['level_name']); |
145 | } | 145 | } |
146 | |||
147 | public function testImportEmptyFile() | ||
148 | { | ||
149 | $wallabagV2Import = $this->getWallabagV2Import(); | ||
150 | $wallabagV2Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2-empty.json'); | ||
151 | |||
152 | $res = $wallabagV2Import->import(); | ||
153 | |||
154 | $this->assertFalse($res); | ||
155 | $this->assertEquals(['skipped' => 0, 'imported' => 0], $wallabagV2Import->getSummary()); | ||
156 | } | ||
157 | |||
158 | public function testImportWithExceptionFromGraby() | ||
159 | { | ||
160 | $wallabagV2Import = $this->getWallabagV2Import(); | ||
161 | $wallabagV2Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2.json'); | ||
162 | |||
163 | $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository') | ||
164 | ->disableOriginalConstructor() | ||
165 | ->getMock(); | ||
166 | |||
167 | $entryRepo->expects($this->exactly(24)) | ||
168 | ->method('findByUrlAndUserId') | ||
169 | ->will($this->onConsecutiveCalls(false, true, false)); | ||
170 | |||
171 | $this->em | ||
172 | ->expects($this->any()) | ||
173 | ->method('getRepository') | ||
174 | ->willReturn($entryRepo); | ||
175 | |||
176 | $this->contentProxy | ||
177 | ->expects($this->exactly(2)) | ||
178 | ->method('updateEntry') | ||
179 | ->will($this->throwException(new \Exception())); | ||
180 | |||
181 | $res = $wallabagV2Import->import(); | ||
182 | |||
183 | $this->assertTrue($res); | ||
184 | $this->assertEquals(['skipped' => 24, 'imported' => 0], $wallabagV2Import->getSummary()); | ||
185 | } | ||
146 | } | 186 | } |
diff --git a/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-empty.json b/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-empty.json new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-empty.json | |||