diff options
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 | ||