diff options
Diffstat (limited to 'src/Wallabag')
34 files changed, 418 insertions, 160 deletions
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php index 31bb67fd..93c8157e 100644 --- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php | |||
@@ -231,7 +231,6 @@ class EntryRestController extends WallabagRestController | |||
231 | $this->validateAuthentication(); | 231 | $this->validateAuthentication(); |
232 | 232 | ||
233 | $urls = json_decode($request->query->get('urls', [])); | 233 | $urls = json_decode($request->query->get('urls', [])); |
234 | $results = []; | ||
235 | 234 | ||
236 | $limit = $this->container->getParameter('wallabag_core.api_limit_mass_actions'); | 235 | $limit = $this->container->getParameter('wallabag_core.api_limit_mass_actions'); |
237 | 236 | ||
@@ -239,32 +238,34 @@ class EntryRestController extends WallabagRestController | |||
239 | throw new HttpException(400, 'API limit reached'); | 238 | throw new HttpException(400, 'API limit reached'); |
240 | } | 239 | } |
241 | 240 | ||
241 | $results = []; | ||
242 | if (empty($urls)) { | ||
243 | return $this->sendResponse($results); | ||
244 | } | ||
245 | |||
242 | // handle multiple urls | 246 | // handle multiple urls |
243 | if (!empty($urls)) { | 247 | foreach ($urls as $key => $url) { |
244 | foreach ($urls as $key => $url) { | 248 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( |
245 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId( | 249 | $url, |
246 | $url, | 250 | $this->getUser()->getId() |
247 | $this->getUser()->getId() | 251 | ); |
248 | ); | ||
249 | |||
250 | $results[$key]['url'] = $url; | ||
251 | |||
252 | if (false === $entry) { | ||
253 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( | ||
254 | new Entry($this->getUser()), | ||
255 | $url | ||
256 | ); | ||
257 | } | ||
258 | 252 | ||
259 | $em = $this->getDoctrine()->getManager(); | 253 | $results[$key]['url'] = $url; |
260 | $em->persist($entry); | ||
261 | $em->flush(); | ||
262 | 254 | ||
263 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; | 255 | if (false === $entry) { |
256 | $entry = new Entry($this->getUser()); | ||
264 | 257 | ||
265 | // entry saved, dispatch event about it! | 258 | $this->get('wallabag_core.content_proxy')->updateEntry($entry, $url); |
266 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | ||
267 | } | 259 | } |
260 | |||
261 | $em = $this->getDoctrine()->getManager(); | ||
262 | $em->persist($entry); | ||
263 | $em->flush(); | ||
264 | |||
265 | $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false; | ||
266 | |||
267 | // entry saved, dispatch event about it! | ||
268 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | ||
268 | } | 269 | } |
269 | 270 | ||
270 | return $this->sendResponse($results); | 271 | return $this->sendResponse($results); |
@@ -273,6 +274,9 @@ class EntryRestController extends WallabagRestController | |||
273 | /** | 274 | /** |
274 | * Create an entry. | 275 | * Create an entry. |
275 | * | 276 | * |
277 | * If you want to provide the HTML content (which means wallabag won't fetch it from the url), you must provide `content`, `title` & `url` fields **non-empty**. | ||
278 | * Otherwise, content will be fetched as normal from the url and values will be overwritten. | ||
279 | * | ||
276 | * @ApiDoc( | 280 | * @ApiDoc( |
277 | * parameters={ | 281 | * parameters={ |
278 | * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."}, | 282 | * {"name"="url", "dataType"="string", "required"=true, "format"="http://www.test.com/article.html", "description"="Url for the entry."}, |
@@ -280,6 +284,11 @@ class EntryRestController extends WallabagRestController | |||
280 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, | 284 | * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, |
281 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"}, | 285 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already starred"}, |
282 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"}, | 286 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="entry already archived"}, |
287 | * {"name"="content", "dataType"="string", "required"=false, "description"="Content of the entry"}, | ||
288 | * {"name"="language", "dataType"="string", "required"=false, "description"="Language of the entry"}, | ||
289 | * {"name"="preview_picture", "dataType"="string", "required"=false, "description"="Preview picture of the entry"}, | ||
290 | * {"name"="published_at", "dataType"="datetime|integer", "format"="YYYY-MM-DDTHH:II:SS+TZ or a timestamp", "required"=false, "description"="Published date of the entry"}, | ||
291 | * {"name"="authors", "dataType"="string", "format"="Name Firstname,author2,author3", "required"=false, "description"="Authors of the entry"}, | ||
283 | * } | 292 | * } |
284 | * ) | 293 | * ) |
285 | * | 294 | * |
@@ -291,32 +300,46 @@ class EntryRestController extends WallabagRestController | |||
291 | 300 | ||
292 | $url = $request->request->get('url'); | 301 | $url = $request->request->get('url'); |
293 | $title = $request->request->get('title'); | 302 | $title = $request->request->get('title'); |
303 | $tags = $request->request->get('tags', []); | ||
294 | $isArchived = $request->request->get('archive'); | 304 | $isArchived = $request->request->get('archive'); |
295 | $isStarred = $request->request->get('starred'); | 305 | $isStarred = $request->request->get('starred'); |
306 | $content = $request->request->get('content'); | ||
307 | $language = $request->request->get('language'); | ||
308 | $picture = $request->request->get('preview_picture'); | ||
309 | $publishedAt = $request->request->get('published_at'); | ||
310 | $authors = $request->request->get('authors', ''); | ||
296 | 311 | ||
297 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId()); | 312 | $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($url, $this->getUser()->getId()); |
298 | 313 | ||
299 | if (false === $entry) { | 314 | if (false === $entry) { |
300 | $entry = new Entry($this->getUser()); | 315 | $entry = new Entry($this->getUser()); |
301 | try { | ||
302 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( | ||
303 | $entry, | ||
304 | $url | ||
305 | ); | ||
306 | } catch (\Exception $e) { | ||
307 | $this->get('logger')->error('Error while saving an entry', [ | ||
308 | 'exception' => $e, | ||
309 | 'entry' => $entry, | ||
310 | ]); | ||
311 | $entry->setUrl($url); | ||
312 | } | ||
313 | } | 316 | } |
314 | 317 | ||
315 | if (!is_null($title)) { | 318 | try { |
316 | $entry->setTitle($title); | 319 | $this->get('wallabag_core.content_proxy')->updateEntry( |
320 | $entry, | ||
321 | $url, | ||
322 | [ | ||
323 | 'title' => $title, | ||
324 | 'html' => $content, | ||
325 | 'url' => $url, | ||
326 | 'language' => $language, | ||
327 | 'date' => $publishedAt, | ||
328 | // faking the preview picture | ||
329 | 'open_graph' => [ | ||
330 | 'og_image' => $picture, | ||
331 | ], | ||
332 | 'authors' => explode(',', $authors), | ||
333 | ] | ||
334 | ); | ||
335 | } catch (\Exception $e) { | ||
336 | $this->get('logger')->error('Error while saving an entry', [ | ||
337 | 'exception' => $e, | ||
338 | 'entry' => $entry, | ||
339 | ]); | ||
340 | $entry->setUrl($url); | ||
317 | } | 341 | } |
318 | 342 | ||
319 | $tags = $request->request->get('tags', ''); | ||
320 | if (!empty($tags)) { | 343 | if (!empty($tags)) { |
321 | $this->get('wallabag_core.tags_assigner')->assignTagsToEntry($entry, $tags); | 344 | $this->get('wallabag_core.tags_assigner')->assignTagsToEntry($entry, $tags); |
322 | } | 345 | } |
@@ -406,7 +429,7 @@ class EntryRestController extends WallabagRestController | |||
406 | $this->validateUserAccess($entry->getUser()->getId()); | 429 | $this->validateUserAccess($entry->getUser()->getId()); |
407 | 430 | ||
408 | try { | 431 | try { |
409 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); | 432 | $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); |
410 | } catch (\Exception $e) { | 433 | } catch (\Exception $e) { |
411 | $this->get('logger')->error('Error while saving an entry', [ | 434 | $this->get('logger')->error('Error while saving an entry', [ |
412 | 'exception' => $e, | 435 | 'exception' => $e, |
diff --git a/src/Wallabag/ApiBundle/Controller/UserRestController.php b/src/Wallabag/ApiBundle/Controller/UserRestController.php new file mode 100644 index 00000000..a1b78e3f --- /dev/null +++ b/src/Wallabag/ApiBundle/Controller/UserRestController.php | |||
@@ -0,0 +1,139 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use FOS\UserBundle\Event\UserEvent; | ||
6 | use FOS\UserBundle\FOSUserEvents; | ||
7 | use JMS\Serializer\SerializationContext; | ||
8 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | ||
9 | use Symfony\Component\HttpFoundation\Request; | ||
10 | use Symfony\Component\HttpFoundation\JsonResponse; | ||
11 | use Wallabag\UserBundle\Entity\User; | ||
12 | |||
13 | class UserRestController extends WallabagRestController | ||
14 | { | ||
15 | /** | ||
16 | * Retrieve current logged in user informations. | ||
17 | * | ||
18 | * @ApiDoc() | ||
19 | * | ||
20 | * @return JsonResponse | ||
21 | */ | ||
22 | public function getUserAction() | ||
23 | { | ||
24 | $this->validateAuthentication(); | ||
25 | |||
26 | return $this->sendUser($this->getUser()); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * Register an user. | ||
31 | * | ||
32 | * @ApiDoc( | ||
33 | * requirements={ | ||
34 | * {"name"="username", "dataType"="string", "required"=true, "description"="The user's username"}, | ||
35 | * {"name"="password", "dataType"="string", "required"=true, "description"="The user's password"}, | ||
36 | * {"name"="email", "dataType"="string", "required"=true, "description"="The user's email"} | ||
37 | * } | ||
38 | * ) | ||
39 | * | ||
40 | * @todo Make this method (or the whole API) accessible only through https | ||
41 | * | ||
42 | * @return JsonResponse | ||
43 | */ | ||
44 | public function putUserAction(Request $request) | ||
45 | { | ||
46 | if (!$this->container->getParameter('fosuser_registration')) { | ||
47 | $json = $this->get('serializer')->serialize(['error' => "Server doesn't allow registrations"], 'json'); | ||
48 | |||
49 | return (new JsonResponse())->setJson($json)->setStatusCode(403); | ||
50 | } | ||
51 | |||
52 | $userManager = $this->get('fos_user.user_manager'); | ||
53 | $user = $userManager->createUser(); | ||
54 | // enable created user by default | ||
55 | $user->setEnabled(true); | ||
56 | |||
57 | $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [ | ||
58 | 'csrf_protection' => false, | ||
59 | ]); | ||
60 | |||
61 | // simulate form submission | ||
62 | $form->submit([ | ||
63 | 'username' => $request->request->get('username'), | ||
64 | 'plainPassword' => [ | ||
65 | 'first' => $request->request->get('password'), | ||
66 | 'second' => $request->request->get('password'), | ||
67 | ], | ||
68 | 'email' => $request->request->get('email'), | ||
69 | ]); | ||
70 | |||
71 | if ($form->isSubmitted() && false === $form->isValid()) { | ||
72 | $view = $this->view($form, 400); | ||
73 | $view->setFormat('json'); | ||
74 | |||
75 | // handle errors in a more beautiful way than the default view | ||
76 | $data = json_decode($this->handleView($view)->getContent(), true)['children']; | ||
77 | $errors = []; | ||
78 | |||
79 | if (isset($data['username']['errors'])) { | ||
80 | $errors['username'] = $this->translateErrors($data['username']['errors']); | ||
81 | } | ||
82 | |||
83 | if (isset($data['email']['errors'])) { | ||
84 | $errors['email'] = $this->translateErrors($data['email']['errors']); | ||
85 | } | ||
86 | |||
87 | if (isset($data['plainPassword']['children']['first']['errors'])) { | ||
88 | $errors['password'] = $this->translateErrors($data['plainPassword']['children']['first']['errors']); | ||
89 | } | ||
90 | |||
91 | $json = $this->get('serializer')->serialize(['error' => $errors], 'json'); | ||
92 | |||
93 | return (new JsonResponse())->setJson($json)->setStatusCode(400); | ||
94 | } | ||
95 | |||
96 | $userManager->updateUser($user); | ||
97 | |||
98 | // dispatch a created event so the associated config will be created | ||
99 | $event = new UserEvent($user, $request); | ||
100 | $this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event); | ||
101 | |||
102 | return $this->sendUser($user); | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Send user response. | ||
107 | * | ||
108 | * @param User $user | ||
109 | * | ||
110 | * @return JsonResponse | ||
111 | */ | ||
112 | private function sendUser(User $user) | ||
113 | { | ||
114 | $json = $this->get('serializer')->serialize( | ||
115 | $user, | ||
116 | 'json', | ||
117 | SerializationContext::create()->setGroups(['user_api']) | ||
118 | ); | ||
119 | |||
120 | return (new JsonResponse())->setJson($json); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * Translate errors message. | ||
125 | * | ||
126 | * @param array $errors | ||
127 | * | ||
128 | * @return array | ||
129 | */ | ||
130 | private function translateErrors($errors) | ||
131 | { | ||
132 | $translatedErrors = []; | ||
133 | foreach ($errors as $error) { | ||
134 | $translatedErrors[] = $this->get('translator')->trans($error); | ||
135 | } | ||
136 | |||
137 | return $translatedErrors; | ||
138 | } | ||
139 | } | ||
diff --git a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml index 57d37f4b..c0283e71 100644 --- a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml +++ b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml | |||
@@ -17,3 +17,8 @@ misc: | |||
17 | type: rest | 17 | type: rest |
18 | resource: "WallabagApiBundle:WallabagRest" | 18 | resource: "WallabagApiBundle:WallabagRest" |
19 | name_prefix: api_ | 19 | name_prefix: api_ |
20 | |||
21 | user: | ||
22 | type: rest | ||
23 | resource: "WallabagApiBundle:UserRest" | ||
24 | name_prefix: api_ | ||
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index 0d9364f6..d9608246 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php | |||
@@ -499,20 +499,18 @@ class InstallCommand extends ContainerAwareCommand | |||
499 | $output = new BufferedOutput(); | 499 | $output = new BufferedOutput(); |
500 | $exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output); | 500 | $exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output); |
501 | 501 | ||
502 | // PDO does not always close the connection after Doctrine commands. | ||
503 | // See https://github.com/symfony/symfony/issues/11750. | ||
504 | $this->getContainer()->get('doctrine')->getManager()->getConnection()->close(); | ||
505 | |||
502 | if (0 !== $exitCode) { | 506 | if (0 !== $exitCode) { |
503 | $this->getApplication()->setAutoExit(true); | 507 | $this->getApplication()->setAutoExit(true); |
504 | 508 | ||
505 | $this->defaultOutput->writeln(''); | 509 | throw new \RuntimeException( |
506 | $this->defaultOutput->writeln('<error>The command "'.$command.'" generates some errors: </error>'); | 510 | 'The command "'.$command."\" generates some errors: \n\n" |
507 | $this->defaultOutput->writeln($output->fetch()); | 511 | .$output->fetch()); |
508 | |||
509 | die(); | ||
510 | } | 512 | } |
511 | 513 | ||
512 | // PDO does not always close the connection after Doctrine commands. | ||
513 | // See https://github.com/symfony/symfony/issues/11750. | ||
514 | $this->getContainer()->get('doctrine')->getManager()->getConnection()->close(); | ||
515 | |||
516 | return $this; | 514 | return $this; |
517 | } | 515 | } |
518 | 516 | ||
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index 1a80cc1a..0e61c642 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php | |||
@@ -250,7 +250,7 @@ class ConfigController extends Controller | |||
250 | case 'entries': | 250 | case 'entries': |
251 | // SQLite doesn't care about cascading remove, so we need to manually remove associated stuff | 251 | // SQLite doesn't care about cascading remove, so we need to manually remove associated stuff |
252 | // otherwise they won't be removed ... | 252 | // otherwise they won't be removed ... |
253 | if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) { | 253 | if ($this->get('doctrine')->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) { |
254 | $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId()); | 254 | $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId()); |
255 | } | 255 | } |
256 | 256 | ||
@@ -262,7 +262,7 @@ class ConfigController extends Controller | |||
262 | ->removeAllByUserId($this->getUser()->getId()); | 262 | ->removeAllByUserId($this->getUser()->getId()); |
263 | break; | 263 | break; |
264 | case 'archived': | 264 | case 'archived': |
265 | if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) { | 265 | if ($this->get('doctrine')->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) { |
266 | $this->removeAnnotationsForArchivedByUserId($this->getUser()->getId()); | 266 | $this->removeAnnotationsForArchivedByUserId($this->getUser()->getId()); |
267 | } | 267 | } |
268 | 268 | ||
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index 8d2ac6d4..fafa49f1 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php | |||
@@ -53,22 +53,17 @@ class EntryController extends Controller | |||
53 | 53 | ||
54 | /** | 54 | /** |
55 | * Fetch content and update entry. | 55 | * Fetch content and update entry. |
56 | * In case it fails, entry will return to avod loosing the data. | 56 | * In case it fails, $entry->getContent will return an error message. |
57 | * | 57 | * |
58 | * @param Entry $entry | 58 | * @param Entry $entry |
59 | * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded | 59 | * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded |
60 | * | ||
61 | * @return Entry | ||
62 | */ | 60 | */ |
63 | private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') | 61 | private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') |
64 | { | 62 | { |
65 | // put default title in case of fetching content failed | ||
66 | $entry->setTitle('No title found'); | ||
67 | |||
68 | $message = 'flashes.entry.notice.'.$prefixMessage; | 63 | $message = 'flashes.entry.notice.'.$prefixMessage; |
69 | 64 | ||
70 | try { | 65 | try { |
71 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); | 66 | $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); |
72 | } catch (\Exception $e) { | 67 | } catch (\Exception $e) { |
73 | $this->get('logger')->error('Error while saving an entry', [ | 68 | $this->get('logger')->error('Error while saving an entry', [ |
74 | 'exception' => $e, | 69 | 'exception' => $e, |
@@ -79,8 +74,6 @@ class EntryController extends Controller | |||
79 | } | 74 | } |
80 | 75 | ||
81 | $this->get('session')->getFlashBag()->add('notice', $message); | 76 | $this->get('session')->getFlashBag()->add('notice', $message); |
82 | |||
83 | return $entry; | ||
84 | } | 77 | } |
85 | 78 | ||
86 | /** | 79 | /** |
@@ -321,8 +314,7 @@ class EntryController extends Controller | |||
321 | 314 | ||
322 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); | 315 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); |
323 | 316 | ||
324 | $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries') | 317 | $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')->prepare($pagerAdapter); |
325 | ->prepare($pagerAdapter, $page); | ||
326 | 318 | ||
327 | try { | 319 | try { |
328 | $entries->setCurrentPage($page); | 320 | $entries->setCurrentPage($page); |
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php index fb6a720b..9422bae4 100644 --- a/src/Wallabag/CoreBundle/Controller/TagController.php +++ b/src/Wallabag/CoreBundle/Controller/TagController.php | |||
@@ -70,7 +70,7 @@ class TagController extends Controller | |||
70 | $em->flush(); | 70 | $em->flush(); |
71 | } | 71 | } |
72 | 72 | ||
73 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer')); | 73 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'), '', true); |
74 | 74 | ||
75 | return $this->redirect($redirectUrl); | 75 | return $this->redirect($redirectUrl); |
76 | } | 76 | } |
@@ -125,8 +125,7 @@ class TagController extends Controller | |||
125 | 125 | ||
126 | $pagerAdapter = new ArrayAdapter($entriesByTag); | 126 | $pagerAdapter = new ArrayAdapter($entriesByTag); |
127 | 127 | ||
128 | $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries') | 128 | $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')->prepare($pagerAdapter); |
129 | ->prepare($pagerAdapter, $page); | ||
130 | 129 | ||
131 | try { | 130 | try { |
132 | $entries->setCurrentPage($page); | 131 | $entries->setCurrentPage($page); |
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php index 75b37729..8b5b5744 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php | |||
@@ -41,6 +41,8 @@ class Configuration implements ConfigurationInterface | |||
41 | ->end() | 41 | ->end() |
42 | ->scalarNode('fetching_error_message') | 42 | ->scalarNode('fetching_error_message') |
43 | ->end() | 43 | ->end() |
44 | ->scalarNode('fetching_error_message_title') | ||
45 | ->end() | ||
44 | ->scalarNode('action_mark_as_read') | 46 | ->scalarNode('action_mark_as_read') |
45 | ->defaultValue(1) | 47 | ->defaultValue(1) |
46 | ->end() | 48 | ->end() |
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php index c075c19f..a2a703cb 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php | |||
@@ -26,6 +26,7 @@ class WallabagCoreExtension extends Extension | |||
26 | $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']); | 26 | $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']); |
27 | $container->setParameter('wallabag_core.list_mode', $config['list_mode']); | 27 | $container->setParameter('wallabag_core.list_mode', $config['list_mode']); |
28 | $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']); | 28 | $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']); |
29 | $container->setParameter('wallabag_core.fetching_error_message_title', $config['fetching_error_message_title']); | ||
29 | $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']); | 30 | $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']); |
30 | 31 | ||
31 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | 32 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php index 08a67c34..9a7dd4e7 100644 --- a/src/Wallabag/CoreBundle/Entity/Entry.php +++ b/src/Wallabag/CoreBundle/Entity/Entry.php | |||
@@ -550,7 +550,7 @@ class Entry | |||
550 | } | 550 | } |
551 | 551 | ||
552 | /** | 552 | /** |
553 | * @return ArrayCollection<Tag> | 553 | * @return ArrayCollection |
554 | */ | 554 | */ |
555 | public function getTags() | 555 | public function getTags() |
556 | { | 556 | { |
@@ -685,7 +685,7 @@ class Entry | |||
685 | } | 685 | } |
686 | 686 | ||
687 | /** | 687 | /** |
688 | * @return int | 688 | * @return string |
689 | */ | 689 | */ |
690 | public function getHttpStatus() | 690 | public function getHttpStatus() |
691 | { | 691 | { |
@@ -693,7 +693,7 @@ class Entry | |||
693 | } | 693 | } |
694 | 694 | ||
695 | /** | 695 | /** |
696 | * @param int $httpStatus | 696 | * @param string $httpStatus |
697 | * | 697 | * |
698 | * @return Entry | 698 | * @return Entry |
699 | */ | 699 | */ |
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php index 3b4c4cf9..5e6af8cc 100644 --- a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php +++ b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php | |||
@@ -45,9 +45,8 @@ class SQLiteCascadeDeleteSubscriber implements EventSubscriber | |||
45 | public function preRemove(LifecycleEventArgs $args) | 45 | public function preRemove(LifecycleEventArgs $args) |
46 | { | 46 | { |
47 | $entity = $args->getEntity(); | 47 | $entity = $args->getEntity(); |
48 | 48 | if (!$this->doctrine->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform | |
49 | if (!$this->doctrine->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver || | 49 | || !$entity instanceof Entry) { |
50 | !$entity instanceof Entry) { | ||
51 | return; | 50 | return; |
52 | } | 51 | } |
53 | 52 | ||
diff --git a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php index c712bb26..1c56fa9f 100644 --- a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php +++ b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php | |||
@@ -5,7 +5,6 @@ namespace Wallabag\CoreBundle\GuzzleSiteAuthenticator; | |||
5 | use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig; | 5 | use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig; |
6 | use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder; | 6 | use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder; |
7 | use Graby\SiteConfig\ConfigBuilder; | 7 | use Graby\SiteConfig\ConfigBuilder; |
8 | use OutOfRangeException; | ||
9 | use Psr\Log\LoggerInterface; | 8 | use Psr\Log\LoggerInterface; |
10 | 9 | ||
11 | class GrabySiteConfigBuilder implements SiteConfigBuilder | 10 | class GrabySiteConfigBuilder implements SiteConfigBuilder |
@@ -38,13 +37,7 @@ class GrabySiteConfigBuilder implements SiteConfigBuilder | |||
38 | } | 37 | } |
39 | 38 | ||
40 | /** | 39 | /** |
41 | * Builds the SiteConfig for a host. | 40 | * {@inheritdoc} |
42 | * | ||
43 | * @param string $host The "www." prefix is ignored | ||
44 | * | ||
45 | * @return SiteConfig | ||
46 | * | ||
47 | * @throws OutOfRangeException If there is no config for $host | ||
48 | */ | 41 | */ |
49 | public function buildForHost($host) | 42 | public function buildForHost($host) |
50 | { | 43 | { |
diff --git a/src/Wallabag/CoreBundle/Helper/ContentProxy.php b/src/Wallabag/CoreBundle/Helper/ContentProxy.php index 4b3e6fbb..bfaa1976 100644 --- a/src/Wallabag/CoreBundle/Helper/ContentProxy.php +++ b/src/Wallabag/CoreBundle/Helper/ContentProxy.php | |||
@@ -31,22 +31,20 @@ class ContentProxy | |||
31 | } | 31 | } |
32 | 32 | ||
33 | /** | 33 | /** |
34 | * Fetch content using graby and hydrate given entry with results information. | 34 | * Update entry using either fetched or provided content. |
35 | * In case we couldn't find content, we'll try to use Open Graph data. | ||
36 | * | 35 | * |
37 | * We can also force the content, in case of an import from the v1 for example, so the function won't | 36 | * @param Entry $entry Entry to update |
38 | * fetch the content from the website but rather use information given with the $content parameter. | 37 | * @param string $url Url of the content |
39 | * | 38 | * @param array $content Array with content provided for import with AT LEAST keys title, html, url to skip the fetchContent from the url |
40 | * @param Entry $entry Entry to update | 39 | * @param bool $disableContentUpdate Whether to skip trying to fetch content using Graby |
41 | * @param string $url Url to grab content for | ||
42 | * @param array $content An array with AT LEAST keys title, html, url, language & content_type to skip the fetchContent from the url | ||
43 | * | ||
44 | * @return Entry | ||
45 | */ | 40 | */ |
46 | public function updateEntry(Entry $entry, $url, array $content = []) | 41 | public function updateEntry(Entry $entry, $url, array $content = [], $disableContentUpdate = false) |
47 | { | 42 | { |
48 | // do we have to fetch the content or the provided one is ok? | 43 | if (!empty($content['html'])) { |
49 | if (empty($content) || false === $this->validateContent($content)) { | 44 | $content['html'] = $this->graby->cleanupHtml($content['html'], $url); |
45 | } | ||
46 | |||
47 | if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) { | ||
50 | $fetchedContent = $this->graby->fetchContent($url); | 48 | $fetchedContent = $this->graby->fetchContent($url); |
51 | 49 | ||
52 | // when content is imported, we have information in $content | 50 | // when content is imported, we have information in $content |
@@ -56,8 +54,24 @@ class ContentProxy | |||
56 | } | 54 | } |
57 | } | 55 | } |
58 | 56 | ||
57 | // be sure to keep the url in case of error | ||
58 | // so we'll be able to refetch it in the future | ||
59 | $content['url'] = !empty($content['url']) ? $content['url'] : $url; | ||
60 | |||
61 | $this->stockEntry($entry, $content); | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * Stock entry with fetched or imported content. | ||
66 | * Will fall back to OpenGraph data if available. | ||
67 | * | ||
68 | * @param Entry $entry Entry to stock | ||
69 | * @param array $content Array with at least title, url & html | ||
70 | */ | ||
71 | private function stockEntry(Entry $entry, array $content) | ||
72 | { | ||
59 | $title = $content['title']; | 73 | $title = $content['title']; |
60 | if (!$title && isset($content['open_graph']['og_title'])) { | 74 | if (!$title && !empty($content['open_graph']['og_title'])) { |
61 | $title = $content['open_graph']['og_title']; | 75 | $title = $content['open_graph']['og_title']; |
62 | } | 76 | } |
63 | 77 | ||
@@ -65,19 +79,30 @@ class ContentProxy | |||
65 | if (false === $html) { | 79 | if (false === $html) { |
66 | $html = $this->fetchingErrorMessage; | 80 | $html = $this->fetchingErrorMessage; |
67 | 81 | ||
68 | if (isset($content['open_graph']['og_description'])) { | 82 | if (!empty($content['open_graph']['og_description'])) { |
69 | $html .= '<p><i>But we found a short description: </i></p>'; | 83 | $html .= '<p><i>But we found a short description: </i></p>'; |
70 | $html .= $content['open_graph']['og_description']; | 84 | $html .= $content['open_graph']['og_description']; |
71 | } | 85 | } |
72 | } | 86 | } |
73 | 87 | ||
74 | $entry->setUrl($content['url'] ?: $url); | 88 | $entry->setUrl($content['url']); |
75 | $entry->setTitle($title); | 89 | $entry->setTitle($title); |
76 | $entry->setContent($html); | 90 | $entry->setContent($html); |
77 | $entry->setHttpStatus(isset($content['status']) ? $content['status'] : ''); | 91 | $entry->setHttpStatus(isset($content['status']) ? $content['status'] : ''); |
78 | 92 | ||
79 | if (isset($content['date']) && null !== $content['date'] && '' !== $content['date']) { | 93 | if (!empty($content['date'])) { |
80 | $entry->setPublishedAt(new \DateTime($content['date'])); | 94 | $date = $content['date']; |
95 | |||
96 | // is it a timestamp? | ||
97 | if (filter_var($date, FILTER_VALIDATE_INT) !== false) { | ||
98 | $date = '@'.$content['date']; | ||
99 | } | ||
100 | |||
101 | try { | ||
102 | $entry->setPublishedAt(new \DateTime($date)); | ||
103 | } catch (\Exception $e) { | ||
104 | $this->logger->warning('Error while defining date', ['e' => $e, 'url' => $content['url'], 'date' => $content['date']]); | ||
105 | } | ||
81 | } | 106 | } |
82 | 107 | ||
83 | if (!empty($content['authors'])) { | 108 | if (!empty($content['authors'])) { |
@@ -97,12 +122,12 @@ class ContentProxy | |||
97 | $entry->setDomainName($domainName); | 122 | $entry->setDomainName($domainName); |
98 | } | 123 | } |
99 | 124 | ||
100 | if (isset($content['open_graph']['og_image']) && $content['open_graph']['og_image']) { | 125 | if (!empty($content['open_graph']['og_image'])) { |
101 | $entry->setPreviewPicture($content['open_graph']['og_image']); | 126 | $entry->setPreviewPicture($content['open_graph']['og_image']); |
102 | } | 127 | } |
103 | 128 | ||
104 | // if content is an image define as a preview too | 129 | // if content is an image define as a preview too |
105 | if (isset($content['content_type']) && in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) { | 130 | if (!empty($content['content_type']) && in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) { |
106 | $entry->setPreviewPicture($content['url']); | 131 | $entry->setPreviewPicture($content['url']); |
107 | } | 132 | } |
108 | 133 | ||
@@ -110,17 +135,14 @@ class ContentProxy | |||
110 | $this->tagger->tag($entry); | 135 | $this->tagger->tag($entry); |
111 | } catch (\Exception $e) { | 136 | } catch (\Exception $e) { |
112 | $this->logger->error('Error while trying to automatically tag an entry.', [ | 137 | $this->logger->error('Error while trying to automatically tag an entry.', [ |
113 | 'entry_url' => $url, | 138 | 'entry_url' => $content['url'], |
114 | 'error_msg' => $e->getMessage(), | 139 | 'error_msg' => $e->getMessage(), |
115 | ]); | 140 | ]); |
116 | } | 141 | } |
117 | |||
118 | return $entry; | ||
119 | } | 142 | } |
120 | 143 | ||
121 | /** | 144 | /** |
122 | * Validate that the given content as enough value to be used | 145 | * Validate that the given content has at least a title, an html and a url. |
123 | * instead of fetch the content from the url. | ||
124 | * | 146 | * |
125 | * @param array $content | 147 | * @param array $content |
126 | * | 148 | * |
@@ -128,6 +150,6 @@ class ContentProxy | |||
128 | */ | 150 | */ |
129 | private function validateContent(array $content) | 151 | private function validateContent(array $content) |
130 | { | 152 | { |
131 | return isset($content['title']) && isset($content['html']) && isset($content['url']) && isset($content['language']) && isset($content['content_type']); | 153 | return !empty($content['title']) && !empty($content['html']) && !empty($content['url']); |
132 | } | 154 | } |
133 | } | 155 | } |
diff --git a/src/Wallabag/CoreBundle/Helper/DownloadImages.php b/src/Wallabag/CoreBundle/Helper/DownloadImages.php index 0d330d2a..54e23a05 100644 --- a/src/Wallabag/CoreBundle/Helper/DownloadImages.php +++ b/src/Wallabag/CoreBundle/Helper/DownloadImages.php | |||
@@ -54,7 +54,7 @@ class DownloadImages | |||
54 | $crawler = new Crawler($html); | 54 | $crawler = new Crawler($html); |
55 | $result = $crawler | 55 | $result = $crawler |
56 | ->filterXpath('//img') | 56 | ->filterXpath('//img') |
57 | ->extract(array('src')); | 57 | ->extract(['src']); |
58 | 58 | ||
59 | $relativePath = $this->getRelativePath($entryId); | 59 | $relativePath = $this->getRelativePath($entryId); |
60 | 60 | ||
@@ -66,6 +66,11 @@ class DownloadImages | |||
66 | continue; | 66 | continue; |
67 | } | 67 | } |
68 | 68 | ||
69 | // if image contains "&" and we can't find it in the html it might be because it's encoded as & | ||
70 | if (false !== stripos($image, '&') && false === stripos($html, $image)) { | ||
71 | $image = str_replace('&', '&', $image); | ||
72 | } | ||
73 | |||
69 | $html = str_replace($image, $imagePath, $html); | 74 | $html = str_replace($image, $imagePath, $html); |
70 | } | 75 | } |
71 | 76 | ||
@@ -114,7 +119,7 @@ class DownloadImages | |||
114 | $ext = $this->mimeGuesser->guess($res->getHeader('content-type')); | 119 | $ext = $this->mimeGuesser->guess($res->getHeader('content-type')); |
115 | $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); | 120 | $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); |
116 | if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) { | 121 | if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) { |
117 | $this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping '.$imagePath); | 122 | $this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping: '.$imagePath); |
118 | 123 | ||
119 | return false; | 124 | return false; |
120 | } | 125 | } |
diff --git a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php index 7d3798b9..df579ebd 100644 --- a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php +++ b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php | |||
@@ -20,16 +20,15 @@ class PreparePagerForEntries | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @param AdapterInterface $adapter | 22 | * @param AdapterInterface $adapter |
23 | * @param int $page | ||
24 | * | 23 | * |
25 | * @return null|Pagerfanta | 24 | * @return null|Pagerfanta |
26 | */ | 25 | */ |
27 | public function prepare(AdapterInterface $adapter, $page = 1) | 26 | public function prepare(AdapterInterface $adapter) |
28 | { | 27 | { |
29 | $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; | 28 | $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; |
30 | 29 | ||
31 | if (null === $user || !is_object($user)) { | 30 | if (null === $user || !is_object($user)) { |
32 | return null; | 31 | return; |
33 | } | 32 | } |
34 | 33 | ||
35 | $entries = new Pagerfanta($adapter); | 34 | $entries = new Pagerfanta($adapter); |
diff --git a/src/Wallabag/CoreBundle/Helper/Redirect.php b/src/Wallabag/CoreBundle/Helper/Redirect.php index f78b7fe0..abc84d08 100644 --- a/src/Wallabag/CoreBundle/Helper/Redirect.php +++ b/src/Wallabag/CoreBundle/Helper/Redirect.php | |||
@@ -21,12 +21,13 @@ class Redirect | |||
21 | } | 21 | } |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * @param string $url URL to redirect | 24 | * @param string $url URL to redirect |
25 | * @param string $fallback Fallback URL if $url is null | 25 | * @param string $fallback Fallback URL if $url is null |
26 | * @param bool $ignoreActionMarkAsRead Ignore configured action when mark as read | ||
26 | * | 27 | * |
27 | * @return string | 28 | * @return string |
28 | */ | 29 | */ |
29 | public function to($url, $fallback = '') | 30 | public function to($url, $fallback = '', $ignoreActionMarkAsRead = false) |
30 | { | 31 | { |
31 | $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; | 32 | $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null; |
32 | 33 | ||
@@ -34,7 +35,8 @@ class Redirect | |||
34 | return $url; | 35 | return $url; |
35 | } | 36 | } |
36 | 37 | ||
37 | if (Config::REDIRECT_TO_HOMEPAGE === $user->getConfig()->getActionMarkAsRead()) { | 38 | if (!$ignoreActionMarkAsRead && |
39 | Config::REDIRECT_TO_HOMEPAGE === $user->getConfig()->getActionMarkAsRead()) { | ||
38 | return $this->router->generate('homepage'); | 40 | return $this->router->generate('homepage'); |
39 | } | 41 | } |
40 | 42 | ||
diff --git a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php index add27db2..509d0dec 100644 --- a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php +++ b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php | |||
@@ -15,6 +15,7 @@ class RuleBasedTagger | |||
15 | private $rulerz; | 15 | private $rulerz; |
16 | private $tagRepository; | 16 | private $tagRepository; |
17 | private $entryRepository; | 17 | private $entryRepository; |
18 | private $logger; | ||
18 | 19 | ||
19 | public function __construct(RulerZ $rulerz, TagRepository $tagRepository, EntryRepository $entryRepository, LoggerInterface $logger) | 20 | public function __construct(RulerZ $rulerz, TagRepository $tagRepository, EntryRepository $entryRepository, LoggerInterface $logger) |
20 | { | 21 | { |
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index a68b2fdc..a9b0d2d5 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml | |||
@@ -41,6 +41,7 @@ services: | |||
41 | arguments: | 41 | arguments: |
42 | - | 42 | - |
43 | error_message: '%wallabag_core.fetching_error_message%' | 43 | error_message: '%wallabag_core.fetching_error_message%' |
44 | error_message_title: '%wallabag_core.fetching_error_message_title%' | ||
44 | - "@wallabag_core.guzzle.http_client" | 45 | - "@wallabag_core.guzzle.http_client" |
45 | - "@wallabag_core.graby.config_builder" | 46 | - "@wallabag_core.graby.config_builder" |
46 | calls: | 47 | calls: |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig index 174b7b54..b64e1436 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig | |||
@@ -1,18 +1,28 @@ | |||
1 | <div class="card"> | 1 | <div class="card-stacked"> |
2 | <div class="card-stacked"> | 2 | <div class="preview">{% if entry.previewPicture is not null %}<img src="{{ entry.previewPicture }}" />{% endif %}</div> |
3 | <div class="card-content"> | 3 | <div class="card-content"> |
4 | <span class="card-title dot-ellipsis dot-resize-update"> | 4 | <span class="card-title dot-ellipsis dot-resize-update"> |
5 | <a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title | striptags | e('html_attr') }}"> | 5 | <a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title | striptags | e('html_attr') }}"> |
6 | {{ entry.title| striptags | truncate(120, true, '…') | raw }} | 6 | {{ entry.title| striptags | truncate(120, true, '…') | raw }} |
7 | </a> | 7 | </a> |
8 | </span> | 8 | </span> |
9 | <ul class="tools-list right"> | 9 | |
10 | <li> | 10 | <div class="metadata"> |
11 | <a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}redo{% endif %}</i></a> | 11 | <a href="{{ entry.url|e }}" class="grey-text domain" target="_blank" title="{{ entry.domainName|removeWww }}"> |
12 | <a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool grey-text" href="{{ path('star_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isStarred == 0 %}star_border{% else %}star{% endif %}</i></a> | 12 | <span>{{ entry.domainName|removeWww }}</span> |
13 | <a title="{{ 'entry.list.delete'|trans }}" onclick="return confirm('{{ 'entry.confirm.delete'|trans|escape('js') }}')" class="tool grey-text delete" href="{{ path('delete_entry', { 'id': entry.id }) }}"><i class="material-icons">delete</i></a> | 13 | </a> |
14 | </li> | 14 | {% for tag in entry.tags | slice(0, 3) %} |
15 | </ul> | 15 | <span class="chip hide-on-med-and-down"> |
16 | <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a> | ||
17 | </span> | ||
18 | {% endfor %} | ||
16 | </div> | 19 | </div> |
17 | </div> | 20 | </div> |
21 | <ul class="tools-list hide-on-small-only"> | ||
22 | <li> | ||
23 | <a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}redo{% endif %}</i></a> | ||
24 | <a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool grey-text" href="{{ path('star_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isStarred == 0 %}star_border{% else %}star{% endif %}</i></a> | ||
25 | <a title="{{ 'entry.list.delete'|trans }}" onclick="return confirm('{{ 'entry.confirm.delete'|trans|escape('js') }}')" class="tool grey-text delete" href="{{ path('delete_entry', { 'id': entry.id }) }}"><i class="material-icons">delete</i></a> | ||
26 | </li> | ||
27 | </ul> | ||
18 | </div> | 28 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig index b2d91c9c..6f657b18 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig | |||
@@ -24,9 +24,9 @@ | |||
24 | </div> | 24 | </div> |
25 | 25 | ||
26 | <br /> | 26 | <br /> |
27 | <ul class="row data"> | 27 | <ul class="{% if listMode == 1 %}collection{% else %}row data{% endif %}"> |
28 | {% for entry in entries %} | 28 | {% for entry in entries %} |
29 | <li id="entry-{{ entry.id|e }}" class="col {% if listMode == 0 %}l3 m6{% endif %} s12"> | 29 | <li id="entry-{{ entry.id|e }}" class="col {% if listMode == 0 %}l3 m6{% else %}collection-item{% endif %} s12"> |
30 | {% if listMode == 1 %} | 30 | {% if listMode == 1 %} |
31 | {% include "@WallabagCore/themes/material/Entry/_card_list.html.twig" with {'entry': entry} only %} | 31 | {% include "@WallabagCore/themes/material/Entry/_card_list.html.twig" with {'entry': entry} only %} |
32 | {% elseif entry.previewPicture is null %} | 32 | {% elseif entry.previewPicture is null %} |
diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php index ce72837a..5f1ab0af 100644 --- a/src/Wallabag/ImportBundle/Command/ImportCommand.php +++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php | |||
@@ -5,6 +5,7 @@ namespace Wallabag\ImportBundle\Command; | |||
5 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; | 5 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; |
6 | use Symfony\Component\Config\Definition\Exception\Exception; | 6 | use Symfony\Component\Config\Definition\Exception\Exception; |
7 | use Symfony\Component\Console\Input\InputArgument; | 7 | use Symfony\Component\Console\Input\InputArgument; |
8 | use Symfony\Component\Console\Input\InputOption; | ||
8 | use Symfony\Component\Console\Input\InputInterface; | 9 | use Symfony\Component\Console\Input\InputInterface; |
9 | use Symfony\Component\Console\Output\OutputInterface; | 10 | use Symfony\Component\Console\Output\OutputInterface; |
10 | 11 | ||
@@ -17,9 +18,10 @@ class ImportCommand extends ContainerAwareCommand | |||
17 | ->setDescription('Import entries from a JSON export') | 18 | ->setDescription('Import entries from a JSON export') |
18 | ->addArgument('username', InputArgument::REQUIRED, 'User to populate') | 19 | ->addArgument('username', InputArgument::REQUIRED, 'User to populate') |
19 | ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') | 20 | ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') |
20 | ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, readability, firefox or chrome', 'v1') | 21 | ->addOption('importer', null, InputOption::VALUE_OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, readability, firefox or chrome', 'v1') |
21 | ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false) | 22 | ->addOption('markAsRead', null, InputOption::VALUE_OPTIONAL, 'Mark all entries as read', false) |
22 | ->addOption('useUserId', null, InputArgument::OPTIONAL, 'Use user id instead of username to find account', false) | 23 | ->addOption('useUserId', null, InputOption::VALUE_NONE, 'Use user id instead of username to find account') |
24 | ->addOption('disableContentUpdate', null, InputOption::VALUE_NONE, 'Disable fetching updated content from URL') | ||
23 | ; | 25 | ; |
24 | } | 26 | } |
25 | 27 | ||
@@ -69,6 +71,7 @@ class ImportCommand extends ContainerAwareCommand | |||
69 | } | 71 | } |
70 | 72 | ||
71 | $import->setMarkAsRead($input->getOption('markAsRead')); | 73 | $import->setMarkAsRead($input->getOption('markAsRead')); |
74 | $import->setDisableContentUpdate($input->getOption('disableContentUpdate')); | ||
72 | $import->setUser($user); | 75 | $import->setUser($user); |
73 | 76 | ||
74 | $res = $import | 77 | $res = $import |
diff --git a/src/Wallabag/ImportBundle/Import/AbstractImport.php b/src/Wallabag/ImportBundle/Import/AbstractImport.php index a61388c0..9b624296 100644 --- a/src/Wallabag/ImportBundle/Import/AbstractImport.php +++ b/src/Wallabag/ImportBundle/Import/AbstractImport.php | |||
@@ -24,6 +24,7 @@ abstract class AbstractImport implements ImportInterface | |||
24 | protected $producer; | 24 | protected $producer; |
25 | protected $user; | 25 | protected $user; |
26 | protected $markAsRead; | 26 | protected $markAsRead; |
27 | protected $disableContentUpdate = false; | ||
27 | protected $skippedEntries = 0; | 28 | protected $skippedEntries = 0; |
28 | protected $importedEntries = 0; | 29 | protected $importedEntries = 0; |
29 | protected $queuedEntries = 0; | 30 | protected $queuedEntries = 0; |
@@ -85,21 +86,34 @@ abstract class AbstractImport implements ImportInterface | |||
85 | } | 86 | } |
86 | 87 | ||
87 | /** | 88 | /** |
89 | * Set whether articles should be fetched for updated content. | ||
90 | * | ||
91 | * @param bool $disableContentUpdate | ||
92 | */ | ||
93 | public function setDisableContentUpdate($disableContentUpdate) | ||
94 | { | ||
95 | $this->disableContentUpdate = $disableContentUpdate; | ||
96 | |||
97 | return $this; | ||
98 | } | ||
99 | |||
100 | /** | ||
88 | * Fetch content from the ContentProxy (using graby). | 101 | * Fetch content from the ContentProxy (using graby). |
89 | * If it fails return the given entry to be saved in all case (to avoid user to loose the content). | 102 | * If it fails return the given entry to be saved in all case (to avoid user to loose the content). |
90 | * | 103 | * |
91 | * @param Entry $entry Entry to update | 104 | * @param Entry $entry Entry to update |
92 | * @param string $url Url to grab content for | 105 | * @param string $url Url to grab content for |
93 | * @param array $content An array with AT LEAST keys title, html, url, language & content_type to skip the fetchContent from the url | 106 | * @param array $content An array with AT LEAST keys title, html, url, language & content_type to skip the fetchContent from the url |
94 | * | ||
95 | * @return Entry | ||
96 | */ | 107 | */ |
97 | protected function fetchContent(Entry $entry, $url, array $content = []) | 108 | protected function fetchContent(Entry $entry, $url, array $content = []) |
98 | { | 109 | { |
99 | try { | 110 | try { |
100 | return $this->contentProxy->updateEntry($entry, $url, $content); | 111 | $this->contentProxy->updateEntry($entry, $url, $content, $this->disableContentUpdate); |
101 | } catch (\Exception $e) { | 112 | } catch (\Exception $e) { |
102 | return $entry; | 113 | $this->logger->error('Error trying to import an entry.', [ |
114 | 'entry_url' => $url, | ||
115 | 'error_msg' => $e->getMessage(), | ||
116 | ]); | ||
103 | } | 117 | } |
104 | } | 118 | } |
105 | 119 | ||
diff --git a/src/Wallabag/ImportBundle/Import/BrowserImport.php b/src/Wallabag/ImportBundle/Import/BrowserImport.php index ef0eeb7e..71e65e59 100644 --- a/src/Wallabag/ImportBundle/Import/BrowserImport.php +++ b/src/Wallabag/ImportBundle/Import/BrowserImport.php | |||
@@ -201,7 +201,7 @@ abstract class BrowserImport extends AbstractImport | |||
201 | $entry->setTitle($data['title']); | 201 | $entry->setTitle($data['title']); |
202 | 202 | ||
203 | // update entry with content (in case fetching failed, the given entry will be return) | 203 | // update entry with content (in case fetching failed, the given entry will be return) |
204 | $entry = $this->fetchContent($entry, $data['url'], $data); | 204 | $this->fetchContent($entry, $data['url'], $data); |
205 | 205 | ||
206 | if (array_key_exists('tags', $data)) { | 206 | if (array_key_exists('tags', $data)) { |
207 | $this->tagsAssigner->assignTagsToEntry( | 207 | $this->tagsAssigner->assignTagsToEntry( |
diff --git a/src/Wallabag/ImportBundle/Import/InstapaperImport.php b/src/Wallabag/ImportBundle/Import/InstapaperImport.php index 70a53f1a..3aa12f6f 100644 --- a/src/Wallabag/ImportBundle/Import/InstapaperImport.php +++ b/src/Wallabag/ImportBundle/Import/InstapaperImport.php | |||
@@ -68,6 +68,14 @@ class InstapaperImport extends AbstractImport | |||
68 | continue; | 68 | continue; |
69 | } | 69 | } |
70 | 70 | ||
71 | // last element in the csv is the folder where the content belong | ||
72 | // BUT it can also be the status (since status = folder in Instapaper) | ||
73 | // and we don't want archive, unread & starred to become a tag | ||
74 | $tags = null; | ||
75 | if (false === in_array($data[3], ['Archive', 'Unread', 'Starred'])) { | ||
76 | $tags = [$data[3]]; | ||
77 | } | ||
78 | |||
71 | $entries[] = [ | 79 | $entries[] = [ |
72 | 'url' => $data[0], | 80 | 'url' => $data[0], |
73 | 'title' => $data[1], | 81 | 'title' => $data[1], |
@@ -75,6 +83,7 @@ class InstapaperImport extends AbstractImport | |||
75 | 'is_archived' => $data[3] === 'Archive' || $data[3] === 'Starred', | 83 | 'is_archived' => $data[3] === 'Archive' || $data[3] === 'Starred', |
76 | 'is_starred' => $data[3] === 'Starred', | 84 | 'is_starred' => $data[3] === 'Starred', |
77 | 'html' => false, | 85 | 'html' => false, |
86 | 'tags' => $tags, | ||
78 | ]; | 87 | ]; |
79 | } | 88 | } |
80 | fclose($handle); | 89 | fclose($handle); |
@@ -116,7 +125,15 @@ class InstapaperImport extends AbstractImport | |||
116 | $entry->setTitle($importedEntry['title']); | 125 | $entry->setTitle($importedEntry['title']); |
117 | 126 | ||
118 | // update entry with content (in case fetching failed, the given entry will be return) | 127 | // update entry with content (in case fetching failed, the given entry will be return) |
119 | $entry = $this->fetchContent($entry, $importedEntry['url'], $importedEntry); | 128 | $this->fetchContent($entry, $importedEntry['url'], $importedEntry); |
129 | |||
130 | if (!empty($importedEntry['tags'])) { | ||
131 | $this->tagsAssigner->assignTagsToEntry( | ||
132 | $entry, | ||
133 | $importedEntry['tags'], | ||
134 | $this->em->getUnitOfWork()->getScheduledEntityInsertions() | ||
135 | ); | ||
136 | } | ||
120 | 137 | ||
121 | $entry->setArchived($importedEntry['is_archived']); | 138 | $entry->setArchived($importedEntry['is_archived']); |
122 | $entry->setStarred($importedEntry['is_starred']); | 139 | $entry->setStarred($importedEntry['is_starred']); |
diff --git a/src/Wallabag/ImportBundle/Import/PinboardImport.php b/src/Wallabag/ImportBundle/Import/PinboardImport.php index 489b9257..110b0464 100644 --- a/src/Wallabag/ImportBundle/Import/PinboardImport.php +++ b/src/Wallabag/ImportBundle/Import/PinboardImport.php | |||
@@ -109,7 +109,7 @@ class PinboardImport extends AbstractImport | |||
109 | $entry->setTitle($data['title']); | 109 | $entry->setTitle($data['title']); |
110 | 110 | ||
111 | // update entry with content (in case fetching failed, the given entry will be return) | 111 | // update entry with content (in case fetching failed, the given entry will be return) |
112 | $entry = $this->fetchContent($entry, $data['url'], $data); | 112 | $this->fetchContent($entry, $data['url'], $data); |
113 | 113 | ||
114 | if (!empty($data['tags'])) { | 114 | if (!empty($data['tags'])) { |
115 | $this->tagsAssigner->assignTagsToEntry( | 115 | $this->tagsAssigner->assignTagsToEntry( |
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 8835161b..c1d5b6da 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php | |||
@@ -192,7 +192,7 @@ class PocketImport extends AbstractImport | |||
192 | $entry->setUrl($url); | 192 | $entry->setUrl($url); |
193 | 193 | ||
194 | // update entry with content (in case fetching failed, the given entry will be return) | 194 | // update entry with content (in case fetching failed, the given entry will be return) |
195 | $entry = $this->fetchContent($entry, $url); | 195 | $this->fetchContent($entry, $url); |
196 | 196 | ||
197 | // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted | 197 | // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted |
198 | $entry->setArchived($importedEntry['status'] == 1 || $this->markAsRead); | 198 | $entry->setArchived($importedEntry['status'] == 1 || $this->markAsRead); |
diff --git a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php index de320d23..002b27f4 100644 --- a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php +++ b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php | |||
@@ -109,7 +109,7 @@ class ReadabilityImport extends AbstractImport | |||
109 | $entry->setTitle($data['title']); | 109 | $entry->setTitle($data['title']); |
110 | 110 | ||
111 | // update entry with content (in case fetching failed, the given entry will be return) | 111 | // update entry with content (in case fetching failed, the given entry will be return) |
112 | $entry = $this->fetchContent($entry, $data['url'], $data); | 112 | $this->fetchContent($entry, $data['url'], $data); |
113 | 113 | ||
114 | $entry->setArchived($data['is_archived']); | 114 | $entry->setArchived($data['is_archived']); |
115 | $entry->setStarred($data['is_starred']); | 115 | $entry->setStarred($data['is_starred']); |
diff --git a/src/Wallabag/ImportBundle/Import/WallabagImport.php b/src/Wallabag/ImportBundle/Import/WallabagImport.php index 0e5382cf..c64ccd64 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagImport.php +++ b/src/Wallabag/ImportBundle/Import/WallabagImport.php | |||
@@ -108,7 +108,7 @@ abstract class WallabagImport extends AbstractImport | |||
108 | $entry->setTitle($data['title']); | 108 | $entry->setTitle($data['title']); |
109 | 109 | ||
110 | // update entry with content (in case fetching failed, the given entry will be return) | 110 | // update entry with content (in case fetching failed, the given entry will be return) |
111 | $entry = $this->fetchContent($entry, $data['url'], $data); | 111 | $this->fetchContent($entry, $data['url'], $data); |
112 | 112 | ||
113 | if (array_key_exists('tags', $data)) { | 113 | if (array_key_exists('tags', $data)) { |
114 | $this->tagsAssigner->assignTagsToEntry( | 114 | $this->tagsAssigner->assignTagsToEntry( |
diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php index 59e3ce02..1f0df646 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php | |||
@@ -4,6 +4,17 @@ namespace Wallabag\ImportBundle\Import; | |||
4 | 4 | ||
5 | class WallabagV1Import extends WallabagImport | 5 | class WallabagV1Import extends WallabagImport |
6 | { | 6 | { |
7 | protected $fetchingErrorMessage; | ||
8 | protected $fetchingErrorMessageTitle; | ||
9 | |||
10 | public function __construct($em, $contentProxy, $tagsAssigner, $eventDispatcher, $fetchingErrorMessageTitle, $fetchingErrorMessage) | ||
11 | { | ||
12 | $this->fetchingErrorMessageTitle = $fetchingErrorMessageTitle; | ||
13 | $this->fetchingErrorMessage = $fetchingErrorMessage; | ||
14 | |||
15 | parent::__construct($em, $contentProxy, $tagsAssigner, $eventDispatcher); | ||
16 | } | ||
17 | |||
7 | /** | 18 | /** |
8 | * {@inheritdoc} | 19 | * {@inheritdoc} |
9 | */ | 20 | */ |
@@ -43,10 +54,11 @@ class WallabagV1Import extends WallabagImport | |||
43 | 'created_at' => '', | 54 | 'created_at' => '', |
44 | ]; | 55 | ]; |
45 | 56 | ||
46 | // force content to be refreshed in case on bad fetch in the v1 installation | 57 | // In case of a bad fetch in v1, replace title and content with v2 error strings |
58 | // If fetching fails again, they will get this instead of the v1 strings | ||
47 | if (in_array($entry['title'], $this->untitled)) { | 59 | if (in_array($entry['title'], $this->untitled)) { |
48 | $data['title'] = ''; | 60 | $data['title'] = $this->fetchingErrorMessageTitle; |
49 | $data['html'] = ''; | 61 | $data['html'] = $this->fetchingErrorMessage; |
50 | } | 62 | } |
51 | 63 | ||
52 | if (array_key_exists('tags', $entry) && $entry['tags'] != '') { | 64 | if (array_key_exists('tags', $entry) && $entry['tags'] != '') { |
diff --git a/src/Wallabag/ImportBundle/Import/WallabagV2Import.php b/src/Wallabag/ImportBundle/Import/WallabagV2Import.php index d2a89d79..3e085ecf 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV2Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV2Import.php | |||
@@ -36,8 +36,8 @@ class WallabagV2Import extends WallabagImport | |||
36 | return [ | 36 | return [ |
37 | 'html' => $entry['content'], | 37 | 'html' => $entry['content'], |
38 | 'content_type' => $entry['mimetype'], | 38 | 'content_type' => $entry['mimetype'], |
39 | 'is_archived' => (int) ($entry['is_archived'] || $this->markAsRead), | 39 | 'is_archived' => (bool) ($entry['is_archived'] || $this->markAsRead), |
40 | 'is_starred' => false, | 40 | 'is_starred' => (bool) $entry['is_starred'], |
41 | ] + $entry; | 41 | ] + $entry; |
42 | } | 42 | } |
43 | 43 | ||
diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index 661dc7e1..b224a6a2 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml | |||
@@ -35,6 +35,8 @@ services: | |||
35 | - "@wallabag_core.content_proxy" | 35 | - "@wallabag_core.content_proxy" |
36 | - "@wallabag_core.tags_assigner" | 36 | - "@wallabag_core.tags_assigner" |
37 | - "@event_dispatcher" | 37 | - "@event_dispatcher" |
38 | - "%wallabag_core.fetching_error_message_title%" | ||
39 | - "%wallabag_core.fetching_error_message%" | ||
38 | calls: | 40 | calls: |
39 | - [ setLogger, [ "@logger" ]] | 41 | - [ setLogger, [ "@logger" ]] |
40 | tags: | 42 | tags: |
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php index 1c5c86d4..084f2c67 100644 --- a/src/Wallabag/UserBundle/Controller/ManageController.php +++ b/src/Wallabag/UserBundle/Controller/ManageController.php | |||
@@ -33,9 +33,7 @@ class ManageController extends Controller | |||
33 | // enable created user by default | 33 | // enable created user by default |
34 | $user->setEnabled(true); | 34 | $user->setEnabled(true); |
35 | 35 | ||
36 | $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [ | 36 | $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user); |
37 | 'validation_groups' => ['Profile'], | ||
38 | ]); | ||
39 | $form->handleRequest($request); | 37 | $form->handleRequest($request); |
40 | 38 | ||
41 | if ($form->isSubmitted() && $form->isValid()) { | 39 | if ($form->isSubmitted() && $form->isValid()) { |
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index 3a167de7..ed6ce331 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php | |||
@@ -4,11 +4,11 @@ namespace Wallabag\UserBundle\Entity; | |||
4 | 4 | ||
5 | use Doctrine\Common\Collections\ArrayCollection; | 5 | use Doctrine\Common\Collections\ArrayCollection; |
6 | use Doctrine\ORM\Mapping as ORM; | 6 | use Doctrine\ORM\Mapping as ORM; |
7 | use JMS\Serializer\Annotation\Groups; | ||
8 | use JMS\Serializer\Annotation\XmlRoot; | ||
7 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | 9 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; |
8 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; | 10 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; |
9 | use FOS\UserBundle\Model\User as BaseUser; | 11 | use FOS\UserBundle\Model\User as BaseUser; |
10 | use JMS\Serializer\Annotation\ExclusionPolicy; | ||
11 | use JMS\Serializer\Annotation\Expose; | ||
12 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | 12 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; |
13 | use Symfony\Component\Security\Core\User\UserInterface; | 13 | use Symfony\Component\Security\Core\User\UserInterface; |
14 | use Wallabag\ApiBundle\Entity\Client; | 14 | use Wallabag\ApiBundle\Entity\Client; |
@@ -18,23 +18,25 @@ use Wallabag\CoreBundle\Entity\Entry; | |||
18 | /** | 18 | /** |
19 | * User. | 19 | * User. |
20 | * | 20 | * |
21 | * @XmlRoot("user") | ||
21 | * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") | 22 | * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") |
22 | * @ORM\Table(name="`user`") | 23 | * @ORM\Table(name="`user`") |
23 | * @ORM\HasLifecycleCallbacks() | 24 | * @ORM\HasLifecycleCallbacks() |
24 | * @ExclusionPolicy("all") | ||
25 | * | 25 | * |
26 | * @UniqueEntity("email") | 26 | * @UniqueEntity("email") |
27 | * @UniqueEntity("username") | 27 | * @UniqueEntity("username") |
28 | */ | 28 | */ |
29 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | 29 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface |
30 | { | 30 | { |
31 | /** @Serializer\XmlAttribute */ | ||
31 | /** | 32 | /** |
32 | * @var int | 33 | * @var int |
33 | * | 34 | * |
34 | * @Expose | ||
35 | * @ORM\Column(name="id", type="integer") | 35 | * @ORM\Column(name="id", type="integer") |
36 | * @ORM\Id | 36 | * @ORM\Id |
37 | * @ORM\GeneratedValue(strategy="AUTO") | 37 | * @ORM\GeneratedValue(strategy="AUTO") |
38 | * | ||
39 | * @Groups({"user_api"}) | ||
38 | */ | 40 | */ |
39 | protected $id; | 41 | protected $id; |
40 | 42 | ||
@@ -42,20 +44,40 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
42 | * @var string | 44 | * @var string |
43 | * | 45 | * |
44 | * @ORM\Column(name="name", type="text", nullable=true) | 46 | * @ORM\Column(name="name", type="text", nullable=true) |
47 | * | ||
48 | * @Groups({"user_api"}) | ||
45 | */ | 49 | */ |
46 | protected $name; | 50 | protected $name; |
47 | 51 | ||
48 | /** | 52 | /** |
49 | * @var date | 53 | * @var string |
54 | * | ||
55 | * @Groups({"user_api"}) | ||
56 | */ | ||
57 | protected $username; | ||
58 | |||
59 | /** | ||
60 | * @var string | ||
61 | * | ||
62 | * @Groups({"user_api"}) | ||
63 | */ | ||
64 | protected $email; | ||
65 | |||
66 | /** | ||
67 | * @var \DateTime | ||
50 | * | 68 | * |
51 | * @ORM\Column(name="created_at", type="datetime") | 69 | * @ORM\Column(name="created_at", type="datetime") |
70 | * | ||
71 | * @Groups({"user_api"}) | ||
52 | */ | 72 | */ |
53 | protected $createdAt; | 73 | protected $createdAt; |
54 | 74 | ||
55 | /** | 75 | /** |
56 | * @var date | 76 | * @var \DateTime |
57 | * | 77 | * |
58 | * @ORM\Column(name="updated_at", type="datetime") | 78 | * @ORM\Column(name="updated_at", type="datetime") |
79 | * | ||
80 | * @Groups({"user_api"}) | ||
59 | */ | 81 | */ |
60 | protected $updatedAt; | 82 | protected $updatedAt; |
61 | 83 | ||
@@ -135,7 +157,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
135 | } | 157 | } |
136 | 158 | ||
137 | /** | 159 | /** |
138 | * @return string | 160 | * @return \DateTime |
139 | */ | 161 | */ |
140 | public function getCreatedAt() | 162 | public function getCreatedAt() |
141 | { | 163 | { |
@@ -143,7 +165,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
143 | } | 165 | } |
144 | 166 | ||
145 | /** | 167 | /** |
146 | * @return string | 168 | * @return \DateTime |
147 | */ | 169 | */ |
148 | public function getUpdatedAt() | 170 | public function getUpdatedAt() |
149 | { | 171 | { |
diff --git a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php index 0bdd1cae..e4d55c19 100644 --- a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php +++ b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php | |||
@@ -5,7 +5,6 @@ namespace Wallabag\UserBundle\EventListener; | |||
5 | use Doctrine\ORM\EntityManager; | 5 | use Doctrine\ORM\EntityManager; |
6 | use FOS\UserBundle\Event\UserEvent; | 6 | use FOS\UserBundle\Event\UserEvent; |
7 | use FOS\UserBundle\FOSUserEvents; | 7 | use FOS\UserBundle\FOSUserEvents; |
8 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
9 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | 8 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
10 | use Wallabag\CoreBundle\Entity\Config; | 9 | use Wallabag\CoreBundle\Entity\Config; |
11 | 10 | ||
@@ -47,7 +46,7 @@ class CreateConfigListener implements EventSubscriberInterface | |||
47 | ]; | 46 | ]; |
48 | } | 47 | } |
49 | 48 | ||
50 | public function createConfig(UserEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null) | 49 | public function createConfig(UserEvent $event) |
51 | { | 50 | { |
52 | $config = new Config($event->getUser()); | 51 | $config = new Config($event->getUser()); |
53 | $config->setTheme($this->theme); | 52 | $config->setTheme($this->theme); |