aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/ImportBundle/Import/PocketImport.php
diff options
context:
space:
mode:
authorJeremy Benoist <jeremy.benoist@gmail.com>2015-12-30 12:23:51 +0100
committerJeremy Benoist <jeremy.benoist@gmail.com>2016-01-02 23:27:41 +0100
commit252ebd60719d32ec954d0519c9edf2b52b03310c (patch)
tree044c97abeda75c33901d8bfcd33fa107279b1778 /src/Wallabag/ImportBundle/Import/PocketImport.php
parentb4b592a0c0ee356e81775baf8f9976288d7b686c (diff)
downloadwallabag-252ebd60719d32ec954d0519c9edf2b52b03310c.tar.gz
wallabag-252ebd60719d32ec954d0519c9edf2b52b03310c.tar.zst
wallabag-252ebd60719d32ec954d0519c9edf2b52b03310c.zip
Rewrote Pocket Import
For the moment, we won't do a queue system, just a plain synchronous import. We also use ContentProxy to grab content for each article from Pocket. Error from Pocket are now logged using the logger. The ImportInterface need to be simple and not related to oAuth (not all import will use that method).
Diffstat (limited to 'src/Wallabag/ImportBundle/Import/PocketImport.php')
-rw-r--r--src/Wallabag/ImportBundle/Import/PocketImport.php154
1 files changed, 86 insertions, 68 deletions
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php
index e5c86f07..1710d9d3 100644
--- a/src/Wallabag/ImportBundle/Import/PocketImport.php
+++ b/src/Wallabag/ImportBundle/Import/PocketImport.php
@@ -2,29 +2,39 @@
2 2
3namespace Wallabag\ImportBundle\Import; 3namespace Wallabag\ImportBundle\Import;
4 4
5use Psr\Log\LoggerInterface;
6use Psr\Log\NullLogger;
5use Doctrine\ORM\EntityManager; 7use Doctrine\ORM\EntityManager;
6use GuzzleHttp\Client; 8use GuzzleHttp\Client;
7use Symfony\Component\HttpFoundation\Session\Session; 9use GuzzleHttp\Exception\RequestException;
8use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 10use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
9use Wallabag\CoreBundle\Entity\Entry; 11use Wallabag\CoreBundle\Entity\Entry;
10use Wallabag\CoreBundle\Entity\Tag; 12use Wallabag\CoreBundle\Entity\Tag;
11use Wallabag\CoreBundle\Tools\Utils; 13use Wallabag\CoreBundle\Helper\ContentProxy;
12 14
13class PocketImport implements ImportInterface 15class PocketImport implements ImportInterface
14{ 16{
15 private $user; 17 private $user;
16 private $session;
17 private $em; 18 private $em;
19 private $contentProxy;
20 private $logger;
18 private $consumerKey; 21 private $consumerKey;
19 private $skippedEntries = 0; 22 private $skippedEntries = 0;
20 private $importedEntries = 0; 23 private $importedEntries = 0;
24 protected $accessToken;
21 25
22 public function __construct(TokenStorageInterface $tokenStorage, Session $session, EntityManager $em, $consumerKey) 26 public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, $consumerKey)
23 { 27 {
24 $this->user = $tokenStorage->getToken()->getUser(); 28 $this->user = $tokenStorage->getToken()->getUser();
25 $this->session = $session;
26 $this->em = $em; 29 $this->em = $em;
30 $this->contentProxy = $contentProxy;
27 $this->consumerKey = $consumerKey; 31 $this->consumerKey = $consumerKey;
32 $this->logger = new NullLogger();
33 }
34
35 public function setLogger(LoggerInterface $logger)
36 {
37 $this->logger = $logger;
28 } 38 }
29 39
30 /** 40 /**
@@ -44,9 +54,13 @@ class PocketImport implements ImportInterface
44 } 54 }
45 55
46 /** 56 /**
47 * {@inheritdoc} 57 * Return the oauth url to authenticate the client.
58 *
59 * @param string $redirectUri Redirect url in case of error
60 *
61 * @return string request_token for callback method
48 */ 62 */
49 public function oAuthRequest($redirectUri, $callbackUri) 63 public function getRequestToken($redirectUri)
50 { 64 {
51 $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', 65 $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/request',
52 [ 66 [
@@ -57,44 +71,59 @@ class PocketImport implements ImportInterface
57 ] 71 ]
58 ); 72 );
59 73
60 $response = $this->client->send($request); 74 try {
61 $values = $response->json(); 75 $response = $this->client->send($request);
76 } catch (RequestException $e) {
77 $this->logger->error(sprintf('PocketImport: Failed to request token: %s', $e->getMessage()), ['exception' => $e]);
62 78
63 // store code in session for callback method 79 return false;
64 $this->session->set('pocketCode', $values['code']); 80 }
65 81
66 return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; 82 return $response->json()['code'];
67 } 83 }
68 84
69 /** 85 /**
70 * {@inheritdoc} 86 * Usually called by the previous callback to authorize the client.
87 * Then it return a token that can be used for next requests.
88 *
89 * @param string $code request_token from getRequestToken
90 *
91 * @return bool
71 */ 92 */
72 public function oAuthAuthorize() 93 public function authorize($code)
73 { 94 {
74 $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', 95 $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize',
75 [ 96 [
76 'body' => json_encode([ 97 'body' => json_encode([
77 'consumer_key' => $this->consumerKey, 98 'consumer_key' => $this->consumerKey,
78 'code' => $this->session->get('pocketCode'), 99 'code' => $code,
79 ]), 100 ]),
80 ] 101 ]
81 ); 102 );
82 103
83 $response = $this->client->send($request); 104 try {
105 $response = $this->client->send($request);
106 } catch (RequestException $e) {
107 $this->logger->error(sprintf('PocketImport: Failed to authorize client: %s', $e->getMessage()), ['exception' => $e]);
84 108
85 return $response->json()['access_token']; 109 return false;
110 }
111
112 $this->accessToken = $response->json()['access_token'];
113
114 return true;
86 } 115 }
87 116
88 /** 117 /**
89 * {@inheritdoc} 118 * {@inheritdoc}
90 */ 119 */
91 public function import($accessToken) 120 public function import()
92 { 121 {
93 $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/get', 122 $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/get',
94 [ 123 [
95 'body' => json_encode([ 124 'body' => json_encode([
96 'consumer_key' => $this->consumerKey, 125 'consumer_key' => $this->consumerKey,
97 'access_token' => $accessToken, 126 'access_token' => $this->accessToken,
98 'detailType' => 'complete', 127 'detailType' => 'complete',
99 'state' => 'all', 128 'state' => 'all',
100 'sort' => 'oldest', 129 'sort' => 'oldest',
@@ -102,61 +131,45 @@ class PocketImport implements ImportInterface
102 ] 131 ]
103 ); 132 );
104 133
105 $response = $this->client->send($request); 134 try {
135 $response = $this->client->send($request);
136 } catch (RequestException $e) {
137 $this->logger->error(sprintf('PocketImport: Failed to import: %s', $e->getMessage()), ['exception' => $e]);
138
139 return false;
140 }
141
106 $entries = $response->json(); 142 $entries = $response->json();
107 143
108 $this->parsePocketEntries($entries['list']); 144 $this->parsePocketEntries($entries['list']);
109 145
110 $this->session->getFlashBag()->add( 146 return true;
111 'notice',
112 $this->importedEntries.' entries imported, '.$this->skippedEntries.' already saved.'
113 );
114 } 147 }
115 148
116 /** 149 /**
117 * Set the Guzzle client. 150 * {@inheritdoc}
118 *
119 * @param Client $client
120 */ 151 */
121 public function setClient(Client $client) 152 public function getSummary()
122 { 153 {
123 $this->client = $client; 154 return [
155 'skipped' => $this->skippedEntries,
156 'imported' => $this->importedEntries,
157 ];
124 } 158 }
125 159
126 /** 160 /**
127 * Returns the good title for current entry. 161 * Set the Guzzle client.
128 *
129 * @param $pocketEntry
130 * 162 *
131 * @return string 163 * @param Client $client
132 */ 164 */
133 private function guessTitle($pocketEntry) 165 public function setClient(Client $client)
134 { 166 {
135 if (isset($pocketEntry['resolved_title']) && $pocketEntry['resolved_title'] != '') { 167 $this->client = $client;
136 return $pocketEntry['resolved_title'];
137 } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') {
138 return $pocketEntry['given_title'];
139 }
140
141 return 'Untitled';
142 } 168 }
143 169
144 /** 170 /**
145 * Returns the good URL for current entry. 171 * @todo move that in a more global place
146 *
147 * @param $pocketEntry
148 *
149 * @return string
150 */ 172 */
151 private function guessURL($pocketEntry)
152 {
153 if (isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '') {
154 return $pocketEntry['resolved_url'];
155 }
156
157 return $pocketEntry['given_url'];
158 }
159
160 private function assignTagsToEntry(Entry $entry, $tags) 173 private function assignTagsToEntry(Entry $entry, $tags)
161 { 174 {
162 foreach ($tags as $tag) { 175 foreach ($tags as $tag) {
@@ -177,13 +190,16 @@ class PocketImport implements ImportInterface
177 } 190 }
178 191
179 /** 192 /**
193 * @see https://getpocket.com/developer/docs/v3/retrieve
194 *
180 * @param $entries 195 * @param $entries
181 */ 196 */
182 private function parsePocketEntries($entries) 197 private function parsePocketEntries($entries)
183 { 198 {
184 foreach ($entries as $pocketEntry) { 199 foreach ($entries as $pocketEntry) {
185 $entry = new Entry($this->user); 200 $entry = new Entry($this->user);
186 $url = $this->guessURL($pocketEntry); 201
202 $url = isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '' ? $pocketEntry['resolved_url'] : $pocketEntry['given_url'];
187 203
188 $existingEntry = $this->em 204 $existingEntry = $this->em
189 ->getRepository('WallabagCoreBundle:Entry') 205 ->getRepository('WallabagCoreBundle:Entry')
@@ -194,31 +210,33 @@ class PocketImport implements ImportInterface
194 continue; 210 continue;
195 } 211 }
196 212
197 $entry->setUrl($url); 213 $entry = $this->contentProxy->updateEntry($entry, $url);
198 $entry->setDomainName(parse_url($url, PHP_URL_HOST));
199 214
215 // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted
200 if ($pocketEntry['status'] == 1) { 216 if ($pocketEntry['status'] == 1) {
201 $entry->setArchived(true); 217 $entry->setArchived(true);
202 } 218 }
219
220 // 0 or 1 - 1 If the item is favorited
203 if ($pocketEntry['favorite'] == 1) { 221 if ($pocketEntry['favorite'] == 1) {
204 $entry->setStarred(true); 222 $entry->setStarred(true);
205 } 223 }
206 224
207 $entry->setTitle($this->guessTitle($pocketEntry)); 225 $title = 'Untitled';
208 226 if (isset($pocketEntry['resolved_title']) && $pocketEntry['resolved_title'] != '') {
209 if (isset($pocketEntry['excerpt'])) { 227 $title = $pocketEntry['resolved_title'];
210 $entry->setContent($pocketEntry['excerpt']); 228 } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') {
229 $title = $pocketEntry['given_title'];
211 } 230 }
212 231
213 if (isset($pocketEntry['has_image']) && $pocketEntry['has_image'] > 0) { 232 $entry->setTitle($title);
214 $entry->setPreviewPicture($pocketEntry['image']['src']);
215 }
216 233
217 if (isset($pocketEntry['word_count'])) { 234 // 0, 1, or 2 - 1 if the item has images in it - 2 if the item is an image
218 $entry->setReadingTime(Utils::convertWordsToMinutes($pocketEntry['word_count'])); 235 if (isset($pocketEntry['has_image']) && $pocketEntry['has_image'] > 0 && isset($pocketEntry['images'][1])) {
236 $entry->setPreviewPicture($pocketEntry['images'][1]['src']);
219 } 237 }
220 238
221 if (!empty($pocketEntry['tags'])) { 239 if (isset($pocketEntry['tags']) && !empty($pocketEntry['tags'])) {
222 $this->assignTagsToEntry($entry, $pocketEntry['tags']); 240 $this->assignTagsToEntry($entry, $pocketEntry['tags']);
223 } 241 }
224 242