aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php17
-rw-r--r--src/Wallabag/ApiBundle/Controller/EntryRestController.php268
-rw-r--r--src/Wallabag/ApiBundle/Controller/TagRestController.php4
-rw-r--r--src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php119
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php33
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php61
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php2
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php10
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php7
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/Configuration.php3
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php1
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php83
-rw-r--r--src/Wallabag/CoreBundle/Entity/TaggingRule.php4
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/EditEntryType.php6
-rw-r--r--src/Wallabag/CoreBundle/Helper/ContentProxy.php8
-rw-r--r--src/Wallabag/CoreBundle/Operator/Doctrine/NotMatches.php25
-rw-r--r--src/Wallabag/CoreBundle/Operator/PHP/NotMatches.php21
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntryRepository.php40
-rw-r--r--src/Wallabag/CoreBundle/Repository/TagRepository.php20
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.da.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.de.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.es.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml142
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.it.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig5
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig14
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig19
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig6
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig27
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig4
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/edit.html.twig5
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig4
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig96
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig10
-rw-r--r--src/Wallabag/ImportBundle/Command/ImportCommand.php11
-rw-r--r--src/Wallabag/UserBundle/Controller/ManageController.php67
-rw-r--r--src/Wallabag/UserBundle/Form/SearchUserType.php29
-rw-r--r--src/Wallabag/UserBundle/Repository/UserRepository.php13
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig77
47 files changed, 1075 insertions, 285 deletions
diff --git a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
index 8d3f07ee..da361308 100644
--- a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
+++ b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
@@ -122,4 +122,21 @@ class AnnotationRepository extends EntityRepository
122 ->setParameter('userId', $userId) 122 ->setParameter('userId', $userId)
123 ->execute(); 123 ->execute();
124 } 124 }
125
126 /**
127 * Find all annotations related to archived entries.
128 *
129 * @param $userId
130 *
131 * @return mixed
132 */
133 public function findAllArchivedEntriesByUser($userId)
134 {
135 return $this->createQueryBuilder('a')
136 ->leftJoin('a.entry', 'e')
137 ->where('a.user = :userid')->setParameter(':userid', $userId)
138 ->andWhere('e.isArchived = true')
139 ->getQuery()
140 ->getResult();
141 }
125} 142}
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php
index c544815e..632b16d9 100644
--- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php
@@ -5,6 +5,7 @@ namespace Wallabag\ApiBundle\Controller;
5use Hateoas\Configuration\Route; 5use Hateoas\Configuration\Route;
6use Hateoas\Representation\Factory\PagerfantaFactory; 6use Hateoas\Representation\Factory\PagerfantaFactory;
7use Nelmio\ApiDocBundle\Annotation\ApiDoc; 7use Nelmio\ApiDocBundle\Annotation\ApiDoc;
8use Symfony\Component\HttpKernel\Exception\HttpException;
8use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
9use Symfony\Component\HttpFoundation\JsonResponse; 10use Symfony\Component\HttpFoundation\JsonResponse;
10use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 11use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -41,12 +42,10 @@ class EntryRestController extends WallabagRestController
41 ->getRepository('WallabagCoreBundle:Entry') 42 ->getRepository('WallabagCoreBundle:Entry')
42 ->findByUrlAndUserId($url, $this->getUser()->getId()); 43 ->findByUrlAndUserId($url, $this->getUser()->getId());
43 44
44 $results[$url] = false === $res ? false : true; 45 $results[$url] = $res instanceof Entry ? $res->getId() : false;
45 } 46 }
46 47
47 $json = $this->get('serializer')->serialize($results, 'json'); 48 return $this->sendResponse($results);
48
49 return (new JsonResponse())->setJson($json);
50 } 49 }
51 50
52 // let's see if it is a simple url? 51 // let's see if it is a simple url?
@@ -60,11 +59,9 @@ class EntryRestController extends WallabagRestController
60 ->getRepository('WallabagCoreBundle:Entry') 59 ->getRepository('WallabagCoreBundle:Entry')
61 ->findByUrlAndUserId($url, $this->getUser()->getId()); 60 ->findByUrlAndUserId($url, $this->getUser()->getId());
62 61
63 $exists = false === $res ? false : true; 62 $exists = $res instanceof Entry ? $res->getId() : false;
64
65 $json = $this->get('serializer')->serialize(['exists' => $exists], 'json');
66 63
67 return (new JsonResponse())->setJson($json); 64 return $this->sendResponse(['exists' => $exists]);
68 } 65 }
69 66
70 /** 67 /**
@@ -125,9 +122,7 @@ class EntryRestController extends WallabagRestController
125 ) 122 )
126 ); 123 );
127 124
128 $json = $this->get('serializer')->serialize($paginatedCollection, 'json'); 125 return $this->sendResponse($paginatedCollection);
129
130 return (new JsonResponse())->setJson($json);
131 } 126 }
132 127
133 /** 128 /**
@@ -146,9 +141,7 @@ class EntryRestController extends WallabagRestController
146 $this->validateAuthentication(); 141 $this->validateAuthentication();
147 $this->validateUserAccess($entry->getUser()->getId()); 142 $this->validateUserAccess($entry->getUser()->getId());
148 143
149 $json = $this->get('serializer')->serialize($entry, 'json'); 144 return $this->sendResponse($entry);
150
151 return (new JsonResponse())->setJson($json);
152 } 145 }
153 146
154 /** 147 /**
@@ -174,6 +167,110 @@ class EntryRestController extends WallabagRestController
174 } 167 }
175 168
176 /** 169 /**
170 * Handles an entries list and delete URL.
171 *
172 * @ApiDoc(
173 * parameters={
174 * {"name"="urls", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...'}, {'url': 'http://...'}]", "description"="Urls (as an array) to delete."}
175 * }
176 * )
177 *
178 * @return JsonResponse
179 */
180 public function deleteEntriesListAction(Request $request)
181 {
182 $this->validateAuthentication();
183
184 $urls = json_decode($request->query->get('urls', []));
185
186 if (empty($urls)) {
187 return $this->sendResponse([]);
188 }
189
190 $results = [];
191
192 // handle multiple urls
193 foreach ($urls as $key => $url) {
194 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId(
195 $url,
196 $this->getUser()->getId()
197 );
198
199 $results[$key]['url'] = $url;
200
201 if (false !== $entry) {
202 $em = $this->getDoctrine()->getManager();
203 $em->remove($entry);
204 $em->flush();
205
206 // entry deleted, dispatch event about it!
207 $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
208 }
209
210 $results[$key]['entry'] = $entry instanceof Entry ? true : false;
211 }
212
213 return $this->sendResponse($results);
214 }
215
216 /**
217 * Handles an entries list and create URL.
218 *
219 * @ApiDoc(
220 * parameters={
221 * {"name"="urls", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...'}, {'url': 'http://...'}]", "description"="Urls (as an array) to create."}
222 * }
223 * )
224 *
225 * @return JsonResponse
226 *
227 * @throws HttpException When limit is reached
228 */
229 public function postEntriesListAction(Request $request)
230 {
231 $this->validateAuthentication();
232
233 $urls = json_decode($request->query->get('urls', []));
234 $results = [];
235
236 $limit = $this->container->getParameter('wallabag_core.api_limit_mass_actions');
237
238 if (count($urls) > $limit) {
239 throw new HttpException(400, 'API limit reached');
240 }
241
242 // handle multiple urls
243 if (!empty($urls)) {
244 foreach ($urls as $key => $url) {
245 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId(
246 $url,
247 $this->getUser()->getId()
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
259 $em = $this->getDoctrine()->getManager();
260 $em->persist($entry);
261 $em->flush();
262
263 $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false;
264
265 // entry saved, dispatch event about it!
266 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
267 }
268 }
269
270 return $this->sendResponse($results);
271 }
272
273 /**
177 * Create an entry. 274 * Create an entry.
178 * 275 *
179 * @ApiDoc( 276 * @ApiDoc(
@@ -230,9 +327,7 @@ class EntryRestController extends WallabagRestController
230 // entry saved, dispatch event about it! 327 // entry saved, dispatch event about it!
231 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); 328 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
232 329
233 $json = $this->get('serializer')->serialize($entry, 'json'); 330 return $this->sendResponse($entry);
234
235 return (new JsonResponse())->setJson($json);
236 } 331 }
237 332
238 /** 333 /**
@@ -281,9 +376,7 @@ class EntryRestController extends WallabagRestController
281 $em = $this->getDoctrine()->getManager(); 376 $em = $this->getDoctrine()->getManager();
282 $em->flush(); 377 $em->flush();
283 378
284 $json = $this->get('serializer')->serialize($entry, 'json'); 379 return $this->sendResponse($entry);
285
286 return (new JsonResponse())->setJson($json);
287 } 380 }
288 381
289 /** 382 /**
@@ -326,9 +419,7 @@ class EntryRestController extends WallabagRestController
326 // entry saved, dispatch event about it! 419 // entry saved, dispatch event about it!
327 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); 420 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
328 421
329 $json = $this->get('serializer')->serialize($entry, 'json'); 422 return $this->sendResponse($entry);
330
331 return (new JsonResponse())->setJson($json);
332 } 423 }
333 424
334 /** 425 /**
@@ -354,9 +445,7 @@ class EntryRestController extends WallabagRestController
354 // entry deleted, dispatch event about it! 445 // entry deleted, dispatch event about it!
355 $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); 446 $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
356 447
357 $json = $this->get('serializer')->serialize($entry, 'json'); 448 return $this->sendResponse($entry);
358
359 return (new JsonResponse())->setJson($json);
360 } 449 }
361 450
362 /** 451 /**
@@ -375,9 +464,7 @@ class EntryRestController extends WallabagRestController
375 $this->validateAuthentication(); 464 $this->validateAuthentication();
376 $this->validateUserAccess($entry->getUser()->getId()); 465 $this->validateUserAccess($entry->getUser()->getId());
377 466
378 $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); 467 return $this->sendResponse($entry->getTags());
379
380 return (new JsonResponse())->setJson($json);
381 } 468 }
382 469
383 /** 470 /**
@@ -408,9 +495,7 @@ class EntryRestController extends WallabagRestController
408 $em->persist($entry); 495 $em->persist($entry);
409 $em->flush(); 496 $em->flush();
410 497
411 $json = $this->get('serializer')->serialize($entry, 'json'); 498 return $this->sendResponse($entry);
412
413 return (new JsonResponse())->setJson($json);
414 } 499 }
415 500
416 /** 501 /**
@@ -435,7 +520,124 @@ class EntryRestController extends WallabagRestController
435 $em->persist($entry); 520 $em->persist($entry);
436 $em->flush(); 521 $em->flush();
437 522
438 $json = $this->get('serializer')->serialize($entry, 'json'); 523 return $this->sendResponse($entry);
524 }
525
526 /**
527 * Handles an entries list delete tags from them.
528 *
529 * @ApiDoc(
530 * parameters={
531 * {"name"="list", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...','tags': 'tag1, tag2'}, {'url': 'http://...','tags': 'tag1, tag2'}]", "description"="Urls (as an array) to handle."}
532 * }
533 * )
534 *
535 * @return JsonResponse
536 */
537 public function deleteEntriesTagsListAction(Request $request)
538 {
539 $this->validateAuthentication();
540
541 $list = json_decode($request->query->get('list', []));
542
543 if (empty($list)) {
544 return $this->sendResponse([]);
545 }
546
547 // handle multiple urls
548 $results = [];
549
550 foreach ($list as $key => $element) {
551 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId(
552 $element->url,
553 $this->getUser()->getId()
554 );
555
556 $results[$key]['url'] = $element->url;
557 $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false;
558
559 $tags = $element->tags;
560
561 if (false !== $entry && !(empty($tags))) {
562 $tags = explode(',', $tags);
563 foreach ($tags as $label) {
564 $label = trim($label);
565
566 $tag = $this->getDoctrine()
567 ->getRepository('WallabagCoreBundle:Tag')
568 ->findOneByLabel($label);
569
570 if (false !== $tag) {
571 $entry->removeTag($tag);
572 }
573 }
574
575 $em = $this->getDoctrine()->getManager();
576 $em->persist($entry);
577 $em->flush();
578 }
579 }
580
581 return $this->sendResponse($results);
582 }
583
584 /**
585 * Handles an entries list and add tags to them.
586 *
587 * @ApiDoc(
588 * parameters={
589 * {"name"="list", "dataType"="string", "required"=true, "format"="A JSON array of urls [{'url': 'http://...','tags': 'tag1, tag2'}, {'url': 'http://...','tags': 'tag1, tag2'}]", "description"="Urls (as an array) to handle."}
590 * }
591 * )
592 *
593 * @return JsonResponse
594 */
595 public function postEntriesTagsListAction(Request $request)
596 {
597 $this->validateAuthentication();
598
599 $list = json_decode($request->query->get('list', []));
600
601 if (empty($list)) {
602 return $this->sendResponse([]);
603 }
604
605 $results = [];
606
607 // handle multiple urls
608 foreach ($list as $key => $element) {
609 $entry = $this->get('wallabag_core.entry_repository')->findByUrlAndUserId(
610 $element->url,
611 $this->getUser()->getId()
612 );
613
614 $results[$key]['url'] = $element->url;
615 $results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false;
616
617 $tags = $element->tags;
618
619 if (false !== $entry && !(empty($tags))) {
620 $this->get('wallabag_core.content_proxy')->assignTagsToEntry($entry, $tags);
621
622 $em = $this->getDoctrine()->getManager();
623 $em->persist($entry);
624 $em->flush();
625 }
626 }
627
628 return $this->sendResponse($results);
629 }
630
631 /**
632 * Shortcut to send data serialized in json.
633 *
634 * @param mixed $data
635 *
636 * @return JsonResponse
637 */
638 private function sendResponse($data)
639 {
640 $json = $this->get('serializer')->serialize($data, 'json');
439 641
440 return (new JsonResponse())->setJson($json); 642 return (new JsonResponse())->setJson($json);
441 } 643 }
diff --git a/src/Wallabag/ApiBundle/Controller/TagRestController.php b/src/Wallabag/ApiBundle/Controller/TagRestController.php
index bc6d4e64..47298d7e 100644
--- a/src/Wallabag/ApiBundle/Controller/TagRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/TagRestController.php
@@ -31,7 +31,7 @@ class TagRestController extends WallabagRestController
31 } 31 }
32 32
33 /** 33 /**
34 * Permanently remove one tag from **every** entry. 34 * Permanently remove one tag from **every** entry by passing the Tag label.
35 * 35 *
36 * @ApiDoc( 36 * @ApiDoc(
37 * requirements={ 37 * requirements={
@@ -106,7 +106,7 @@ class TagRestController extends WallabagRestController
106 } 106 }
107 107
108 /** 108 /**
109 * Permanently remove one tag from **every** entry. 109 * Permanently remove one tag from **every** entry by passing the Tag ID.
110 * 110 *
111 * @ApiDoc( 111 * @ApiDoc(
112 * requirements={ 112 * requirements={
diff --git a/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php b/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php
new file mode 100644
index 00000000..65f35d8e
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php
@@ -0,0 +1,119 @@
1<?php
2
3namespace Wallabag\CoreBundle\Command;
4
5use Doctrine\ORM\NoResultException;
6use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
7use Symfony\Component\Console\Input\InputArgument;
8use Symfony\Component\Console\Input\InputInterface;
9use Symfony\Component\Console\Output\OutputInterface;
10use Wallabag\CoreBundle\Entity\Entry;
11use Wallabag\UserBundle\Entity\User;
12
13class CleanDuplicatesCommand extends ContainerAwareCommand
14{
15 /** @var OutputInterface */
16 protected $output;
17
18 protected $duplicates = 0;
19
20 protected function configure()
21 {
22 $this
23 ->setName('wallabag:clean-duplicates')
24 ->setDescription('Cleans the database for duplicates')
25 ->setHelp('This command helps you to clean your articles list in case of duplicates')
26 ->addArgument(
27 'username',
28 InputArgument::OPTIONAL,
29 'User to clean'
30 );
31 }
32
33 protected function execute(InputInterface $input, OutputInterface $output)
34 {
35 $this->output = $output;
36
37 $username = $input->getArgument('username');
38
39 if ($username) {
40 try {
41 $user = $this->getUser($username);
42 $this->cleanDuplicates($user);
43 } catch (NoResultException $e) {
44 $output->writeln(sprintf('<error>User "%s" not found.</error>', $username));
45
46 return 1;
47 }
48 } else {
49 $users = $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findAll();
50
51 $output->writeln(sprintf('Cleaning through %d user accounts', count($users)));
52
53 foreach ($users as $user) {
54 $output->writeln(sprintf('Processing user %s', $user->getUsername()));
55 $this->cleanDuplicates($user);
56 }
57 $output->writeln(sprintf('Finished cleaning. %d duplicates found in total', $this->duplicates));
58 }
59
60 return 0;
61 }
62
63 /**
64 * @param User $user
65 */
66 private function cleanDuplicates(User $user)
67 {
68 $em = $this->getContainer()->get('doctrine.orm.entity_manager');
69 $repo = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
70
71 $entries = $repo->getAllEntriesIdAndUrl($user->getId());
72
73 $duplicatesCount = 0;
74 $urls = [];
75 foreach ($entries as $entry) {
76 $url = $this->similarUrl($entry['url']);
77
78 /* @var $entry Entry */
79 if (in_array($url, $urls)) {
80 ++$duplicatesCount;
81
82 $em->remove($repo->find($entry['id']));
83 $em->flush(); // Flushing at the end of the loop would require the instance not being online
84 } else {
85 $urls[] = $entry['url'];
86 }
87 }
88
89 $this->duplicates += $duplicatesCount;
90
91 $this->output->writeln(sprintf('Cleaned %d duplicates for user %s', $duplicatesCount, $user->getUserName()));
92 }
93
94 private function similarUrl($url)
95 {
96 if (in_array(substr($url, -1), ['/', '#'])) { // get rid of "/" and "#" and the end of urls
97 return substr($url, 0, strlen($url));
98 }
99
100 return $url;
101 }
102
103 /**
104 * Fetches a user from its username.
105 *
106 * @param string $username
107 *
108 * @return \Wallabag\UserBundle\Entity\User
109 */
110 private function getUser($username)
111 {
112 return $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findOneByUserName($username);
113 }
114
115 private function getDoctrine()
116 {
117 return $this->getContainer()->get('doctrine');
118 }
119}
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index f0738b91..0d9364f6 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -63,6 +63,7 @@ class InstallCommand extends ContainerAwareCommand
63 ->setupDatabase() 63 ->setupDatabase()
64 ->setupAdmin() 64 ->setupAdmin()
65 ->setupConfig() 65 ->setupConfig()
66 ->runMigrations()
66 ; 67 ;
67 68
68 $output->writeln('<info>wallabag has been successfully installed.</info>'); 69 $output->writeln('<info>wallabag has been successfully installed.</info>');
@@ -71,7 +72,7 @@ class InstallCommand extends ContainerAwareCommand
71 72
72 protected function checkRequirements() 73 protected function checkRequirements()
73 { 74 {
74 $this->defaultOutput->writeln('<info><comment>Step 1 of 4.</comment> Checking system requirements.</info>'); 75 $this->defaultOutput->writeln('<info><comment>Step 1 of 5.</comment> Checking system requirements.</info>');
75 $doctrineManager = $this->getContainer()->get('doctrine')->getManager(); 76 $doctrineManager = $this->getContainer()->get('doctrine')->getManager();
76 77
77 $rows = []; 78 $rows = [];
@@ -175,11 +176,11 @@ class InstallCommand extends ContainerAwareCommand
175 176
176 protected function setupDatabase() 177 protected function setupDatabase()
177 { 178 {
178 $this->defaultOutput->writeln('<info><comment>Step 2 of 4.</comment> Setting up database.</info>'); 179 $this->defaultOutput->writeln('<info><comment>Step 2 of 5.</comment> Setting up database.</info>');
179 180
180 // user want to reset everything? Don't care about what is already here 181 // user want to reset everything? Don't care about what is already here
181 if (true === $this->defaultInput->getOption('reset')) { 182 if (true === $this->defaultInput->getOption('reset')) {
182 $this->defaultOutput->writeln('Droping database, creating database and schema, clearing the cache'); 183 $this->defaultOutput->writeln('Dropping database, creating database and schema, clearing the cache');
183 184
184 $this 185 $this
185 ->runCommand('doctrine:database:drop', ['--force' => true]) 186 ->runCommand('doctrine:database:drop', ['--force' => true])
@@ -211,7 +212,7 @@ class InstallCommand extends ContainerAwareCommand
211 $question = new ConfirmationQuestion('It appears that your database already exists. Would you like to reset it? (y/N)', false); 212 $question = new ConfirmationQuestion('It appears that your database already exists. Would you like to reset it? (y/N)', false);
212 213
213 if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { 214 if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) {
214 $this->defaultOutput->writeln('Droping database, creating database and schema'); 215 $this->defaultOutput->writeln('Dropping database, creating database and schema');
215 216
216 $this 217 $this
217 ->runCommand('doctrine:database:drop', ['--force' => true]) 218 ->runCommand('doctrine:database:drop', ['--force' => true])
@@ -221,7 +222,7 @@ class InstallCommand extends ContainerAwareCommand
221 } elseif ($this->isSchemaPresent()) { 222 } elseif ($this->isSchemaPresent()) {
222 $question = new ConfirmationQuestion('Seems like your database contains schema. Do you want to reset it? (y/N)', false); 223 $question = new ConfirmationQuestion('Seems like your database contains schema. Do you want to reset it? (y/N)', false);
223 if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { 224 if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) {
224 $this->defaultOutput->writeln('Droping schema and creating schema'); 225 $this->defaultOutput->writeln('Dropping schema and creating schema');
225 226
226 $this 227 $this
227 ->runCommand('doctrine:schema:drop', ['--force' => true]) 228 ->runCommand('doctrine:schema:drop', ['--force' => true])
@@ -246,7 +247,7 @@ class InstallCommand extends ContainerAwareCommand
246 247
247 protected function setupAdmin() 248 protected function setupAdmin()
248 { 249 {
249 $this->defaultOutput->writeln('<info><comment>Step 3 of 4.</comment> Administration setup.</info>'); 250 $this->defaultOutput->writeln('<info><comment>Step 3 of 5.</comment> Administration setup.</info>');
250 251
251 $questionHelper = $this->getHelperSet()->get('question'); 252 $questionHelper = $this->getHelperSet()->get('question');
252 $question = new ConfirmationQuestion('Would you like to create a new admin user (recommended) ? (Y/n)', true); 253 $question = new ConfirmationQuestion('Would you like to create a new admin user (recommended) ? (Y/n)', true);
@@ -285,7 +286,7 @@ class InstallCommand extends ContainerAwareCommand
285 286
286 protected function setupConfig() 287 protected function setupConfig()
287 { 288 {
288 $this->defaultOutput->writeln('<info><comment>Step 4 of 4.</comment> Config setup.</info>'); 289 $this->defaultOutput->writeln('<info><comment>Step 4 of 5.</comment> Config setup.</info>');
289 $em = $this->getContainer()->get('doctrine.orm.entity_manager'); 290 $em = $this->getContainer()->get('doctrine.orm.entity_manager');
290 291
291 // cleanup before insert new stuff 292 // cleanup before insert new stuff
@@ -333,6 +334,16 @@ class InstallCommand extends ContainerAwareCommand
333 'section' => 'entry', 334 'section' => 'entry',
334 ], 335 ],
335 [ 336 [
337 'name' => 'share_scuttle',
338 'value' => '1',
339 'section' => 'entry',
340 ],
341 [
342 'name' => 'scuttle_url',
343 'value' => 'http://scuttle.org',
344 'section' => 'entry',
345 ],
346 [
336 'name' => 'share_mail', 347 'name' => 'share_mail',
337 'value' => '1', 348 'value' => '1',
338 'section' => 'entry', 349 'section' => 'entry',
@@ -454,6 +465,14 @@ class InstallCommand extends ContainerAwareCommand
454 return $this; 465 return $this;
455 } 466 }
456 467
468 protected function runMigrations()
469 {
470 $this->defaultOutput->writeln('<info><comment>Step 5 of 5.</comment> Run migrations.</info>');
471
472 $this
473 ->runCommand('doctrine:migrations:migrate', ['--no-interaction' => true]);
474 }
475
457 /** 476 /**
458 * Run a command. 477 * Run a command.
459 * 478 *
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
index 907bf78e..1a80cc1a 100644
--- a/src/Wallabag/CoreBundle/Controller/ConfigController.php
+++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php
@@ -248,7 +248,7 @@ class ConfigController extends Controller
248 break; 248 break;
249 249
250 case 'entries': 250 case 'entries':
251 // SQLite doesn't care about cascading remove, so we need to manually remove associated stuf 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()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
254 $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId()); 254 $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId());
@@ -260,6 +260,19 @@ class ConfigController extends Controller
260 $this->getDoctrine() 260 $this->getDoctrine()
261 ->getRepository('WallabagCoreBundle:Entry') 261 ->getRepository('WallabagCoreBundle:Entry')
262 ->removeAllByUserId($this->getUser()->getId()); 262 ->removeAllByUserId($this->getUser()->getId());
263 break;
264 case 'archived':
265 if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
266 $this->removeAnnotationsForArchivedByUserId($this->getUser()->getId());
267 }
268
269 // manually remove tags to avoid orphan tag
270 $this->removeTagsForArchivedByUserId($this->getUser()->getId());
271
272 $this->getDoctrine()
273 ->getRepository('WallabagCoreBundle:Entry')
274 ->removeArchivedByUserId($this->getUser()->getId());
275 break;
263 } 276 }
264 277
265 $this->get('session')->getFlashBag()->add( 278 $this->get('session')->getFlashBag()->add(
@@ -271,14 +284,13 @@ class ConfigController extends Controller
271 } 284 }
272 285
273 /** 286 /**
274 * Remove all tags for a given user and cleanup orphan tags. 287 * Remove all tags for given tags and a given user and cleanup orphan tags.
275 * 288 *
276 * @param int $userId 289 * @param array $tags
290 * @param int $userId
277 */ 291 */
278 private function removeAllTagsByUserId($userId) 292 private function removeAllTagsByStatusAndUserId($tags, $userId)
279 { 293 {
280 $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findAllTags($userId);
281
282 if (empty($tags)) { 294 if (empty($tags)) {
283 return; 295 return;
284 } 296 }
@@ -300,6 +312,43 @@ class ConfigController extends Controller
300 } 312 }
301 313
302 /** 314 /**
315 * Remove all tags for a given user and cleanup orphan tags.
316 *
317 * @param int $userId
318 */
319 private function removeAllTagsByUserId($userId)
320 {
321 $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findAllTags($userId);
322 $this->removeAllTagsByStatusAndUserId($tags, $userId);
323 }
324
325 /**
326 * Remove all tags for a given user and cleanup orphan tags.
327 *
328 * @param int $userId
329 */
330 private function removeTagsForArchivedByUserId($userId)
331 {
332 $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findForArchivedArticlesByUser($userId);
333 $this->removeAllTagsByStatusAndUserId($tags, $userId);
334 }
335
336 private function removeAnnotationsForArchivedByUserId($userId)
337 {
338 $em = $this->getDoctrine()->getManager();
339
340 $archivedEntriesAnnotations = $this->getDoctrine()
341 ->getRepository('WallabagAnnotationBundle:Annotation')
342 ->findAllArchivedEntriesByUser($userId);
343
344 foreach ($archivedEntriesAnnotations as $archivedEntriesAnnotation) {
345 $em->remove($archivedEntriesAnnotation);
346 }
347
348 $em->flush();
349 }
350
351 /**
303 * Validate that a rule can be edited/deleted by the current user. 352 * Validate that a rule can be edited/deleted by the current user.
304 * 353 *
305 * @param TaggingRule $rule 354 * @param TaggingRule $rule
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index f7398e69..8d2ac6d4 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -227,7 +227,7 @@ class EntryController extends Controller
227 public function showUnreadAction(Request $request, $page) 227 public function showUnreadAction(Request $request, $page)
228 { 228 {
229 // load the quickstart if no entry in database 229 // load the quickstart if no entry in database
230 if ($page == 1 && $this->get('wallabag_core.entry_repository')->countAllEntriesByUsername($this->getUser()->getId()) == 0) { 230 if ($page == 1 && $this->get('wallabag_core.entry_repository')->countAllEntriesByUser($this->getUser()->getId()) == 0) {
231 return $this->redirect($this->generateUrl('quickstart')); 231 return $this->redirect($this->generateUrl('quickstart'));
232 } 232 }
233 233
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
index a723656e..aaeb9ee9 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
@@ -51,11 +51,21 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
51 'section' => 'entry', 51 'section' => 'entry',
52 ], 52 ],
53 [ 53 [
54 'name' => 'share_scuttle',
55 'value' => '1',
56 'section' => 'entry',
57 ],
58 [
54 'name' => 'shaarli_url', 59 'name' => 'shaarli_url',
55 'value' => 'http://myshaarli.com', 60 'value' => 'http://myshaarli.com',
56 'section' => 'entry', 61 'section' => 'entry',
57 ], 62 ],
58 [ 63 [
64 'name' => 'scuttle_url',
65 'value' => 'http://scuttle.org',
66 'section' => 'entry',
67 ],
68 [
59 'name' => 'share_mail', 69 'name' => 'share_mail',
60 'value' => '1', 70 'value' => '1',
61 'section' => 'entry', 71 'section' => 'entry',
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php
index 7efe6356..55abd63c 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php
@@ -36,6 +36,13 @@ class LoadTaggingRuleData extends AbstractFixture implements OrderedFixtureInter
36 36
37 $manager->persist($tr3); 37 $manager->persist($tr3);
38 38
39 $tr4 = new TaggingRule();
40 $tr4->setRule('content notmatches "basket"');
41 $tr4->setTags(['foot']);
42 $tr4->setConfig($this->getReference('admin-config'));
43
44 $manager->persist($tr4);
45
39 $manager->flush(); 46 $manager->flush();
40 } 47 }
41 48
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
index 006a18c3..75b37729 100644
--- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
+++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
@@ -47,6 +47,9 @@ class Configuration implements ConfigurationInterface
47 ->scalarNode('list_mode') 47 ->scalarNode('list_mode')
48 ->defaultValue(1) 48 ->defaultValue(1)
49 ->end() 49 ->end()
50 ->scalarNode('api_limit_mass_actions')
51 ->defaultValue(10)
52 ->end()
50 ->end() 53 ->end()
51 ; 54 ;
52 55
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
index aa9ee339..c075c19f 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.api_limit_mass_actions', $config['api_limit_mass_actions']);
29 30
30 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 31 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
31 $loader->load('services.yml'); 32 $loader->load('services.yml');
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index 7276b437..b71c467c 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -122,6 +122,24 @@ class Entry
122 private $updatedAt; 122 private $updatedAt;
123 123
124 /** 124 /**
125 * @var \DateTime
126 *
127 * @ORM\Column(name="published_at", type="datetime", nullable=true)
128 *
129 * @Groups({"entries_for_user", "export_all"})
130 */
131 private $publishedAt;
132
133 /**
134 * @var array
135 *
136 * @ORM\Column(name="published_by", type="json_array", nullable=true)
137 *
138 * @Groups({"entries_for_user", "export_all"})
139 */
140 private $publishedBy;
141
142 /**
125 * @ORM\OneToMany(targetEntity="Wallabag\AnnotationBundle\Entity\Annotation", mappedBy="entry", cascade={"persist", "remove"}) 143 * @ORM\OneToMany(targetEntity="Wallabag\AnnotationBundle\Entity\Annotation", mappedBy="entry", cascade={"persist", "remove"})
126 * @ORM\JoinTable 144 * @ORM\JoinTable
127 * 145 *
@@ -175,15 +193,6 @@ class Entry
175 private $previewPicture; 193 private $previewPicture;
176 194
177 /** 195 /**
178 * @var bool
179 *
180 * @ORM\Column(name="is_public", type="boolean", nullable=true, options={"default" = false})
181 *
182 * @Groups({"export_all"})
183 */
184 private $isPublic;
185
186 /**
187 * @var string 196 * @var string
188 * 197 *
189 * @ORM\Column(name="http_status", type="string", length=3, nullable=true) 198 * @ORM\Column(name="http_status", type="string", length=3, nullable=true)
@@ -532,22 +541,6 @@ class Entry
532 } 541 }
533 542
534 /** 543 /**
535 * @return bool
536 */
537 public function isPublic()
538 {
539 return $this->isPublic;
540 }
541
542 /**
543 * @param bool $isPublic
544 */
545 public function setIsPublic($isPublic)
546 {
547 $this->isPublic = $isPublic;
548 }
549
550 /**
551 * @return ArrayCollection<Tag> 544 * @return ArrayCollection<Tag>
552 */ 545 */
553 public function getTags() 546 public function getTags()
@@ -701,4 +694,44 @@ class Entry
701 694
702 return $this; 695 return $this;
703 } 696 }
697
698 /**
699 * @return \Datetime
700 */
701 public function getPublishedAt()
702 {
703 return $this->publishedAt;
704 }
705
706 /**
707 * @param \Datetime $publishedAt
708 *
709 * @return Entry
710 */
711 public function setPublishedAt(\Datetime $publishedAt)
712 {
713 $this->publishedAt = $publishedAt;
714
715 return $this;
716 }
717
718 /**
719 * @return string
720 */
721 public function getPublishedBy()
722 {
723 return $this->publishedBy;
724 }
725
726 /**
727 * @param string $publishedBy
728 *
729 * @return Entry
730 */
731 public function setPublishedBy($publishedBy)
732 {
733 $this->publishedBy = $publishedBy;
734
735 return $this;
736 }
704} 737}
diff --git a/src/Wallabag/CoreBundle/Entity/TaggingRule.php b/src/Wallabag/CoreBundle/Entity/TaggingRule.php
index 72651b19..84e11e26 100644
--- a/src/Wallabag/CoreBundle/Entity/TaggingRule.php
+++ b/src/Wallabag/CoreBundle/Entity/TaggingRule.php
@@ -31,7 +31,7 @@ class TaggingRule
31 * @Assert\Length(max=255) 31 * @Assert\Length(max=255)
32 * @RulerZAssert\ValidRule( 32 * @RulerZAssert\ValidRule(
33 * allowed_variables={"title", "url", "isArchived", "isStared", "content", "language", "mimetype", "readingTime", "domainName"}, 33 * allowed_variables={"title", "url", "isArchived", "isStared", "content", "language", "mimetype", "readingTime", "domainName"},
34 * allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches"} 34 * allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches", "notmatches"}
35 * ) 35 * )
36 * @ORM\Column(name="rule", type="string", nullable=false) 36 * @ORM\Column(name="rule", type="string", nullable=false)
37 */ 37 */
@@ -87,7 +87,7 @@ class TaggingRule
87 /** 87 /**
88 * Set tags. 88 * Set tags.
89 * 89 *
90 * @param array<string> $tags 90 * @param array <string> $tags
91 * 91 *
92 * @return TaggingRule 92 * @return TaggingRule
93 */ 93 */
diff --git a/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php b/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php
index c3715646..1627cc44 100644
--- a/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php
+++ b/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php
@@ -3,7 +3,6 @@
3namespace Wallabag\CoreBundle\Form\Type; 3namespace Wallabag\CoreBundle\Form\Type;
4 4
5use Symfony\Component\Form\AbstractType; 5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
7use Symfony\Component\Form\Extension\Core\Type\SubmitType; 6use Symfony\Component\Form\Extension\Core\Type\SubmitType;
8use Symfony\Component\Form\Extension\Core\Type\TextType; 7use Symfony\Component\Form\Extension\Core\Type\TextType;
9use Symfony\Component\Form\FormBuilderInterface; 8use Symfony\Component\Form\FormBuilderInterface;
@@ -18,11 +17,6 @@ class EditEntryType extends AbstractType
18 'required' => true, 17 'required' => true,
19 'label' => 'entry.edit.title_label', 18 'label' => 'entry.edit.title_label',
20 ]) 19 ])
21 ->add('is_public', CheckboxType::class, [
22 'required' => false,
23 'label' => 'entry.edit.is_public_label',
24 'property_path' => 'isPublic',
25 ])
26 ->add('url', TextType::class, [ 20 ->add('url', TextType::class, [
27 'disabled' => true, 21 'disabled' => true,
28 'required' => false, 22 'required' => false,
diff --git a/src/Wallabag/CoreBundle/Helper/ContentProxy.php b/src/Wallabag/CoreBundle/Helper/ContentProxy.php
index f222dd88..d45aef88 100644
--- a/src/Wallabag/CoreBundle/Helper/ContentProxy.php
+++ b/src/Wallabag/CoreBundle/Helper/ContentProxy.php
@@ -79,6 +79,14 @@ class ContentProxy
79 $entry->setContent($html); 79 $entry->setContent($html);
80 $entry->setHttpStatus(isset($content['status']) ? $content['status'] : ''); 80 $entry->setHttpStatus(isset($content['status']) ? $content['status'] : '');
81 81
82 if (isset($content['date']) && null !== $content['date'] && '' !== $content['date']) {
83 $entry->setPublishedAt(new \DateTime($content['date']));
84 }
85
86 if (!empty($content['authors'])) {
87 $entry->setPublishedBy($content['authors']);
88 }
89
82 $entry->setLanguage(isset($content['language']) ? $content['language'] : ''); 90 $entry->setLanguage(isset($content['language']) ? $content['language'] : '');
83 $entry->setMimetype(isset($content['content_type']) ? $content['content_type'] : ''); 91 $entry->setMimetype(isset($content['content_type']) ? $content['content_type'] : '');
84 $entry->setReadingTime(Utils::getReadingTime($html)); 92 $entry->setReadingTime(Utils::getReadingTime($html));
diff --git a/src/Wallabag/CoreBundle/Operator/Doctrine/NotMatches.php b/src/Wallabag/CoreBundle/Operator/Doctrine/NotMatches.php
new file mode 100644
index 00000000..b7f9da57
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Operator/Doctrine/NotMatches.php
@@ -0,0 +1,25 @@
1<?php
2
3namespace Wallabag\CoreBundle\Operator\Doctrine;
4
5/**
6 * Provides a "notmatches" operator used for tagging rules.
7 *
8 * It asserts that a given pattern is not contained in a subject, in a
9 * case-insensitive way.
10 *
11 * This operator will be used to compile tagging rules in DQL, usable
12 * by Doctrine ORM.
13 * It's registered in RulerZ using a service (wallabag.operator.doctrine.notmatches);
14 */
15class NotMatches
16{
17 public function __invoke($subject, $pattern)
18 {
19 if ($pattern[0] === "'") {
20 $pattern = sprintf("'%%%s%%'", substr($pattern, 1, -1));
21 }
22
23 return sprintf('UPPER(%s) NOT LIKE UPPER(%s)', $subject, $pattern);
24 }
25}
diff --git a/src/Wallabag/CoreBundle/Operator/PHP/NotMatches.php b/src/Wallabag/CoreBundle/Operator/PHP/NotMatches.php
new file mode 100644
index 00000000..68b2676f
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Operator/PHP/NotMatches.php
@@ -0,0 +1,21 @@
1<?php
2
3namespace Wallabag\CoreBundle\Operator\PHP;
4
5/**
6 * Provides a "notmatches" operator used for tagging rules.
7 *
8 * It asserts that a given pattern is not contained in a subject, in a
9 * case-insensitive way.
10 *
11 * This operator will be used to compile tagging rules in PHP, usable
12 * directly on Entry objects for instance.
13 * It's registered in RulerZ using a service (wallabag.operator.array.notmatches);
14 */
15class NotMatches
16{
17 public function __invoke($subject, $pattern)
18 {
19 return stripos($subject, $pattern) === false;
20 }
21}
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
index 4071301d..6972e974 100644
--- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
@@ -328,7 +328,7 @@ class EntryRepository extends EntityRepository
328 * 328 *
329 * @return int 329 * @return int
330 */ 330 */
331 public function countAllEntriesByUsername($userId) 331 public function countAllEntriesByUser($userId)
332 { 332 {
333 $qb = $this->createQueryBuilder('e') 333 $qb = $this->createQueryBuilder('e')
334 ->select('count(e)') 334 ->select('count(e)')
@@ -371,4 +371,42 @@ class EntryRepository extends EntityRepository
371 ->setParameter('userId', $userId) 371 ->setParameter('userId', $userId)
372 ->execute(); 372 ->execute();
373 } 373 }
374
375 public function removeArchivedByUserId($userId)
376 {
377 $this->getEntityManager()
378 ->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Entry e WHERE e.user = :userId AND e.isArchived = TRUE')
379 ->setParameter('userId', $userId)
380 ->execute();
381 }
382
383 /**
384 * Get id and url from all entries
385 * Used for the clean-duplicates command.
386 */
387 public function getAllEntriesIdAndUrl($userId)
388 {
389 $qb = $this->createQueryBuilder('e')
390 ->select('e.id, e.url')
391 ->where('e.user = :userid')->setParameter(':userid', $userId);
392
393 return $qb->getQuery()->getArrayResult();
394 }
395
396 /**
397 * Find all entries by url and owner.
398 *
399 * @param $url
400 * @param $userId
401 *
402 * @return array
403 */
404 public function findAllByUrlAndUserId($url, $userId)
405 {
406 return $this->createQueryBuilder('e')
407 ->where('e.url = :url')->setParameter('url', urldecode($url))
408 ->andWhere('e.user = :user_id')->setParameter('user_id', $userId)
409 ->getQuery()
410 ->getResult();
411 }
374} 412}
diff --git a/src/Wallabag/CoreBundle/Repository/TagRepository.php b/src/Wallabag/CoreBundle/Repository/TagRepository.php
index 2182df25..6c63a6a2 100644
--- a/src/Wallabag/CoreBundle/Repository/TagRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/TagRepository.php
@@ -76,4 +76,24 @@ class TagRepository extends EntityRepository
76 ->getQuery() 76 ->getQuery()
77 ->getSingleResult(); 77 ->getSingleResult();
78 } 78 }
79
80 public function findForArchivedArticlesByUser($userId)
81 {
82 $ids = $this->createQueryBuilder('t')
83 ->select('t.id')
84 ->leftJoin('t.entries', 'e')
85 ->where('e.user = :userId')->setParameter('userId', $userId)
86 ->andWhere('e.isArchived = true')
87 ->groupBy('t.id')
88 ->orderBy('t.slug')
89 ->getQuery()
90 ->getArrayResult();
91
92 $tags = [];
93 foreach ($ids as $id) {
94 $tags[] = $this->find($id);
95 }
96
97 return $tags;
98 }
79} 99}
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index 51d6ab47..bccb2e19 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -125,6 +125,16 @@ services:
125 tags: 125 tags:
126 - { name: rulerz.operator, target: doctrine, operator: matches, inline: true } 126 - { name: rulerz.operator, target: doctrine, operator: matches, inline: true }
127 127
128 wallabag.operator.array.notmatches:
129 class: Wallabag\CoreBundle\Operator\PHP\NotMatches
130 tags:
131 - { name: rulerz.operator, target: native, operator: notmatches }
132
133 wallabag.operator.doctrine.notmatches:
134 class: Wallabag\CoreBundle\Operator\Doctrine\NotMatches
135 tags:
136 - { name: rulerz.operator, target: doctrine, operator: notmatches, inline: true }
137
128 wallabag_core.helper.redirect: 138 wallabag_core.helper.redirect:
129 class: Wallabag\CoreBundle\Helper\Redirect 139 class: Wallabag\CoreBundle\Helper\Redirect
130 arguments: 140 arguments:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
index 5d9e85e4..57319af7 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
@@ -110,6 +110,7 @@ config:
110 # annotations: Remove ALL annotations 110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags 111 # tags: Remove ALL tags
112 # entries: Remove ALL entries 112 # entries: Remove ALL entries
113 # archived: Remove ALL archived entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) 114 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 # description: "You can change your password here. Your new password should by at least 8 characters long." 116 # description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,7 +155,7 @@ config:
154 # or: 'One rule OR another' 155 # or: 'One rule OR another'
155 # and: 'One rule AND another' 156 # and: 'One rule AND another'
156 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 157 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
157 158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
158entry: 159entry:
159 page_titles: 160 page_titles:
160 # unread: 'Unread entries' 161 # unread: 'Unread entries'
@@ -223,6 +224,8 @@ entry:
223 original_article: 'original' 224 original_article: 'original'
224 # annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations' 225 # annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
225 created_at: 'Oprettelsesdato' 226 created_at: 'Oprettelsesdato'
227 # published_at: 'Publication date'
228 # published_by: 'Published by'
226 new: 229 new:
227 page_title: 'Gem ny artikel' 230 page_title: 'Gem ny artikel'
228 placeholder: 'http://website.com' 231 placeholder: 'http://website.com'
@@ -234,7 +237,6 @@ entry:
234 # page_title: 'Edit an entry' 237 # page_title: 'Edit an entry'
235 # title_label: 'Title' 238 # title_label: 'Title'
236 url_label: 'Url' 239 url_label: 'Url'
237 # is_public_label: 'Public'
238 save_label: 'Gem' 240 save_label: 'Gem'
239 public: 241 public:
240 # shared_by_wallabag: "This article has been shared by <a href=%wallabag_instance%'>wallabag</a>" 242 # shared_by_wallabag: "This article has been shared by <a href=%wallabag_instance%'>wallabag</a>"
@@ -510,6 +512,8 @@ user:
510 # delete: Delete 512 # delete: Delete
511 # delete_confirm: Are you sure? 513 # delete_confirm: Are you sure?
512 # back_to_list: Back to list 514 # back_to_list: Back to list
515 search:
516 # placeholder: Filter by username or email
513 517
514error: 518error:
515 # page_title: An error occurred 519 # page_title: An error occurred
@@ -528,6 +532,7 @@ flashes:
528 # annotations_reset: Annotations reset 532 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset 533 # tags_reset: Tags reset
530 # entries_reset: Entries reset 534 # entries_reset: Entries reset
535 # archived_reset: Archived entries deleted
531 entry: 536 entry:
532 notice: 537 notice:
533 # entry_already_saved: 'Entry already saved on %date%' 538 # entry_already_saved: 'Entry already saved on %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
index f1952a3e..a7bcecc6 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
@@ -110,6 +110,7 @@ config:
110 annotations: Entferne ALLE Annotationen 110 annotations: Entferne ALLE Annotationen
111 tags: Entferne ALLE Tags 111 tags: Entferne ALLE Tags
112 entries: Entferne ALLE Einträge 112 entries: Entferne ALLE Einträge
113 # archived: Remove ALL archived entries
113 confirm: Bist du wirklich sicher? (DIES KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN) 114 confirm: Bist du wirklich sicher? (DIES KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN)
114 form_password: 115 form_password:
115 description: "Hier kannst du dein Kennwort ändern. Dieses sollte mindestens acht Zeichen enthalten." 116 description: "Hier kannst du dein Kennwort ändern. Dieses sollte mindestens acht Zeichen enthalten."
@@ -154,6 +155,7 @@ config:
154 or: 'Eine Regel ODER die andere' 155 or: 'Eine Regel ODER die andere'
155 and: 'Eine Regel UND eine andere' 156 and: 'Eine Regel UND eine andere'
156 matches: 'Testet, ob eine <i>Variable</i> auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title matches "Fußball"</code>' 157 matches: 'Testet, ob eine <i>Variable</i> auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title matches "Fußball"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'original' 225 original_article: 'original'
224 annotations_on_the_entry: '{0} Keine Anmerkungen|{1} Eine Anmerkung|]1,Inf[ %count% Anmerkungen' 226 annotations_on_the_entry: '{0} Keine Anmerkungen|{1} Eine Anmerkung|]1,Inf[ %count% Anmerkungen'
225 created_at: 'Erstellungsdatum' 227 created_at: 'Erstellungsdatum'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Neuen Artikel speichern' 231 page_title: 'Neuen Artikel speichern'
228 placeholder: 'https://website.de' 232 placeholder: 'https://website.de'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Eintrag bearbeiten' 238 page_title: 'Eintrag bearbeiten'
235 title_label: 'Titel' 239 title_label: 'Titel'
236 url_label: 'URL' 240 url_label: 'URL'
237 is_public_label: 'Öffentlich'
238 save_label: 'Speichern' 241 save_label: 'Speichern'
239 public: 242 public:
240 shared_by_wallabag: "Dieser Artikel wurde mittels <a href='%wallabag_instance%'>wallabag</a> geteilt" 243 shared_by_wallabag: "Dieser Artikel wurde mittels <a href='%wallabag_instance%'>wallabag</a> geteilt"
@@ -510,6 +513,8 @@ user:
510 delete: Löschen 513 delete: Löschen
511 delete_confirm: Bist du sicher? 514 delete_confirm: Bist du sicher?
512 back_to_list: Zurück zur Liste 515 back_to_list: Zurück zur Liste
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 page_title: Ein Fehler ist aufgetreten 520 page_title: Ein Fehler ist aufgetreten
@@ -528,6 +533,7 @@ flashes:
528 annotations_reset: Anmerkungen zurücksetzen 533 annotations_reset: Anmerkungen zurücksetzen
529 tags_reset: Tags zurücksetzen 534 tags_reset: Tags zurücksetzen
530 entries_reset: Einträge zurücksetzen 535 entries_reset: Einträge zurücksetzen
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Eintrag bereits am %date% gespeichert' 539 entry_already_saved: 'Eintrag bereits am %date% gespeichert'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index df782b01..1ef2874d 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -110,6 +110,7 @@ config:
110 annotations: Remove ALL annotations 110 annotations: Remove ALL annotations
111 tags: Remove ALL tags 111 tags: Remove ALL tags
112 entries: Remove ALL entries 112 entries: Remove ALL entries
113 archived: Remove ALL archived entries
113 confirm: Are you really sure? (THIS CAN'T BE UNDONE) 114 confirm: Are you really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 description: "You can change your password here. Your new password should by at least 8 characters long." 116 description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,6 +155,7 @@ config:
154 or: 'One rule OR another' 155 or: 'One rule OR another'
155 and: 'One rule AND another' 156 and: 'One rule AND another'
156 matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 157 matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
158 notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'original' 225 original_article: 'original'
224 annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations' 226 annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
225 created_at: 'Creation date' 227 created_at: 'Creation date'
228 published_at: 'Publication date'
229 published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Save new entry' 231 page_title: 'Save new entry'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Edit an entry' 238 page_title: 'Edit an entry'
235 title_label: 'Title' 239 title_label: 'Title'
236 url_label: 'Url' 240 url_label: 'Url'
237 is_public_label: 'Public'
238 save_label: 'Save' 241 save_label: 'Save'
239 public: 242 public:
240 shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>" 243 shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 delete: Delete 513 delete: Delete
511 delete_confirm: Are you sure? 514 delete_confirm: Are you sure?
512 back_to_list: Back to list 515 back_to_list: Back to list
516 search:
517 placeholder: Filter by username or email
513 518
514error: 519error:
515 page_title: An error occurred 520 page_title: An error occurred
@@ -528,6 +533,7 @@ flashes:
528 annotations_reset: Annotations reset 533 annotations_reset: Annotations reset
529 tags_reset: Tags reset 534 tags_reset: Tags reset
530 entries_reset: Entries reset 535 entries_reset: Entries reset
536 archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Entry already saved on %date%' 539 entry_already_saved: 'Entry already saved on %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
index 3d65c311..6cd079b0 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
@@ -110,6 +110,7 @@ config:
110 annotations: Eliminar TODAS las anotaciones 110 annotations: Eliminar TODAS las anotaciones
111 tags: Eliminar TODAS las etiquetas 111 tags: Eliminar TODAS las etiquetas
112 entries: Eliminar TODOS los artículos 112 entries: Eliminar TODOS los artículos
113 # archived: Remove ALL archived entries
113 confirm: ¿Estás completamente seguro? (NO SE PUEDE DESHACER) 114 confirm: ¿Estás completamente seguro? (NO SE PUEDE DESHACER)
114 form_password: 115 form_password:
115 description: "Puedes cambiar la contraseña aquí. Tu nueva contraseña debe tener al menos 8 caracteres." 116 description: "Puedes cambiar la contraseña aquí. Tu nueva contraseña debe tener al menos 8 caracteres."
@@ -154,6 +155,7 @@ config:
154 or: 'Una regla U otra' 155 or: 'Una regla U otra'
155 and: 'Una regla Y la otra' 156 and: 'Una regla Y la otra'
156 matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>' 157 matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'original' 225 original_article: 'original'
224 annotations_on_the_entry: '{0} Sin anotaciones|{1} Una anotación|]1,Inf[ %count% anotaciones' 226 annotations_on_the_entry: '{0} Sin anotaciones|{1} Una anotación|]1,Inf[ %count% anotaciones'
225 created_at: 'Fecha de creación' 227 created_at: 'Fecha de creación'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Guardar un nuevo artículo' 231 page_title: 'Guardar un nuevo artículo'
228 placeholder: 'http://sitioweb.com' 232 placeholder: 'http://sitioweb.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Editar un artículo' 238 page_title: 'Editar un artículo'
235 title_label: 'Título' 239 title_label: 'Título'
236 url_label: 'URL' 240 url_label: 'URL'
237 is_public_label: 'Es público'
238 save_label: 'Guardar' 241 save_label: 'Guardar'
239 public: 242 public:
240 shared_by_wallabag: "Este artículo se ha compartido con <a href='%wallabag_instance%'>wallabag</a>" 243 shared_by_wallabag: "Este artículo se ha compartido con <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 delete: Eliminar 513 delete: Eliminar
511 delete_confirm: ¿Estás seguro? 514 delete_confirm: ¿Estás seguro?
512 back_to_list: Volver a la lista 515 back_to_list: Volver a la lista
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 page_title: Ha ocurrido un error 520 page_title: Ha ocurrido un error
@@ -528,6 +533,7 @@ flashes:
528 annotations_reset: Anotaciones reiniciadas 533 annotations_reset: Anotaciones reiniciadas
529 tags_reset: Etiquetas reiniciadas 534 tags_reset: Etiquetas reiniciadas
530 entries_reset: Artículos reiniciados 535 entries_reset: Artículos reiniciados
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Artículo ya guardado el %fecha%' 539 entry_already_saved: 'Artículo ya guardado el %fecha%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
index 80500d19..fb6e315e 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
@@ -110,6 +110,7 @@ config:
110 # annotations: Remove ALL annotations 110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags 111 # tags: Remove ALL tags
112 # entries: Remove ALL entries 112 # entries: Remove ALL entries
113 # archived: Remove ALL archived entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) 114 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 # description: "You can change your password here. Your new password should by at least 8 characters long." 116 # description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,6 +155,7 @@ config:
154 # or: 'One rule OR another' 155 # or: 'One rule OR another'
155 # and: 'One rule AND another' 156 # and: 'One rule AND another'
156 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 157 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'اصلی' 225 original_article: 'اصلی'
224 annotations_on_the_entry: '{0} بدون حاشیه|{1} یک حاشیه|]1,Inf[ %nbحاشیه% annotations' 226 annotations_on_the_entry: '{0} بدون حاشیه|{1} یک حاشیه|]1,Inf[ %nbحاشیه% annotations'
225 created_at: 'زمان ساخت' 227 created_at: 'زمان ساخت'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'ذخیرهٔ مقالهٔ تازه' 231 page_title: 'ذخیرهٔ مقالهٔ تازه'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'ویرایش مقاله' 238 page_title: 'ویرایش مقاله'
235 title_label: 'عنوان' 239 title_label: 'عنوان'
236 url_label: 'نشانی' 240 url_label: 'نشانی'
237 is_public_label: 'عمومی'
238 save_label: 'ذخیره' 241 save_label: 'ذخیره'
239 public: 242 public:
240 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>" 243 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 # delete: Delete 513 # delete: Delete
511 # delete_confirm: Are you sure? 514 # delete_confirm: Are you sure?
512 # back_to_list: Back to list 515 # back_to_list: Back to list
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 # page_title: An error occurred 520 # page_title: An error occurred
@@ -528,6 +533,7 @@ flashes:
528 # annotations_reset: Annotations reset 533 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset 534 # tags_reset: Tags reset
530 # entries_reset: Entries reset 535 # entries_reset: Entries reset
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود' 539 entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index 4f49f777..ad886363 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -46,7 +46,7 @@ footer:
46 social: "Social" 46 social: "Social"
47 powered_by: "propulsé par" 47 powered_by: "propulsé par"
48 about: "À propos" 48 about: "À propos"
49 stats: Depuis le %user_creation%, vous avez lu %nb_archives% articles. Ce qui fait %per_day% par jour ! 49 stats: "Depuis le %user_creation%, vous avez lu %nb_archives% articles. Ce qui fait %per_day% par jour !"
50 50
51config: 51config:
52 page_title: "Configuration" 52 page_title: "Configuration"
@@ -71,16 +71,16 @@ config:
71 300_word: "Je lis environ 300 mots par minute" 71 300_word: "Je lis environ 300 mots par minute"
72 400_word: "Je lis environ 400 mots par minute" 72 400_word: "Je lis environ 400 mots par minute"
73 action_mark_as_read: 73 action_mark_as_read:
74 label: 'Où souhaitez-vous être redirigé après avoir marqué un article comme lu ?' 74 label: "Où souhaitez-vous être redirigé après avoir marqué un article comme lu ?"
75 redirect_homepage: "À la page d'accueil" 75 redirect_homepage: "À la page d’accueil"
76 redirect_current_page: 'À la page courante' 76 redirect_current_page: "À la page courante"
77 pocket_consumer_key_label: Clé d’authentification Pocket pour importer les données 77 pocket_consumer_key_label: "Clé d’authentification Pocket pour importer les données"
78 android_configuration: Configurez votre application Android 78 android_configuration: "Configurez votre application Android"
79 help_theme: "L'affichage de wallabag est personnalisable. C'est ici que vous choisissez le thème que vous préférez." 79 help_theme: "L’affichage de wallabag est personnalisable. C’est ici que vous choisissez le thème que vous préférez."
80 help_items_per_page: "Vous pouvez définir le nombre d'articles affichés sur chaque page." 80 help_items_per_page: "Vous pouvez définir le nombre d’articles affichés sur chaque page."
81 help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article." 81 help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article."
82 help_language: "Vous pouvez définir la langue de l'interface de wallabag." 82 help_language: "Vous pouvez définir la langue de l’interface de wallabag."
83 help_pocket_consumer_key: "Nécessaire pour l'import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket." 83 help_pocket_consumer_key: "Nécessaire pour l’import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket."
84 form_rss: 84 form_rss:
85 description: "Les flux RSS fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton." 85 description: "Les flux RSS fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton."
86 token_label: "Jeton RSS" 86 token_label: "Jeton RSS"
@@ -100,17 +100,18 @@ config:
100 twoFactorAuthentication_label: "Double authentification" 100 twoFactorAuthentication_label: "Double authentification"
101 help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." 101 help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email."
102 delete: 102 delete:
103 title: Supprimer mon compte (attention danger !) 103 title: "Supprimer mon compte (attention danger !)"
104 description: Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c'est IRRÉVERSIBLE). Vous serez ensuite déconnecté. 104 description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté."
105 confirm: Vous êtes vraiment sûr ? (C'EST IRRÉVERSIBLE) 105 confirm: "Vous êtes vraiment sûr ? (C’EST IRRÉVERSIBLE)"
106 button: 'Supprimer mon compte' 106 button: "Supprimer mon compte"
107 reset: 107 reset:
108 title: Réinitialisation (attention danger !) 108 title: "Réinitialisation (attention danger !)"
109 description: En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES ! 109 description: "En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES !"
110 annotations: Supprimer TOUTES les annotations 110 annotations: "Supprimer TOUTES les annotations"
111 tags: Supprimer TOUS les tags 111 tags: "Supprimer TOUS les tags"
112 entries: Supprimer TOUS les articles 112 entries: "Supprimer TOUS les articles"
113 confirm: Êtes-vous vraiment vraiment sûr ? (C'EST IRRÉVERSIBLE) 113 archived: "Supprimer TOUS les articles archivés"
114 confirm: "Êtes-vous vraiment vraiment sûr ? (C’EST IRRÉVERSIBLE)"
114 form_password: 115 form_password:
115 description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères." 116 description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères."
116 old_password_label: "Mot de passe actuel" 117 old_password_label: "Mot de passe actuel"
@@ -154,6 +155,7 @@ config:
154 or: "Une règle OU l’autre" 155 or: "Une règle OU l’autre"
155 and: "Une règle ET l’autre" 156 and: "Une règle ET l’autre"
156 matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>" 157 matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>"
158 notmatches: "Teste si un <i>sujet</i> ne correspond pas à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title notmatches \"football\"</code>"
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -162,7 +164,7 @@ entry:
162 archived: "Articles lus" 164 archived: "Articles lus"
163 filtered: "Articles filtrés" 165 filtered: "Articles filtrés"
164 filtered_tags: "Articles filtrés par tags :" 166 filtered_tags: "Articles filtrés par tags :"
165 filtered_search: 'Articles filtrés par recherche :' 167 filtered_search: "Articles filtrés par recherche :"
166 untagged: "Article sans tag" 168 untagged: "Article sans tag"
167 list: 169 list:
168 number_on_the_page: "{0} Il n’y a pas d’article.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles." 170 number_on_the_page: "{0} Il n’y a pas d’article.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles."
@@ -186,7 +188,7 @@ entry:
186 preview_picture_label: "A une photo" 188 preview_picture_label: "A une photo"
187 preview_picture_help: "Photo" 189 preview_picture_help: "Photo"
188 language_label: "Langue" 190 language_label: "Langue"
189 http_status_label: 'Statut HTTP' 191 http_status_label: "Statut HTTP"
190 reading_time: 192 reading_time:
191 label: "Durée de lecture en minutes" 193 label: "Durée de lecture en minutes"
192 from: "de" 194 from: "de"
@@ -223,6 +225,8 @@ entry:
223 original_article: "original" 225 original_article: "original"
224 annotations_on_the_entry: "{0} Aucune annotation|{1} Une annotation|]1,Inf[ %count% annotations" 226 annotations_on_the_entry: "{0} Aucune annotation|{1} Une annotation|]1,Inf[ %count% annotations"
225 created_at: "Date de création" 227 created_at: "Date de création"
228 published_at: "Date de publication"
229 published_by: "Publié par"
226 new: 230 new:
227 page_title: "Sauvegarder un nouvel article" 231 page_title: "Sauvegarder un nouvel article"
228 placeholder: "http://website.com" 232 placeholder: "http://website.com"
@@ -234,7 +238,6 @@ entry:
234 page_title: "Éditer un article" 238 page_title: "Éditer un article"
235 title_label: "Titre" 239 title_label: "Titre"
236 url_label: "Adresse" 240 url_label: "Adresse"
237 is_public_label: "Public"
238 save_label: "Enregistrer" 241 save_label: "Enregistrer"
239 public: 242 public:
240 shared_by_wallabag: "Cet article a été partagé par <a href=\"%wallabag_instance%\">wallabag</a>" 243 shared_by_wallabag: "Cet article a été partagé par <a href=\"%wallabag_instance%\">wallabag</a>"
@@ -295,32 +298,32 @@ howto:
295 bookmarklet: 298 bookmarklet:
296 description: "Glissez et déposez ce lien dans votre barre de favoris :" 299 description: "Glissez et déposez ce lien dans votre barre de favoris :"
297 shortcuts: 300 shortcuts:
298 page_description: Voici les raccourcis disponibles dans wallabag. 301 page_description: "Voici les raccourcis disponibles dans wallabag."
299 shortcut: Raccourci 302 shortcut: "Raccourci"
300 action: Action 303 action: "Action"
301 all_pages_title: Raccourcis disponibles dans toutes les pages 304 all_pages_title: "Raccourcis disponibles dans toutes les pages"
302 go_unread: Afficher les articles non lus 305 go_unread: "Afficher les articles non lus"
303 go_starred: Afficher les articles favoris 306 go_starred: "Afficher les articles favoris"
304 go_archive: Afficher les articles lus 307 go_archive: "Afficher les articles lus"
305 go_all: Afficher tous les articles 308 go_all: "Afficher tous les articles"
306 go_tags: Afficher les tags 309 go_tags: "Afficher les tags"
307 go_config: Aller à la configuration 310 go_config: "Aller à la configuration"
308 go_import: Aller aux imports 311 go_import: "Aller aux imports"
309 go_developers: Aller à la section Développeurs 312 go_developers: "Aller à la section Développeurs"
310 go_howto: Afficher l'aide (cette page !) 313 go_howto: "Afficher l’aide (cette page !)"
311 go_logout: Se déconnecter 314 go_logout: "Se déconnecter"
312 list_title: Raccourcis disponibles dans les pages de liste 315 list_title: "Raccourcis disponibles dans les pages de liste"
313 search: Afficher le formulaire de recherche 316 search: "Afficher le formulaire de recherche"
314 article_title: Raccourcis disponibles quand on affiche un article 317 article_title: "Raccourcis disponibles quand on affiche un article"
315 open_original: Ouvrir l'URL originale de l'article 318 open_original: "Ouvrir l’URL originale de l’article"
316 toggle_favorite: Changer le statut Favori de l'article 319 toggle_favorite: "Changer le statut Favori de l’article"
317 toggle_archive: Changer le status Lu de l'article 320 toggle_archive: "Changer le status Lu de l’article"
318 delete: Supprimer l'article 321 delete: "Supprimer l’article"
319 material_title: Raccourcis disponibles avec le thème Material uniquement 322 material_title: "Raccourcis disponibles avec le thème Material uniquement"
320 add_link: Ajouter un nouvel article 323 add_link: "Ajouter un nouvel article"
321 hide_form: Masquer le formulaire courant (recherche ou nouvel article) 324 hide_form: "Masquer le formulaire courant (recherche ou nouvel article)"
322 arrows_navigation: Naviguer à travers les articles 325 arrows_navigation: "Naviguer à travers les articles"
323 open_article: Afficher l'article sélectionné 326 open_article: "Afficher l’article sélectionné"
324 327
325quickstart: 328quickstart:
326 page_title: "Pour bien débuter" 329 page_title: "Pour bien débuter"
@@ -382,8 +385,8 @@ tag:
382 number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." 385 number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags."
383 see_untagged_entries: "Voir les articles sans tag" 386 see_untagged_entries: "Voir les articles sans tag"
384 new: 387 new:
385 add: 'Ajouter' 388 add: "Ajouter"
386 placeholder: 'Vous pouvez ajouter plusieurs tags, séparés par une virgule.' 389 placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule."
387 390
388import: 391import:
389 page_title: "Importer" 392 page_title: "Importer"
@@ -417,7 +420,7 @@ import:
417 how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l’importer." 420 how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l’importer."
418 worker: 421 worker:
419 enabled: "Les imports sont asynchrones. Une fois l’import commencé un worker externe traitera les messages un par un. Le service activé est :" 422 enabled: "Les imports sont asynchrones. Une fois l’import commencé un worker externe traitera les messages un par un. Le service activé est :"
420 download_images_warning: "Vous avez configuré le téléchagement des images pour vos articles. Combiné à l'import classique, cette opération peut être très très longue (voire échouer). Nous vous conseillons <strong>vivement</strong> d'activer les imports asynchrones." 423 download_images_warning: "Vous avez configuré le téléchagement des images pour vos articles. Combiné à l’import classique, cette opération peut être très très longue (voire échouer). Nous vous conseillons <strong>vivement</strong> d’activer les imports asynchrones."
421 firefox: 424 firefox:
422 page_title: "Import > Firefox" 425 page_title: "Import > Firefox"
423 description: "Cet outil va vous permettre d’importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde… ». Vous allez récupérer un fichier .json. </p>" 426 description: "Cet outil va vous permettre d’importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde… ». Vous allez récupérer un fichier .json. </p>"
@@ -486,16 +489,16 @@ developer:
486 back: "Retour" 489 back: "Retour"
487 490
488user: 491user:
489 page_title: Gestion des utilisateurs 492 page_title: "Gestion des utilisateurs"
490 new_user: Créer un nouvel utilisateur 493 new_user: "Créer un nouvel utilisateur"
491 edit_user: Éditer un utilisateur existant 494 edit_user: "Éditer un utilisateur existant"
492 description: Ici vous pouvez gérer vos utilisateurs (création, mise à jour et suppression) 495 description: "Ici vous pouvez gérer vos utilisateurs (création, mise à jour et suppression)"
493 list: 496 list:
494 actions: Actions 497 actions: "Actions"
495 edit_action: Éditer 498 edit_action: "Éditer"
496 yes: Oui 499 yes: "Oui"
497 no: Non 500 no: "Non"
498 create_new_one: Créer un nouvel utilisateur 501 create_new_one: "Créer un nouvel utilisateur"
499 form: 502 form:
500 username_label: "Nom d’utilisateur" 503 username_label: "Nom d’utilisateur"
501 name_label: "Nom" 504 name_label: "Nom"
@@ -510,9 +513,11 @@ user:
510 delete: "Supprimer" 513 delete: "Supprimer"
511 delete_confirm: "Voulez-vous vraiment ?" 514 delete_confirm: "Voulez-vous vraiment ?"
512 back_to_list: "Revenir à la liste" 515 back_to_list: "Revenir à la liste"
516 search:
517 placeholder: "Filtrer par nom d’utilisateur ou email"
513 518
514error: 519error:
515 page_title: Une erreur est survenue 520 page_title: "Une erreur est survenue"
516 521
517flashes: 522flashes:
518 config: 523 config:
@@ -525,9 +530,10 @@ flashes:
525 tagging_rules_updated: "Règles mises à jour" 530 tagging_rules_updated: "Règles mises à jour"
526 tagging_rules_deleted: "Règle supprimée" 531 tagging_rules_deleted: "Règle supprimée"
527 rss_token_updated: "Jeton RSS mis à jour" 532 rss_token_updated: "Jeton RSS mis à jour"
528 annotations_reset: Annotations supprimées 533 annotations_reset: "Annotations supprimées"
529 tags_reset: Tags supprimés 534 tags_reset: "Tags supprimés"
530 entries_reset: Articles supprimés 535 entries_reset: "Articles supprimés"
536 archived_reset: "Articles archivés supprimés"
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: "Article déjà sauvegardé le %date%" 539 entry_already_saved: "Article déjà sauvegardé le %date%"
@@ -559,6 +565,6 @@ flashes:
559 client_deleted: "Client %name% supprimé" 565 client_deleted: "Client %name% supprimé"
560 user: 566 user:
561 notice: 567 notice:
562 added: 'Utilisateur "%username%" ajouté' 568 added: "Utilisateur \"%username%\" ajouté"
563 updated: 'Utilisateur "%username%" mis à jour' 569 updated: "Utilisateur \"%username%\" mis à jour"
564 deleted: 'Utilisateur "%username%" supprimé' 570 deleted: "Utilisateur \"%username%\" supprimé"
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
index 992ff71c..5a9605ff 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
@@ -110,6 +110,7 @@ config:
110 # annotations: Remove ALL annotations 110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags 111 # tags: Remove ALL tags
112 # entries: Remove ALL entries 112 # entries: Remove ALL entries
113 # archived: Remove ALL archived entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) 114 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 # description: "You can change your password here. Your new password should by at least 8 characters long." 116 # description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,6 +155,7 @@ config:
154 or: "Una regola O un'altra" 155 or: "Una regola O un'altra"
155 and: "Una regola E un'altra" 156 and: "Una regola E un'altra"
156 matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>' 157 matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'originale' 225 original_article: 'originale'
224 annotations_on_the_entry: '{0} Nessuna annotazione|{1} Una annotazione|]1,Inf[ %count% annotazioni' 226 annotations_on_the_entry: '{0} Nessuna annotazione|{1} Una annotazione|]1,Inf[ %count% annotazioni'
225 created_at: 'Data di creazione' 227 created_at: 'Data di creazione'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Salva un nuovo contenuto' 231 page_title: 'Salva un nuovo contenuto'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Modifica voce' 238 page_title: 'Modifica voce'
235 title_label: 'Titolo' 239 title_label: 'Titolo'
236 url_label: 'Url' 240 url_label: 'Url'
237 is_public_label: 'Pubblico'
238 save_label: 'Salva' 241 save_label: 'Salva'
239 public: 242 public:
240 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>" 243 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 # delete: Delete 513 # delete: Delete
511 # delete_confirm: Are you sure? 514 # delete_confirm: Are you sure?
512 # back_to_list: Back to list 515 # back_to_list: Back to list
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 # page_title: An error occurred 520 # page_title: An error occurred
@@ -528,6 +533,7 @@ flashes:
528 # annotations_reset: Annotations reset 533 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset 534 # tags_reset: Tags reset
530 # entries_reset: Entries reset 535 # entries_reset: Entries reset
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Contenuto già salvato in data %date%' 539 entry_already_saved: 'Contenuto già salvato in data %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
index f6488565..942bc257 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
@@ -110,6 +110,7 @@ config:
110 annotations: Levar TOTAS las anotacions 110 annotations: Levar TOTAS las anotacions
111 tags: Levar TOTAS las etiquetas 111 tags: Levar TOTAS las etiquetas
112 entries: Levar TOTES los articles 112 entries: Levar TOTES los articles
113 # archived: Remove ALL archived entries
113 confirm: Sètz vertadièrament segur ? (ES IRREVERSIBLE) 114 confirm: Sètz vertadièrament segur ? (ES IRREVERSIBLE)
114 form_password: 115 form_password:
115 description: "Podètz cambiar vòstre senhal aquí. Vòstre senhal deu èsser long d'almens 8 caractèrs." 116 description: "Podètz cambiar vòstre senhal aquí. Vòstre senhal deu èsser long d'almens 8 caractèrs."
@@ -154,6 +155,7 @@ config:
154 or: "Una règla O l'autra" 155 or: "Una règla O l'autra"
155 and: "Una règla E l'autra" 156 and: "Una règla E l'autra"
156 matches: 'Teste se un <i>subjècte</i> correspond a una <i>recerca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>' 157 matches: 'Teste se un <i>subjècte</i> correspond a una <i>recerca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'original' 225 original_article: 'original'
224 annotations_on_the_entry: "{0} Pas cap d'anotacion|{1} Una anotacion|]1,Inf[ %count% anotacions" 226 annotations_on_the_entry: "{0} Pas cap d'anotacion|{1} Una anotacion|]1,Inf[ %count% anotacions"
225 created_at: 'Data de creacion' 227 created_at: 'Data de creacion'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Enregistrar un novèl article' 231 page_title: 'Enregistrar un novèl article'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Modificar un article' 238 page_title: 'Modificar un article'
235 title_label: 'Títol' 239 title_label: 'Títol'
236 url_label: 'Url' 240 url_label: 'Url'
237 is_public_label: 'Public'
238 save_label: 'Enregistrar' 241 save_label: 'Enregistrar'
239 public: 242 public:
240 shared_by_wallabag: "Aqueste article es estat partejat per <a href='%wallabag_instance%'>wallabag</a>" 243 shared_by_wallabag: "Aqueste article es estat partejat per <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 delete: 'Suprimir' 513 delete: 'Suprimir'
511 delete_confirm: 'Sètz segur ?' 514 delete_confirm: 'Sètz segur ?'
512 back_to_list: 'Tornar a la lista' 515 back_to_list: 'Tornar a la lista'
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 page_title: Una error s'es produsida 520 page_title: Una error s'es produsida
@@ -528,6 +533,7 @@ flashes:
528 annotations_reset: Anotacions levadas 533 annotations_reset: Anotacions levadas
529 tags_reset: Etiquetas levadas 534 tags_reset: Etiquetas levadas
530 entries_reset: Articles levats 535 entries_reset: Articles levats
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Article ja salvargardat lo %date%' 539 entry_already_saved: 'Article ja salvargardat lo %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
index eda9bbbf..fea90440 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
@@ -110,6 +110,7 @@ config:
110 annotations: Usuń WSZYSTKIE adnotacje 110 annotations: Usuń WSZYSTKIE adnotacje
111 tags: Usuń WSZYSTKIE tagi 111 tags: Usuń WSZYSTKIE tagi
112 entries: usuń WSZYTSTKIE wpisy 112 entries: usuń WSZYTSTKIE wpisy
113 # archived: Remove ALL archived entries
113 confirm: Jesteś pewien? (tej operacji NIE MOŻNA cofnąć) 114 confirm: Jesteś pewien? (tej operacji NIE MOŻNA cofnąć)
114 form_password: 115 form_password:
115 description: "Tutaj możesz zmienić swoje hasło. Twoje nowe hasło powinno mieć conajmniej 8 znaków." 116 description: "Tutaj możesz zmienić swoje hasło. Twoje nowe hasło powinno mieć conajmniej 8 znaków."
@@ -154,6 +155,7 @@ config:
154 or: 'Jedna reguła LUB inna' 155 or: 'Jedna reguła LUB inna'
155 and: 'Jedna reguła I inna' 156 and: 'Jedna reguła I inna'
156 matches: 'Sprawdź czy <i>temat</i> pasuje <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł zawiera "piłka nożna"</code>' 157 matches: 'Sprawdź czy <i>temat</i> pasuje <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł zawiera "piłka nożna"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'oryginalny' 225 original_article: 'oryginalny'
224 annotations_on_the_entry: '{0} Nie ma adnotacji |{1} Jedna adnotacja |]1,Inf[ %count% adnotacji' 226 annotations_on_the_entry: '{0} Nie ma adnotacji |{1} Jedna adnotacja |]1,Inf[ %count% adnotacji'
225 created_at: 'Czas stworzenia' 227 created_at: 'Czas stworzenia'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Zapisz nowy wpis' 231 page_title: 'Zapisz nowy wpis'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Edytuj wpis' 238 page_title: 'Edytuj wpis'
235 title_label: 'Tytuł' 239 title_label: 'Tytuł'
236 url_label: 'Adres URL' 240 url_label: 'Adres URL'
237 is_public_label: 'Publiczny'
238 save_label: 'Zapisz' 241 save_label: 'Zapisz'
239 public: 242 public:
240 shared_by_wallabag: "Ten artykuł został udostępniony przez <a href='%wallabag_instance%'>wallabag</a>" 243 shared_by_wallabag: "Ten artykuł został udostępniony przez <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 delete: Usuń 513 delete: Usuń
511 delete_confirm: JesteÅ› pewien? 514 delete_confirm: JesteÅ› pewien?
512 back_to_list: Powrót do listy 515 back_to_list: Powrót do listy
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 page_title: Wystąpił błąd 520 page_title: Wystąpił błąd
@@ -528,6 +533,7 @@ flashes:
528 annotations_reset: Zresetuj adnotacje 533 annotations_reset: Zresetuj adnotacje
529 tags_reset: Zresetuj tagi 534 tags_reset: Zresetuj tagi
530 entries_reset: Zresetuj wpisy 535 entries_reset: Zresetuj wpisy
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Wpis już został dodany %date%' 539 entry_already_saved: 'Wpis już został dodany %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
index 8a7cc6f8..c59991f8 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
@@ -110,6 +110,7 @@ config:
110 # annotations: Remove ALL annotations 110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags 111 # tags: Remove ALL tags
112 # entries: Remove ALL entries 112 # entries: Remove ALL entries
113 # archived: Remove ALL archived entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) 114 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 # description: "You can change your password here. Your new password should by at least 8 characters long." 116 # description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,6 +155,7 @@ config:
154 or: 'Uma regra OU outra' 155 or: 'Uma regra OU outra'
155 and: 'Uma regra E outra' 156 and: 'Uma regra E outra'
156 matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>' 157 matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'original' 225 original_article: 'original'
224 annotations_on_the_entry: '{0} Sem anotações|{1} Uma anotação|]1,Inf[ %nbAnnotations% anotações' 226 annotations_on_the_entry: '{0} Sem anotações|{1} Uma anotação|]1,Inf[ %nbAnnotations% anotações'
225 created_at: 'Data de criação' 227 created_at: 'Data de criação'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Salvar nova entrada' 231 page_title: 'Salvar nova entrada'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Editar uma entrada' 238 page_title: 'Editar uma entrada'
235 title_label: 'Título' 239 title_label: 'Título'
236 url_label: 'Url' 240 url_label: 'Url'
237 is_public_label: 'Público'
238 save_label: 'Salvar' 241 save_label: 'Salvar'
239 public: 242 public:
240 shared_by_wallabag: "Este artigo foi compartilhado pelo <a href='%wallabag_instance%'>wallabag</a>" 243 shared_by_wallabag: "Este artigo foi compartilhado pelo <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 delete: 'Apagar' 513 delete: 'Apagar'
511 delete_confirm: 'Tem certeza?' 514 delete_confirm: 'Tem certeza?'
512 back_to_list: 'Voltar para a lista' 515 back_to_list: 'Voltar para a lista'
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 # page_title: An error occurred 520 # page_title: An error occurred
@@ -528,6 +533,7 @@ flashes:
528 # annotations_reset: Annotations reset 533 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset 534 # tags_reset: Tags reset
530 # entries_reset: Entries reset 535 # entries_reset: Entries reset
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Entrada já foi salva em %date%' 539 entry_already_saved: 'Entrada já foi salva em %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
index 52b6414f..5846b7cc 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
@@ -110,6 +110,7 @@ config:
110 # annotations: Remove ALL annotations 110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags 111 # tags: Remove ALL tags
112 # entries: Remove ALL entries 112 # entries: Remove ALL entries
113 # archived: Remove ALL archived entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) 114 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 # description: "You can change your password here. Your new password should by at least 8 characters long." 116 # description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,6 +155,7 @@ config:
154 # or: 'One rule OR another' 155 # or: 'One rule OR another'
155 # and: 'One rule AND another' 156 # and: 'One rule AND another'
156 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 157 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'original' 225 original_article: 'original'
224 # annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations' 226 # annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
225 created_at: 'Data creării' 227 created_at: 'Data creării'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Salvează un nou articol' 231 page_title: 'Salvează un nou articol'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 # page_title: 'Edit an entry' 238 # page_title: 'Edit an entry'
235 # title_label: 'Title' 239 # title_label: 'Title'
236 url_label: 'Url' 240 url_label: 'Url'
237 # is_public_label: 'Public'
238 save_label: 'Salvează' 241 save_label: 'Salvează'
239 public: 242 public:
240 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>" 243 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 # delete: Delete 513 # delete: Delete
511 # delete_confirm: Are you sure? 514 # delete_confirm: Are you sure?
512 # back_to_list: Back to list 515 # back_to_list: Back to list
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 # page_title: An error occurred 520 # page_title: An error occurred
@@ -528,6 +533,7 @@ flashes:
528 # annotations_reset: Annotations reset 533 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset 534 # tags_reset: Tags reset
530 # entries_reset: Entries reset 535 # entries_reset: Entries reset
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 # entry_already_saved: 'Entry already saved on %date%' 539 # entry_already_saved: 'Entry already saved on %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
index bfb7e206..430fb96b 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
@@ -110,6 +110,7 @@ config:
110 # annotations: Remove ALL annotations 110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags 111 # tags: Remove ALL tags
112 # entries: Remove ALL entries 112 # entries: Remove ALL entries
113 # archived: Remove ALL archived entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) 114 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
114 form_password: 115 form_password:
115 # description: "You can change your password here. Your new password should by at least 8 characters long." 116 # description: "You can change your password here. Your new password should by at least 8 characters long."
@@ -154,6 +155,7 @@ config:
154 or: 'Bir kural veya birbaşkası' 155 or: 'Bir kural veya birbaşkası'
155 and: 'Bir kural ve diÄŸeri' 156 and: 'Bir kural ve diÄŸeri'
156 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 157 # matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
158 # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
157 159
158entry: 160entry:
159 page_titles: 161 page_titles:
@@ -223,6 +225,8 @@ entry:
223 original_article: 'orijinal' 225 original_article: 'orijinal'
224 # annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations' 226 # annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
225 created_at: 'OluÅŸturulma tarihi' 227 created_at: 'OluÅŸturulma tarihi'
228 # published_at: 'Publication date'
229 # published_by: 'Published by'
226 new: 230 new:
227 page_title: 'Yeni makaleyi kaydet' 231 page_title: 'Yeni makaleyi kaydet'
228 placeholder: 'http://website.com' 232 placeholder: 'http://website.com'
@@ -234,7 +238,6 @@ entry:
234 page_title: 'Makaleyi düzenle' 238 page_title: 'Makaleyi düzenle'
235 title_label: 'Başlık' 239 title_label: 'Başlık'
236 url_label: 'Url' 240 url_label: 'Url'
237 is_public_label: 'Herkes tarafından erişime açık olsun mu?'
238 save_label: 'Kaydet' 241 save_label: 'Kaydet'
239 public: 242 public:
240 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>" 243 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>"
@@ -510,6 +513,8 @@ user:
510 # delete: Delete 513 # delete: Delete
511 # delete_confirm: Are you sure? 514 # delete_confirm: Are you sure?
512 # back_to_list: Back to list 515 # back_to_list: Back to list
516 search:
517 # placeholder: Filter by username or email
513 518
514error: 519error:
515 # page_title: An error occurred 520 # page_title: An error occurred
@@ -528,6 +533,7 @@ flashes:
528 # annotations_reset: Annotations reset 533 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset 534 # tags_reset: Tags reset
530 # entries_reset: Entries reset 535 # entries_reset: Entries reset
536 # archived_reset: Archived entries deleted
531 entry: 537 entry:
532 notice: 538 notice:
533 entry_already_saved: 'Entry already saved on %date%' 539 entry_already_saved: 'Entry already saved on %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
index 3548f590..01f63a7b 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
@@ -200,6 +200,11 @@
200 </a> 200 </a>
201 </li> 201 </li>
202 <li> 202 <li>
203 <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
204 {{ 'config.reset.archived'|trans }}
205 </a>
206 </li>
207 <li>
203 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> 208 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
204 {{ 'config.reset.entries'|trans }} 209 {{ 'config.reset.entries'|trans }}
205 </a> 210 </a>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
index 859b166b..bdd44b54 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
@@ -17,9 +17,9 @@
17 <div class="results"> 17 <div class="results">
18 <div class="nb-results">{{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}</div> 18 <div class="nb-results">{{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}</div>
19 <div class="pagination"> 19 <div class="pagination">
20 <a href="{{ path('switch_view_mode') }}"><i class="listMode-btn material-icons md-36">{% if listMode == 0 %}list{% else %}view_module{% endif %}</i></a> 20 <a href="{{ path('switch_view_mode') }}"><i class="listMode-btn material-icons md-24">{% if listMode == 0 %}list{% else %}view_module{% endif %}</i></a>
21 <i class="btn-clickable download-btn material-icons md-36 js-export-action">file_download</i> 21 <i class="btn-clickable download-btn material-icons md-24 js-export-action">file_download</i>
22 <i class="btn-clickable filter-btn material-icons md-36 js-filters-action">filter_list</i> 22 <i class="btn-clickable filter-btn material-icons md-24 js-filters-action">filter_list</i>
23 {% if entries.getNbPages > 1 %} 23 {% if entries.getNbPages > 1 %}
24 {{ pagerfanta(entries, 'twitter_bootstrap_translated', {'proximity': 1}) }} 24 {{ pagerfanta(entries, 'twitter_bootstrap_translated', {'proximity': 1}) }}
25 {% endif %} 25 {% endif %}
@@ -47,10 +47,10 @@
47 </div> 47 </div>
48 48
49 <ul class="tools links"> 49 <ul class="tools links">
50 <li><a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool icon-check icon {% if entry.isArchived == 0 %}archive-off{% else %}archive{% endif %}" href="{{ path('archive_entry', { 'id': entry.id }) }}"><span>{{ 'entry.list.toogle_as_read'|trans }}</span></a></li> 50 <li><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.list.original_article'|trans }} : {{ entry.title|e }}"><span>{{ entry.domainName|removeWww }}</span></a></li>
51 <li><a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool icon-star icon {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"><span>{{ 'entry.list.toogle_as_star'|trans }}</span></a></li> 51 <li><a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool icon {% if entry.isArchived == 0 %}archive-off{% else %}archive{% endif %}" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons md-24 vertical-align-middle">check</i><span>{{ 'entry.list.toogle_as_read'|trans }}</span></a></li>
52 <li><a title="{{ 'entry.list.delete'|trans }}" class="tool delete icon-trash icon" href="{{ path('delete_entry', { 'id': entry.id }) }}"><span>{{ 'entry.list.delete'|trans }}</span></a></li> 52 <li><a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool icon {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"><i class="material-icons md-24 vertical-align-middle">star_rate</i><span>{{ 'entry.list.toogle_as_star'|trans }}</span></a></li>
53 <li><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.list.original_article'|trans }} : {{ entry.title|e }}" class="tool link icon-link icon"><span>{{ entry.domainName|removeWww }}</span></a></li> 53 <li><a title="{{ 'entry.list.delete'|trans }}" class="tool icon" href="{{ path('delete_entry', { 'id': entry.id }) }}"><i class="material-icons md-24 vertical-align-middle">delete</i><span>{{ 'entry.list.delete'|trans }}</span></a></li>
54 </ul> 54 </ul>
55 {% if (entry.previewPicture is null or listMode == 1) %} 55 {% if (entry.previewPicture is null or listMode == 1) %}
56 <ul class="card-entry-tags"> 56 <ul class="card-entry-tags">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
index a555691d..660211f2 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
@@ -30,6 +30,7 @@
30 {% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %} 30 {% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %}
31 {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %} 31 {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %}
32 {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}" target="_blank" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %} 32 {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}" target="_blank" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %}
33 {% if craue_setting('share_scuttle') %}<li><a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&amp;address={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}" target="_blank" class="tool icon-image icon-image--scuttle" title="scuttle"><span>scuttle</span></a></li>{% endif %}
33 {% if craue_setting('share_diaspora') %}<li><a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&notes=&v=1&noui=1&jump=doclose" target="_blank" class="tool diaspora icon-image icon-image--diaspora" title="diaspora"><span>diaspora</span></a></li>{% endif %} 34 {% if craue_setting('share_diaspora') %}<li><a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&notes=&v=1&noui=1&jump=doclose" target="_blank" class="tool diaspora icon-image icon-image--diaspora" title="diaspora"><span>diaspora</span></a></li>{% endif %}
34 {% if craue_setting('share_unmark') %}<li><a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|url_encode}}&amp;v=6" target="_blank" class="tool unmark icon-image icon-image--unmark" title="unmark"><span>unmark.it</span></a></li>{% endif %} 35 {% if craue_setting('share_unmark') %}<li><a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|url_encode}}&amp;v=6" target="_blank" class="tool unmark icon-image icon-image--unmark" title="unmark"><span>unmark.it</span></a></li>{% endif %}
35 {% if craue_setting('carrot') %}<li><a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" class="tool carrot icon-image icon-image--carrot" target="_blank" title="carrot"><span>Carrot</span></a></li>{% endif %} 36 {% if craue_setting('carrot') %}<li><a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" class="tool carrot icon-image icon-image--carrot" target="_blank" title="carrot"><span>Carrot</span></a></li>{% endif %}
@@ -43,9 +44,23 @@
43 44
44 <div id="article-informations"> 45 <div id="article-informations">
45 <i class="tool icon icon-calendar" title="{{ 'entry.view.created_at'|trans }}"> 46 <i class="tool icon icon-calendar" title="{{ 'entry.view.created_at'|trans }}">
46 {{ entry.createdAt|date('Y-m-d') }} 47 {{ entry.createdAt|date('Y-m-d H:i') }}
47 </i> 48 </i>
48 49
50 {% if entry.publishedAt is not null %}
51 <i class="tool icon icon-pencil2" title="{{ 'entry.view.published_at'|trans }}">
52 {{ entry.publishedAt|date('Y-m-d H:i') }}
53 </i>
54 {% endif %}
55
56 {% if entry.publishedBy is not empty %}
57 <i class="tool icon icon-users" title="{{ 'entry.view.published_by'|trans }}">
58 {% for author in entry.publishedBy %}
59 {{ author }}{% if not loop.last %}, {% endif %}
60 {% endfor %}
61 </i>
62 {% endif %}
63
49 <i class="tool icon icon-time"> 64 <i class="tool icon icon-time">
50 {% set readingTime = entry.readingTime / app.user.config.readingSpeed %} 65 {% set readingTime = entry.readingTime / app.user.config.readingSpeed %}
51 {% if readingTime > 0 %} 66 {% if readingTime > 0 %}
@@ -62,7 +77,7 @@
62 <span class="label-outline"><i class="material-icons">label_outline</i> <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a> <a href="{{ path('remove_tag', { 'entry': entry.id, 'tag': tag.id }) }}" class="nostyle"><i>✘</i></a></span> 77 <span class="label-outline"><i class="material-icons">label_outline</i> <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a> <a href="{{ path('remove_tag', { 'entry': entry.id, 'tag': tag.id }) }}" class="nostyle"><i>✘</i></a></span>
63 {% endfor %} 78 {% endfor %}
64 </div> 79 </div>
65 <div class="input-field nav-panel-add-tag" style="display: none"> 80 <div class="input-field baggy-add-tag" style="display: none">
66 {{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }} 81 {{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }}
67 </div> 82 </div>
68 </aside> 83 </aside>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
index 07ff8e14..42aeace9 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
@@ -2,12 +2,14 @@
2 2
3{% block css %} 3{% block css %}
4 {{ parent() }} 4 {{ parent() }}
5 <link rel="stylesheet" href="{{ asset('bundles/wallabagcore/themes/baggy/css/style.min.css') }}" media="screen,projection,print"/> 5 {% if not app.debug %}
6 <link rel="stylesheet" href="{{ asset('bundles/wallabagcore/baggy.css') }}">
7 {% endif %}
6{% endblock %} 8{% endblock %}
7 9
8{% block scripts %} 10{% block scripts %}
9 {{ parent() }} 11 {{ parent() }}
10 <script src="{{ asset('bundles/wallabagcore/themes/baggy/js/baggy.min.js') }}"></script> 12 <script src="{{ asset('bundles/wallabagcore/baggy' ~ (app.debug ? '.dev' : '') ~ '.js') }}"></script>
11{% endblock %} 13{% endblock %}
12 14
13{% block header %} 15{% block header %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
index 5d411fdd..9b0816eb 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
@@ -25,9 +25,9 @@
25 25
26 <div class="row"> 26 <div class="row">
27 <div class="input-field col s11"> 27 <div class="input-field col s11">
28 {{ form_label(form.config.theme) }}
29 {{ form_errors(form.config.theme) }} 28 {{ form_errors(form.config.theme) }}
30 {{ form_widget(form.config.theme) }} 29 {{ form_widget(form.config.theme) }}
30 {{ form_label(form.config.theme) }}
31 </div> 31 </div>
32 <div class="input-field col s1"> 32 <div class="input-field col s1">
33 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_theme'|trans }}"> 33 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_theme'|trans }}">
@@ -38,9 +38,9 @@
38 38
39 <div class="row"> 39 <div class="row">
40 <div class="input-field col s11"> 40 <div class="input-field col s11">
41 {{ form_label(form.config.items_per_page) }}
42 {{ form_errors(form.config.items_per_page) }} 41 {{ form_errors(form.config.items_per_page) }}
43 {{ form_widget(form.config.items_per_page) }} 42 {{ form_widget(form.config.items_per_page) }}
43 {{ form_label(form.config.items_per_page) }}
44 </div> 44 </div>
45 <div class="input-field col s1"> 45 <div class="input-field col s1">
46 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_items_per_page'|trans }}"> 46 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_items_per_page'|trans }}">
@@ -51,9 +51,9 @@
51 51
52 <div class="row"> 52 <div class="row">
53 <div class="input-field col s11"> 53 <div class="input-field col s11">
54 {{ form_label(form.config.reading_speed) }}
55 {{ form_errors(form.config.reading_speed) }} 54 {{ form_errors(form.config.reading_speed) }}
56 {{ form_widget(form.config.reading_speed) }} 55 {{ form_widget(form.config.reading_speed) }}
56 {{ form_label(form.config.reading_speed) }}
57 <p> 57 <p>
58 {{ 'config.form_settings.reading_speed.help_message'|trans }} 58 {{ 'config.form_settings.reading_speed.help_message'|trans }}
59 <a href="http://www.myreadspeed.com/calculate/">myreadspeed</a> 59 <a href="http://www.myreadspeed.com/calculate/">myreadspeed</a>
@@ -68,17 +68,17 @@
68 68
69 <div class="row"> 69 <div class="row">
70 <div class="input-field col s12"> 70 <div class="input-field col s12">
71 {{ form_label(form.config.action_mark_as_read) }}
72 {{ form_errors(form.config.action_mark_as_read) }} 71 {{ form_errors(form.config.action_mark_as_read) }}
73 {{ form_widget(form.config.action_mark_as_read) }} 72 {{ form_widget(form.config.action_mark_as_read) }}
73 {{ form_label(form.config.action_mark_as_read) }}
74 </div> 74 </div>
75 </div> 75 </div>
76 76
77 <div class="row"> 77 <div class="row">
78 <div class="input-field col s11"> 78 <div class="input-field col s11">
79 {{ form_label(form.config.language) }}
80 {{ form_errors(form.config.language) }} 79 {{ form_errors(form.config.language) }}
81 {{ form_widget(form.config.language) }} 80 {{ form_widget(form.config.language) }}
81 {{ form_label(form.config.language) }}
82 </div> 82 </div>
83 <div class="input-field col s1"> 83 <div class="input-field col s1">
84 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_language'|trans }}"> 84 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_language'|trans }}">
@@ -89,9 +89,9 @@
89 89
90 <div class="row"> 90 <div class="row">
91 <div class="input-field col s11"> 91 <div class="input-field col s11">
92 {{ form_label(form.config.pocket_consumer_key) }}
93 {{ form_errors(form.config.pocket_consumer_key) }} 92 {{ form_errors(form.config.pocket_consumer_key) }}
94 {{ form_widget(form.config.pocket_consumer_key) }} 93 {{ form_widget(form.config.pocket_consumer_key) }}
94 {{ form_label(form.config.pocket_consumer_key) }}
95 <p> 95 <p>
96 &raquo; 96 &raquo;
97 <a href="https://getpocket.com/developer/docs/authentication">https://getpocket.com/developer/docs/authentication</a> 97 <a href="https://getpocket.com/developer/docs/authentication">https://getpocket.com/developer/docs/authentication</a>
@@ -132,8 +132,8 @@
132 </div> 132 </div>
133 133
134 <div class="row"> 134 <div class="row">
135 <div class="input-field col s12"> 135 <div class="col s12">
136 <label>{{ 'config.form_rss.token_label'|trans }}</label> 136 <h6 class="grey-text">{{ 'config.form_rss.token_label'|trans }}</h6>
137 <div> 137 <div>
138 {% if rss.token %} 138 {% if rss.token %}
139 {{ rss.token }} 139 {{ rss.token }}
@@ -151,8 +151,8 @@
151 </div> 151 </div>
152 {% if rss.token %} 152 {% if rss.token %}
153 <div class="row"> 153 <div class="row">
154 <div class="input-field col s12"> 154 <div class="col s12">
155 <label>{{ 'config.form_rss.rss_links'|trans }}</label> 155 <h6 class="grey-text">{{ 'config.form_rss.rss_links'|trans }}</h6>
156 <ul> 156 <ul>
157 <li><a href="{{ path('unread_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.unread'|trans }}</a></li> 157 <li><a href="{{ path('unread_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.unread'|trans }}</a></li>
158 <li><a href="{{ path('starred_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.starred'|trans }}</a></li> 158 <li><a href="{{ path('starred_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.starred'|trans }}</a></li>
@@ -229,6 +229,9 @@
229 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> 229 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
230 {{ 'config.reset.tags'|trans }} 230 {{ 'config.reset.tags'|trans }}
231 </a> 231 </a>
232 <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
233 {{ 'config.reset.archived'|trans }}
234 </a>
232 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> 235 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
233 {{ 'config.reset.entries'|trans }} 236 {{ 'config.reset.entries'|trans }}
234 </a> 237 </a>
@@ -410,8 +413,8 @@
410 <tr> 413 <tr>
411 <td>domainName</td> 414 <td>domainName</td>
412 <td>{{ 'config.form_rules.faq.variable_description.domainName'|trans }}</td> 415 <td>{{ 'config.form_rules.faq.variable_description.domainName'|trans }}</td>
413 <td>matches</td> 416 <td>matches<br />notmaches</td>
414 <td>{{ 'config.form_rules.faq.operator_description.matches'|trans|raw }}</td> 417 <td>{{ 'config.form_rules.faq.operator_description.matches'|trans|raw }}<br />{{ 'config.form_rules.faq.operator_description.notmatches'|trans|raw }}</td>
415 </tr> 418 </tr>
416 </tbody> 419 </tbody>
417 </table> 420 </table>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig
index 1a932a9f..6ba18768 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig
@@ -1,7 +1,7 @@
1{% set readingTime = entry.readingTime / app.user.config.readingSpeed %} 1{% set readingTime = entry.readingTime / app.user.config.readingSpeed %}
2<i class="material-icons">timer</i> 2<i class="material-icons">timer</i>
3{% if readingTime > 0 %} 3{% if readingTime > 0 %}
4 {{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }} 4 <span>{{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }}</span>
5{% else %} 5{% else %}
6 {{ 'entry.list.reading_time_less_one_minute_short'|trans|raw }} 6 <span>{{ 'entry.list.reading_time_less_one_minute_short'|trans|raw }}</span>
7{% endif %} 7{% endif %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/edit.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/edit.html.twig
index 1c5e2aab..b9537975 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/edit.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/edit.html.twig
@@ -27,11 +27,6 @@
27 {{ form_label(form.url) }} 27 {{ form_label(form.url) }}
28 {{ form_widget(form.url) }} 28 {{ form_widget(form.url) }}
29 </div> 29 </div>
30
31 <div class="input-field s12">
32 {{ form_widget(form.is_public) }}
33 {{ form_label(form.is_public) }}
34 </div>
35 <br> 30 <br>
36 31
37 {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} 32 {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
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 5fca53ae..b2d91c9c 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
@@ -45,7 +45,7 @@
45 {% endif %} 45 {% endif %}
46 46
47 <!-- Export --> 47 <!-- Export -->
48 <div id="export" class="side-nav fixed right-aligned"> 48 <div id="export" class="side-nav right-aligned">
49 {% set currentRoute = app.request.attributes.get('_route') %} 49 {% set currentRoute = app.request.attributes.get('_route') %}
50 {% set currentTag = '' %} 50 {% set currentTag = '' %}
51 {% if tag is defined %} 51 {% if tag is defined %}
@@ -68,7 +68,7 @@
68 68
69 <!-- Filters --> 69 <!-- Filters -->
70 {% if form is not null %} 70 {% if form is not null %}
71 <div id="filters" class="side-nav fixed right-aligned"> 71 <div id="filters" class="side-nav right-aligned">
72 <form action="{{ path('all') }}"> 72 <form action="{{ path('all') }}">
73 73
74 <h4 class="center">{{ 'entry.filters.title'|trans }}</h4> 74 <h4 class="center">{{ 'entry.filters.title'|trans }}</h4>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
index c3508083..47e6e8c3 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
@@ -12,6 +12,11 @@
12 <div class="nav-wrapper cyan darken-1"> 12 <div class="nav-wrapper cyan darken-1">
13 <ul> 13 <ul>
14 <li> 14 <li>
15 <a href="#" data-activates="slide-out" class="button-collapse">
16 <i class="material-icons">menu</i>
17 </a>
18 </li>
19 <li>
15 <a class="waves-effect" href="{{ path('homepage') }}"> 20 <a class="waves-effect" href="{{ path('homepage') }}">
16 <i class="material-icons">exit_to_app</i> 21 <i class="material-icons">exit_to_app</i>
17 </a> 22 </a>
@@ -28,11 +33,6 @@
28 <i class="material-icons small">{% if entry.isStarred == 0 %}star_outline{% else %}star{% endif %}</i> 33 <i class="material-icons small">{% if entry.isStarred == 0 %}star_outline{% else %}star{% endif %}</i>
29 </a> 34 </a>
30 </li> 35 </li>
31 <li>
32 <a href="#" data-activates="slide-out" class="button-collapse right">
33 <i class="material-icons">menu</i>
34 </a>
35 </li>
36 </ul> 36 </ul>
37 </div> 37 </div>
38 </nav> 38 </nav>
@@ -125,39 +125,43 @@
125 {% endif %} 125 {% endif %}
126 {% if craue_setting('share_shaarli') %} 126 {% if craue_setting('share_shaarli') %}
127 <li> 127 <li>
128 <a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}" target="_blank"> 128 <a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}" target="_blank" title="shaarli" class="tool icon-image shaarli">
129 <i class="tool icon-image icon-image--shaarli" title="shaarli"></i>
130 <span>shaarli</span> 129 <span>shaarli</span>
131 </a> 130 </a>
132 </li> 131 </li>
133 {% endif %} 132 {% endif %}
133 {% if craue_setting('share_scuttle') %}
134 <li>
135 <a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&amp;address={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}" target="_blank" title="scuttle" class="tool icon-image scuttle">
136 <span>scuttle</span>
137 </a>
138 </li>
139 {% endif %}
134 {% if craue_setting('share_diaspora') %} 140 {% if craue_setting('share_diaspora') %}
135 <li> 141 <li>
136 <a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;notes=&amp;v=1&amp;noui=1&amp;jump=doclose" target="_blank"> 142 <a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;notes=&amp;v=1&amp;noui=1&amp;jump=doclose" target="_blank" class="tool icon-image diaspora" title="diaspora">
137 <i class="tool icon-image icon-image--diaspora" title="diaspora"></i>
138 <span>diaspora*</span> 143 <span>diaspora*</span>
139 </a> 144 </a>
140 </li> 145 </li>
141 {% endif %} 146 {% endif %}
142 {% if craue_setting('share_unmark') %} 147 {% if craue_setting('share_unmark') %}
143 <li> 148 <li>
144 <a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|striptags|url_encode}}&amp;v=6" target="_blank"> 149 <a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|striptags|url_encode}}&amp;v=6" target="_blank" class="tool icon-image unmark" title="unmark">
145 <i class="tool icon-image icon-image--unmark" title="unmark"></i>
146 <span>unmark.it</span> 150 <span>unmark.it</span>
147 </a> 151 </a>
148 </li> 152 </li>
149 {% endif %} 153 {% endif %}
150 {% if craue_setting('carrot') %} 154 {% if craue_setting('carrot') %}
151 <li> 155 <li>
152 <a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}" target="_blank" title="carrot"> 156 <a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}" target="_blank" title="carrot" class="tool icon-image carrot">
153 <i class="tool icon-image icon-image--carrot"></i>
154 <span>Carrot</span> 157 <span>Carrot</span>
155 </a> 158 </a>
156 </li> 159 </li>
157 {% endif %} 160 {% endif %}
158 {% if craue_setting('share_mail') %} 161 {% if craue_setting('share_mail') %}
159 <li> 162 <li>
160 <a href="mailto:?subject={{ entry.title|striptags|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" title="{{ 'entry.view.left_menu.share_email_label'|trans }}" class="tool email icon icon-mail"> 163 <a href="mailto:?subject={{ entry.title|striptags|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" title="{{ 'entry.view.left_menu.share_email_label'|trans }}" class="tool icon">
164 <i class="material-icons vertical-align-middle">mail</i>
161 <span>{{ 'entry.view.left_menu.share_email_label'|trans }}</span> 165 <span>{{ 'entry.view.left_menu.share_email_label'|trans }}</span>
162 </a> 166 </a>
163 </li> 167 </li>
@@ -212,32 +216,48 @@
212 <h1>{{ entry.title|striptags|raw }} <a href="{{ path('edit', { 'id': entry.id }) }}" title="{{ 'entry.view.edit_title'|trans }}">✎</a></h1> 216 <h1>{{ entry.title|striptags|raw }} <a href="{{ path('edit', { 'id': entry.id }) }}" title="{{ 'entry.view.edit_title'|trans }}">✎</a></h1>
213 </header> 217 </header>
214 <aside> 218 <aside>
215 <ul class="tools"> 219 <div class="tools">
216 <li> 220 <ul class="stats">
217 {% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %} 221 <li>
218 </li> 222 {% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %}
219 <li> 223 </li>
220 <i class="material-icons" title="{{ 'entry.view.created_at'|trans }}">today</i> 224 <li>
221 {{ entry.createdAt|date('Y-m-d') }} 225 <i class="material-icons" title="{{ 'entry.view.created_at'|trans }}">today</i>
222 </li> 226 {{ entry.createdAt|date('Y-m-d H:i') }}
223 <li> 227 </li>
224 <i class="material-icons link">link</i> 228 {% if entry.publishedAt is not null %}
225 <a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|striptags }}" class="tool"> 229 <li>
226 {{ entry.domainName|removeWww }} 230 <i class="material-icons" title="{{ 'entry.view.published_at'|trans }}">create</i>
227 </a> 231 {{ entry.publishedAt|date('Y-m-d H:i') }}
228 </li> 232 </li>
229 <li> 233 {% endif %}
230 <i class="material-icons link">comment</i> 234 {% if entry.publishedBy is not empty %}
231 {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }} 235 <li>
232 </li> 236 <i class="material-icons" title="{{ 'entry.view.published_by'|trans }}">person</i>
233 <li id="list"> 237 {% for author in entry.publishedBy %}
238 {{ author }}{% if not loop.last %}, {% endif %}
239 {% endfor %}
240 </li>
241 {% endif %}
242 <li>
243 <i class="material-icons link">link</i>
244 <a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|striptags }}" class="tool">
245 {{ entry.domainName|removeWww }}
246 </a>
247 </li>
248 <li>
249 <i class="material-icons link">comment</i>
250 {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}
251 </li>
252 </ul>
253 <ul class="tags">
234 {% for tag in entry.tags %} 254 {% for tag in entry.tags %}
235 <div class="chip"> 255 <li class="chip">
236 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a> <a href="{{ path('remove_tag', { 'entry': entry.id, 'tag': tag.id }) }}"><i class="material-icons">delete</i></a> 256 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a> <a href="{{ path('remove_tag', { 'entry': entry.id, 'tag': tag.id }) }}"><i class="material-icons vertical-align-middle">delete</i></a>
237 </div> 257 </li>
238 {% endfor %} 258 {% endfor %}
239 </li> 259 </ul>
240 </ul> 260 </div>
241 261
242 <div class="input-field nav-panel-add-tag" style="display: none"> 262 <div class="input-field nav-panel-add-tag" style="display: none">
243 {{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }} 263 {{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
index 3c169c04..2dab1c18 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -2,12 +2,14 @@
2 2
3{% block css %} 3{% block css %}
4 {{ parent() }} 4 {{ parent() }}
5 <link rel="stylesheet" href="{{ asset('bundles/wallabagcore/themes/material/css/style.min.css') }}" media="screen,projection,print"/> 5 {% if not app.debug %}
6 <link rel="stylesheet" href="{{ asset('bundles/wallabagcore/material.css') }}">
7 {% endif %}
6{% endblock %} 8{% endblock %}
7 9
8{% block scripts %} 10{% block scripts %}
9 {{ parent() }} 11 {{ parent() }}
10 <script src="{{ asset('bundles/wallabagcore/themes/material/js/material.min.js') }}"></script> 12 <script src="{{ asset('bundles/wallabagcore/material' ~ (app.debug ? '.dev' : '') ~ '.js') }}"></script>
11{% endblock %} 13{% endblock %}
12 14
13{% block header %} 15{% block header %}
@@ -116,12 +118,12 @@
116 </ul> 118 </ul>
117 <div class="input-field nav-panel-search" style="display: none"> 119 <div class="input-field nav-panel-search" style="display: none">
118 {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': app.request.attributes.get('_route')})) }} 120 {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': app.request.attributes.get('_route')})) }}
119 <label for="search" class="active"><i class="material-icons search">search</i></label> 121 <label for="search"><i class="material-icons search">search</i></label>
120 <i class="material-icons close">clear</i> 122 <i class="material-icons close">clear</i>
121 </div> 123 </div>
122 <div class="input-field nav-panel-add" style="display: none"> 124 <div class="input-field nav-panel-add" style="display: none">
123 {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }} 125 {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }}
124 <label for="add" class="active"><i class="material-icons add">add</i></label> 126 <label for="add"><i class="material-icons add">add</i></label>
125 <i class="material-icons close">clear</i> 127 <i class="material-icons close">clear</i>
126 </div> 128 </div>
127 </div> 129 </div>
diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php
index 28d01715..ce72837a 100644
--- a/src/Wallabag/ImportBundle/Command/ImportCommand.php
+++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php
@@ -15,10 +15,11 @@ class ImportCommand extends ContainerAwareCommand
15 $this 15 $this
16 ->setName('wallabag:import') 16 ->setName('wallabag:import')
17 ->setDescription('Import entries from a JSON export') 17 ->setDescription('Import entries from a JSON export')
18 ->addArgument('userId', InputArgument::REQUIRED, 'User ID to populate') 18 ->addArgument('username', InputArgument::REQUIRED, 'User to populate')
19 ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') 19 ->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') 20 ->addOption('importer', null, InputArgument::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) 21 ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false)
22 ->addOption('useUserId', null, InputArgument::OPTIONAL, 'Use user id instead of username to find account', false)
22 ; 23 ;
23 } 24 }
24 25
@@ -34,10 +35,14 @@ class ImportCommand extends ContainerAwareCommand
34 // Turning off doctrine default logs queries for saving memory 35 // Turning off doctrine default logs queries for saving memory
35 $em->getConnection()->getConfiguration()->setSQLLogger(null); 36 $em->getConnection()->getConfiguration()->setSQLLogger(null);
36 37
37 $user = $em->getRepository('WallabagUserBundle:User')->findOneById($input->getArgument('userId')); 38 if ($input->getOption('useUserId')) {
39 $user = $em->getRepository('WallabagUserBundle:User')->findOneById($input->getArgument('username'));
40 } else {
41 $user = $em->getRepository('WallabagUserBundle:User')->findOneByUsername($input->getArgument('username'));
42 }
38 43
39 if (!is_object($user)) { 44 if (!is_object($user)) {
40 throw new Exception(sprintf('User with id "%s" not found', $input->getArgument('userId'))); 45 throw new Exception(sprintf('User "%s" not found', $input->getArgument('username')));
41 } 46 }
42 47
43 switch ($input->getOption('importer')) { 48 switch ($input->getOption('importer')) {
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php
index 92ee2b41..1c5c86d4 100644
--- a/src/Wallabag/UserBundle/Controller/ManageController.php
+++ b/src/Wallabag/UserBundle/Controller/ManageController.php
@@ -4,12 +4,15 @@ namespace Wallabag\UserBundle\Controller;
4 4
5use FOS\UserBundle\Event\UserEvent; 5use FOS\UserBundle\Event\UserEvent;
6use FOS\UserBundle\FOSUserEvents; 6use FOS\UserBundle\FOSUserEvents;
7use Pagerfanta\Adapter\DoctrineORMAdapter;
8use Pagerfanta\Exception\OutOfRangeCurrentPageException;
9use Pagerfanta\Pagerfanta;
7use Symfony\Component\HttpFoundation\Request; 10use Symfony\Component\HttpFoundation\Request;
8use Symfony\Bundle\FrameworkBundle\Controller\Controller; 11use Symfony\Bundle\FrameworkBundle\Controller\Controller;
9use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 12use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
10use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 13use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
11use Wallabag\UserBundle\Entity\User; 14use Wallabag\UserBundle\Entity\User;
12use Wallabag\CoreBundle\Entity\Config; 15use Wallabag\UserBundle\Form\SearchUserType;
13 16
14/** 17/**
15 * User controller. 18 * User controller.
@@ -17,23 +20,6 @@ use Wallabag\CoreBundle\Entity\Config;
17class ManageController extends Controller 20class ManageController extends Controller
18{ 21{
19 /** 22 /**
20 * Lists all User entities.
21 *
22 * @Route("/", name="user_index")
23 * @Method("GET")
24 */
25 public function indexAction()
26 {
27 $em = $this->getDoctrine()->getManager();
28
29 $users = $em->getRepository('WallabagUserBundle:User')->findAll();
30
31 return $this->render('WallabagUserBundle:Manage:index.html.twig', array(
32 'users' => $users,
33 ));
34 }
35
36 /**
37 * Creates a new User entity. 23 * Creates a new User entity.
38 * 24 *
39 * @Route("/new", name="user_new") 25 * @Route("/new", name="user_new")
@@ -146,4 +132,49 @@ class ManageController extends Controller
146 ->getForm() 132 ->getForm()
147 ; 133 ;
148 } 134 }
135
136 /**
137 * @param Request $request
138 * @param int $page
139 *
140 * @Route("/list/{page}", name="user_index", defaults={"page" = 1})
141 *
142 * Default parameter for page is hardcoded (in duplication of the defaults from the Route)
143 * because this controller is also called inside the layout template without any page as argument
144 *
145 * @return \Symfony\Component\HttpFoundation\Response
146 */
147 public function searchFormAction(Request $request, $page = 1)
148 {
149 $em = $this->getDoctrine()->getManager();
150 $qb = $em->getRepository('WallabagUserBundle:User')->createQueryBuilder('u');
151
152 $form = $this->createForm(SearchUserType::class);
153 $form->handleRequest($request);
154
155 if ($form->isSubmitted() && $form->isValid()) {
156 $this->get('logger')->info('searching users');
157
158 $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : '');
159
160 $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm);
161 }
162
163 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
164 $pagerFanta = new Pagerfanta($pagerAdapter);
165 $pagerFanta->setMaxPerPage(50);
166
167 try {
168 $pagerFanta->setCurrentPage($page);
169 } catch (OutOfRangeCurrentPageException $e) {
170 if ($page > 1) {
171 return $this->redirect($this->generateUrl('user_index', ['page' => $pagerFanta->getNbPages()]), 302);
172 }
173 }
174
175 return $this->render('WallabagUserBundle:Manage:index.html.twig', [
176 'searchForm' => $form->createView(),
177 'users' => $pagerFanta,
178 ]);
179 }
149} 180}
diff --git a/src/Wallabag/UserBundle/Form/SearchUserType.php b/src/Wallabag/UserBundle/Form/SearchUserType.php
new file mode 100644
index 00000000..9ce46ee1
--- /dev/null
+++ b/src/Wallabag/UserBundle/Form/SearchUserType.php
@@ -0,0 +1,29 @@
1<?php
2
3namespace Wallabag\UserBundle\Form;
4
5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\Extension\Core\Type\TextType;
7use Symfony\Component\Form\FormBuilderInterface;
8use Symfony\Component\OptionsResolver\OptionsResolver;
9
10class SearchUserType extends AbstractType
11{
12 public function buildForm(FormBuilderInterface $builder, array $options)
13 {
14 $builder
15 ->setMethod('GET')
16 ->add('term', TextType::class, [
17 'required' => true,
18 'label' => 'user.new.form_search.term_label',
19 ])
20 ;
21 }
22
23 public function configureOptions(OptionsResolver $resolver)
24 {
25 $resolver->setDefaults([
26 'csrf_protection' => false,
27 ]);
28 }
29}
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php
index f913f52d..6adbe329 100644
--- a/src/Wallabag/UserBundle/Repository/UserRepository.php
+++ b/src/Wallabag/UserBundle/Repository/UserRepository.php
@@ -52,4 +52,17 @@ class UserRepository extends EntityRepository
52 ->getQuery() 52 ->getQuery()
53 ->getSingleScalarResult(); 53 ->getSingleScalarResult();
54 } 54 }
55
56 /**
57 * Retrieves users filtered with a search term.
58 *
59 * @param string $term
60 *
61 * @return QueryBuilder
62 */
63 public function getQueryBuilderForSearch($term)
64 {
65 return $this->createQueryBuilder('u')
66 ->andWhere('lower(u.username) LIKE lower(:term) OR lower(u.email) LIKE lower(:term) OR lower(u.name) LIKE lower(:term)')->setParameter('term', '%'.$term.'%');
67 }
55} 68}
diff --git a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig
index daba29e4..15002632 100644
--- a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig
@@ -7,37 +7,60 @@
7 <div class="row"> 7 <div class="row">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel"> 9 <div class="card-panel">
10 {% if users.getNbPages > 1 %}
11 {{ pagerfanta(users, 'twitter_bootstrap_translated', {'proximity': 1}) }}
12 {% endif %}
10 <div class="row"> 13 <div class="row">
11 <div class="input-field col s12"> 14 <div class="col s6">
12 <p class="help">{{ 'user.description'|trans|raw }}</p> 15 <p class="help">{{ 'user.description'|trans|raw }}</p>
16 </div>
17 <div class="col s6">
18 <div class="input-field">
19 <form name="search_users" method="GET" action="{{ path('user_index')}}">
20 {% if form_errors(searchForm) %}
21 <span class="black-text">{{ form_errors(searchForm) }}</span>
22 {% endif %}
23
24 {% if form_errors(searchForm.term) %}
25 <span class="black-text">{{ form_errors(searchForm.term) }}</span>
26 {% endif %}
13 27
14 <table class="bordered"> 28 {{ form_widget(searchForm.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'user.search.placeholder'} }) }}
15 <thead> 29
16 <tr> 30 {{ form_rest(searchForm) }}
17 <th>{{ 'user.form.username_label'|trans }}</th> 31 </form>
18 <th>{{ 'user.form.email_label'|trans }}</th> 32 </div>
19 <th>{{ 'user.form.last_login_label'|trans }}</th>
20 <th>{{ 'user.list.actions'|trans }}</th>
21 </tr>
22 </thead>
23 <tbody>
24 {% for user in users %}
25 <tr>
26 <td>{{ user.username }}</td>
27 <td>{{ user.email }}</td>
28 <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td>
29 <td>
30 <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a>
31 </td>
32 </tr>
33 {% endfor %}
34 </tbody>
35 </table>
36 <br />
37 <p>
38 <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a>
39 </p>
40 </div> 33 </div>
34
35 <table class="bordered">
36 <thead>
37 <tr>
38 <th>{{ 'user.form.username_label'|trans }}</th>
39 <th>{{ 'user.form.email_label'|trans }}</th>
40 <th>{{ 'user.form.last_login_label'|trans }}</th>
41 <th>{{ 'user.list.actions'|trans }}</th>
42 </tr>
43 </thead>
44 <tbody>
45 {% for user in users %}
46 <tr>
47 <td>{{ user.username }}</td>
48 <td>{{ user.email }}</td>
49 <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td>
50 <td>
51 <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a>
52 </td>
53 </tr>
54 {% endfor %}
55 </tbody>
56 </table>
57 <br />
58 <p>
59 <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a>
60 </p>
61 {% if users.getNbPages > 1 %}
62 {{ pagerfanta(users, 'twitter_bootstrap_translated', {'proximity': 1}) }}
63 {% endif %}
41 </div> 64 </div>
42 </div> 65 </div>
43 </div> 66 </div>