3 namespace Wallabag\ImportBundle\Import
;
5 use Psr\Log\LoggerInterface
;
6 use Psr\Log\NullLogger
;
7 use Doctrine\ORM\EntityManager
;
9 use GuzzleHttp\Exception\RequestException
;
10 use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
;
11 use Wallabag\CoreBundle\Entity\Entry
;
12 use Wallabag\CoreBundle\Entity\Tag
;
13 use Wallabag\CoreBundle\Helper\ContentProxy
;
15 class PocketImport
implements ImportInterface
19 private $contentProxy;
23 private $skippedEntries = 0;
24 private $importedEntries = 0;
25 protected $accessToken;
27 public function __construct(TokenStorageInterface
$tokenStorage, EntityManager
$em, ContentProxy
$contentProxy, $consumerKey)
29 $this->user
= $tokenStorage->getToken()->getUser();
31 $this->contentProxy
= $contentProxy;
32 $this->consumerKey
= $consumerKey;
33 $this->logger
= new NullLogger();
36 public function setLogger(LoggerInterface
$logger)
38 $this->logger
= $logger;
44 public function getName()
52 public function getUrl()
54 return 'import_pocket';
60 public function getDescription()
62 return 'This importer will import all your Pocket data. Pocket doesn\'t allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag.';
66 * Return the oauth url to authenticate the client.
68 * @param string $redirectUri Redirect url in case of error
70 * @return string request_token for callback method
72 public function getRequestToken($redirectUri)
74 $request = $this->client
->createRequest('POST', 'https://getpocket.com/v3/oauth/request',
76 'body' => json_encode([
77 'consumer_key' => $this->consumerKey
,
78 'redirect_uri' => $redirectUri,
84 $response = $this->client
->send($request);
85 } catch (RequestException
$e) {
86 $this->logger
->error(sprintf('PocketImport: Failed to request token: %s', $e->getMessage()), ['exception' => $e]);
91 return $response->json()['code'];
95 * Usually called by the previous callback to authorize the client.
96 * Then it return a token that can be used for next requests.
98 * @param string $code request_token from getRequestToken
102 public function authorize($code)
104 $request = $this->client
->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize',
106 'body' => json_encode([
107 'consumer_key' => $this->consumerKey
,
114 $response = $this->client
->send($request);
115 } catch (RequestException
$e) {
116 $this->logger
->error(sprintf('PocketImport: Failed to authorize client: %s', $e->getMessage()), ['exception' => $e]);
121 $this->accessToken
= $response->json()['access_token'];
129 public function import()
131 $request = $this->client
->createRequest('POST', 'https://getpocket.com/v3/get',
133 'body' => json_encode([
134 'consumer_key' => $this->consumerKey
,
135 'access_token' => $this->accessToken
,
136 'detailType' => 'complete',
144 $response = $this->client
->send($request);
145 } catch (RequestException
$e) {
146 $this->logger
->error(sprintf('PocketImport: Failed to import: %s', $e->getMessage()), ['exception' => $e]);
151 $entries = $response->json();
153 $this->parseEntries($entries['list']);
161 public function getSummary()
164 'skipped' => $this->skippedEntries
,
165 'imported' => $this->importedEntries
,
170 * Set the Guzzle client.
172 * @param Client $client
174 public function setClient(Client
$client)
176 $this->client
= $client;
179 private function assignTagsToEntry(Entry
$entry, $tags)
181 foreach ($tags as $tag) {
182 $label = trim($tag['tag']);
183 $tagEntity = $this->em
184 ->getRepository('WallabagCoreBundle:Tag')
185 ->findOneByLabel($label);
187 if (is_object($tagEntity)) {
188 $entry->addTag($tagEntity);
191 $newTag->setLabel($label);
193 $entry->addTag($newTag);
200 * @see https://getpocket.com/developer/docs/v3/retrieve
204 private function parseEntries($entries)
208 foreach ($entries as $pocketEntry) {
209 $url = isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '' ? $pocketEntry['resolved_url'] : $pocketEntry['given_url'];
211 $existingEntry = $this->em
212 ->getRepository('WallabagCoreBundle:Entry')
213 ->findByUrlAndUserId($url, $this->user
->getId());
215 if (false !== $existingEntry) {
216 ++
$this->skippedEntries
;
220 $entry = new Entry($this->user
);
221 $entry = $this->contentProxy
->updateEntry($entry, $url);
223 // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted
224 if ($pocketEntry['status'] == 1) {
225 $entry->setArchived(true);
228 // 0 or 1 - 1 If the item is favorited
229 if ($pocketEntry['favorite'] == 1) {
230 $entry->setStarred(true);
234 if (isset($pocketEntry['resolved_title']) && $pocketEntry['resolved_title'] != '') {
235 $title = $pocketEntry['resolved_title'];
236 } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') {
237 $title = $pocketEntry['given_title'];
240 $entry->setTitle($title);
242 // 0, 1, or 2 - 1 if the item has images in it - 2 if the item is an image
243 if (isset($pocketEntry['has_image']) && $pocketEntry['has_image'] > 0 && isset($pocketEntry['images'][1])) {
244 $entry->setPreviewPicture($pocketEntry['images'][1]['src']);
247 if (isset($pocketEntry['tags']) && !empty($pocketEntry['tags'])) {
248 $this->assignTagsToEntry($entry, $pocketEntry['tags']);
251 $this->em
->persist($entry);
252 ++
$this->importedEntries
;
254 // flush every 20 entries
255 if (($i %
20) === 0) {