diff options
author | Jeremy Benoist <jeremy.benoist@gmail.com> | 2015-12-30 12:23:51 +0100 |
---|---|---|
committer | Jeremy Benoist <jeremy.benoist@gmail.com> | 2016-01-02 23:27:41 +0100 |
commit | 252ebd60719d32ec954d0519c9edf2b52b03310c (patch) | |
tree | 044c97abeda75c33901d8bfcd33fa107279b1778 /src/Wallabag/ImportBundle/Import/PocketImport.php | |
parent | b4b592a0c0ee356e81775baf8f9976288d7b686c (diff) | |
download | wallabag-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.php | 154 |
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 | ||
3 | namespace Wallabag\ImportBundle\Import; | 3 | namespace Wallabag\ImportBundle\Import; |
4 | 4 | ||
5 | use Psr\Log\LoggerInterface; | ||
6 | use Psr\Log\NullLogger; | ||
5 | use Doctrine\ORM\EntityManager; | 7 | use Doctrine\ORM\EntityManager; |
6 | use GuzzleHttp\Client; | 8 | use GuzzleHttp\Client; |
7 | use Symfony\Component\HttpFoundation\Session\Session; | 9 | use GuzzleHttp\Exception\RequestException; |
8 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | 10 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; |
9 | use Wallabag\CoreBundle\Entity\Entry; | 11 | use Wallabag\CoreBundle\Entity\Entry; |
10 | use Wallabag\CoreBundle\Entity\Tag; | 12 | use Wallabag\CoreBundle\Entity\Tag; |
11 | use Wallabag\CoreBundle\Tools\Utils; | 13 | use Wallabag\CoreBundle\Helper\ContentProxy; |
12 | 14 | ||
13 | class PocketImport implements ImportInterface | 15 | class 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 | ||