aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag')
-rw-r--r--src/Wallabag/AnnotationBundle/DataFixtures/AnnotationFixtures.php (renamed from src/Wallabag/AnnotationBundle/DataFixtures/ORM/LoadAnnotationData.php)17
-rw-r--r--src/Wallabag/ApiBundle/Controller/DeveloperController.php2
-rw-r--r--src/Wallabag/ApiBundle/Controller/EntryRestController.php28
-rw-r--r--src/Wallabag/ApiBundle/Controller/SearchRestController.php65
-rw-r--r--src/Wallabag/ApiBundle/Controller/WallabagRestController.php39
-rw-r--r--src/Wallabag/ApiBundle/Entity/AccessToken.php16
-rw-r--r--src/Wallabag/ApiBundle/Entity/AuthCode.php16
-rw-r--r--src/Wallabag/ApiBundle/Entity/RefreshToken.php16
-rw-r--r--src/Wallabag/ApiBundle/Resources/config/routing_rest.yml5
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php3
-rw-r--r--src/Wallabag/CoreBundle/Command/ShowUserCommand.php3
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php157
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php126
-rw-r--r--src/Wallabag/CoreBundle/Controller/ExportController.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/RssController.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/SiteCredentialController.php15
-rw-r--r--src/Wallabag/CoreBundle/Controller/StaticController.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/TagController.php53
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ConfigFixtures.php (renamed from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php)15
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/EntryFixtures.php (renamed from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php)16
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/SettingFixtures.php (renamed from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php)15
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/SiteCredentialFixtures.php (renamed from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSiteCredentialData.php)15
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/TagFixtures.php (renamed from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php)15
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/TaggingRuleFixtures.php (renamed from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php)14
-rw-r--r--src/Wallabag/CoreBundle/Doctrine/DBAL/Driver/CustomPostgreSQLDriver.php25
-rw-r--r--src/Wallabag/CoreBundle/Doctrine/DBAL/Schema/CustomPostgreSqlSchemaManager.php38
-rw-r--r--src/Wallabag/CoreBundle/Doctrine/WallabagMigration.php2
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php49
-rw-r--r--src/Wallabag/CoreBundle/Entity/SiteCredential.php17
-rw-r--r--src/Wallabag/CoreBundle/Entity/TaggingRule.php2
-rw-r--r--src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php8
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/RenameTagType.php35
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/UserInformationType.php9
-rw-r--r--src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php2
-rw-r--r--src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php1
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntryRepository.php62
-rw-r--r--src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php2
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml29
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.da.yml32
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.de.yml23
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml33
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.es.yml32
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml32
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml32
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.it.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml33
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.th.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml31
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig97
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig55
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig9
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig18
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig114
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig63
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig6
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig13
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig11
-rw-r--r--src/Wallabag/ImportBundle/Controller/BrowserController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/ChromeController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/FirefoxController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/ImportController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/InstapaperController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/PinboardController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/PocketController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/ReadabilityController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php2
-rw-r--r--src/Wallabag/ImportBundle/Import/BrowserImport.php2
-rw-r--r--src/Wallabag/ImportBundle/Import/InstapaperImport.php5
-rw-r--r--src/Wallabag/ImportBundle/Import/PinboardImport.php2
-rw-r--r--src/Wallabag/ImportBundle/Import/PocketImport.php2
-rw-r--r--src/Wallabag/ImportBundle/Import/ReadabilityImport.php2
-rw-r--r--src/Wallabag/ImportBundle/Import/WallabagImport.php2
-rw-r--r--src/Wallabag/ImportBundle/Resources/config/services.yml8
-rw-r--r--src/Wallabag/UserBundle/Controller/ManageController.php45
-rw-r--r--src/Wallabag/UserBundle/DataFixtures/UserFixtures.php (renamed from src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php)15
-rw-r--r--src/Wallabag/UserBundle/Entity/User.php148
-rw-r--r--src/Wallabag/UserBundle/EventListener/CreateConfigListener.php7
-rw-r--r--src/Wallabag/UserBundle/Form/UserType.php9
-rw-r--r--src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php4
-rw-r--r--src/Wallabag/UserBundle/Resources/config/services.yml1
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig14
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig11
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Registration/register_content.html.twig1
-rw-r--r--src/Wallabag/UserBundle/Resources/views/layout.html.twig5
89 files changed, 1576 insertions, 485 deletions
diff --git a/src/Wallabag/AnnotationBundle/DataFixtures/ORM/LoadAnnotationData.php b/src/Wallabag/AnnotationBundle/DataFixtures/AnnotationFixtures.php
index 20e07fa3..ed46cea9 100644
--- a/src/Wallabag/AnnotationBundle/DataFixtures/ORM/LoadAnnotationData.php
+++ b/src/Wallabag/AnnotationBundle/DataFixtures/AnnotationFixtures.php
@@ -1,13 +1,15 @@
1<?php 1<?php
2 2
3namespace Wallabag\AnnotationBundle\DataFixtures\ORM; 3namespace Wallabag\AnnotationBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 6use Doctrine\Common\DataFixtures\DependentFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 7use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\AnnotationBundle\Entity\Annotation; 8use Wallabag\AnnotationBundle\Entity\Annotation;
9use Wallabag\CoreBundle\DataFixtures\EntryFixtures;
10use Wallabag\UserBundle\DataFixtures\UserFixtures;
9 11
10class LoadAnnotationData extends AbstractFixture implements OrderedFixtureInterface 12class AnnotationFixtures extends Fixture implements DependentFixtureInterface
11{ 13{
12 /** 14 /**
13 * {@inheritdoc} 15 * {@inheritdoc}
@@ -38,8 +40,11 @@ class LoadAnnotationData extends AbstractFixture implements OrderedFixtureInterf
38 /** 40 /**
39 * {@inheritdoc} 41 * {@inheritdoc}
40 */ 42 */
41 public function getOrder() 43 public function getDependencies()
42 { 44 {
43 return 35; 45 return [
46 EntryFixtures::class,
47 UserFixtures::class,
48 ];
44 } 49 }
45} 50}
diff --git a/src/Wallabag/ApiBundle/Controller/DeveloperController.php b/src/Wallabag/ApiBundle/Controller/DeveloperController.php
index c7178017..ae7e83da 100644
--- a/src/Wallabag/ApiBundle/Controller/DeveloperController.php
+++ b/src/Wallabag/ApiBundle/Controller/DeveloperController.php
@@ -2,9 +2,9 @@
2 2
3namespace Wallabag\ApiBundle\Controller; 3namespace Wallabag\ApiBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Routing\Annotation\Route;
8use Wallabag\ApiBundle\Entity\Client; 8use Wallabag\ApiBundle\Entity\Client;
9use Wallabag\ApiBundle\Form\Type\ClientType; 9use Wallabag\ApiBundle\Form\Type\ClientType;
10 10
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php
index b2bad406..16d8a40b 100644
--- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php
@@ -4,14 +4,12 @@ namespace Wallabag\ApiBundle\Controller;
4 4
5use Hateoas\Configuration\Route; 5use Hateoas\Configuration\Route;
6use Hateoas\Representation\Factory\PagerfantaFactory; 6use Hateoas\Representation\Factory\PagerfantaFactory;
7use JMS\Serializer\SerializationContext;
8use Nelmio\ApiDocBundle\Annotation\ApiDoc; 7use Nelmio\ApiDocBundle\Annotation\ApiDoc;
9use Symfony\Component\HttpFoundation\JsonResponse; 8use Symfony\Component\HttpFoundation\JsonResponse;
10use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
11use Symfony\Component\HttpFoundation\Response; 10use Symfony\Component\HttpFoundation\Response;
12use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; 11use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
13use Symfony\Component\HttpKernel\Exception\HttpException; 12use Symfony\Component\HttpKernel\Exception\HttpException;
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15use Wallabag\CoreBundle\Entity\Entry; 13use Wallabag\CoreBundle\Entity\Entry;
16use Wallabag\CoreBundle\Entity\Tag; 14use Wallabag\CoreBundle\Entity\Tag;
17use Wallabag\CoreBundle\Event\EntryDeletedEvent; 15use Wallabag\CoreBundle\Event\EntryDeletedEvent;
@@ -80,7 +78,7 @@ class EntryRestController extends WallabagRestController
80 * parameters={ 78 * parameters={
81 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."}, 79 * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."},
82 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."}, 80 * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."},
83 * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."}, 81 * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated' or 'archived', default 'created'", "description"="sort entries by date."},
84 * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."}, 82 * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."},
85 * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."}, 83 * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
86 * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}, 84 * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."},
@@ -141,7 +139,7 @@ class EntryRestController extends WallabagRestController
141 'tags' => $tags, 139 'tags' => $tags,
142 'since' => $since, 140 'since' => $since,
143 ], 141 ],
144 UrlGeneratorInterface::ABSOLUTE_URL 142 true
145 ) 143 )
146 ); 144 );
147 145
@@ -363,7 +361,7 @@ class EntryRestController extends WallabagRestController
363 } 361 }
364 362
365 if (null !== $data['isArchived']) { 363 if (null !== $data['isArchived']) {
366 $entry->setArchived((bool) $data['isArchived']); 364 $entry->updateArchived((bool) $data['isArchived']);
367 } 365 }
368 366
369 if (null !== $data['isStarred']) { 367 if (null !== $data['isStarred']) {
@@ -479,7 +477,7 @@ class EntryRestController extends WallabagRestController
479 } 477 }
480 478
481 if (null !== $data['isArchived']) { 479 if (null !== $data['isArchived']) {
482 $entry->setArchived((bool) $data['isArchived']); 480 $entry->updateArchived((bool) $data['isArchived']);
483 } 481 }
484 482
485 if (null !== $data['isStarred']) { 483 if (null !== $data['isStarred']) {
@@ -774,24 +772,6 @@ class EntryRestController extends WallabagRestController
774 } 772 }
775 773
776 /** 774 /**
777 * Shortcut to send data serialized in json.
778 *
779 * @param mixed $data
780 *
781 * @return JsonResponse
782 */
783 private function sendResponse($data)
784 {
785 // https://github.com/schmittjoh/JMSSerializerBundle/issues/293
786 $context = new SerializationContext();
787 $context->setSerializeNull(true);
788
789 $json = $this->get('jms_serializer')->serialize($data, 'json', $context);
790
791 return (new JsonResponse())->setJson($json);
792 }
793
794 /**
795 * Retrieve value from the request. 775 * Retrieve value from the request.
796 * Used for POST & PATCH on a an entry. 776 * Used for POST & PATCH on a an entry.
797 * 777 *
diff --git a/src/Wallabag/ApiBundle/Controller/SearchRestController.php b/src/Wallabag/ApiBundle/Controller/SearchRestController.php
new file mode 100644
index 00000000..d9f99844
--- /dev/null
+++ b/src/Wallabag/ApiBundle/Controller/SearchRestController.php
@@ -0,0 +1,65 @@
1<?php
2
3namespace Wallabag\ApiBundle\Controller;
4
5use Hateoas\Configuration\Route;
6use Hateoas\Representation\Factory\PagerfantaFactory;
7use Nelmio\ApiDocBundle\Annotation\ApiDoc;
8use Pagerfanta\Adapter\DoctrineORMAdapter;
9use Pagerfanta\Pagerfanta;
10use Symfony\Component\HttpFoundation\JsonResponse;
11use Symfony\Component\HttpFoundation\Request;
12
13class SearchRestController extends WallabagRestController
14{
15 /**
16 * Search all entries by term.
17 *
18 * @ApiDoc(
19 * parameters={
20 * {"name"="term", "dataType"="string", "required"=false, "format"="any", "description"="Any query term"},
21 * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
22 * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}
23 * }
24 * )
25 *
26 * @return JsonResponse
27 */
28 public function getSearchAction(Request $request)
29 {
30 $this->validateAuthentication();
31
32 $term = $request->query->get('term');
33 $page = (int) $request->query->get('page', 1);
34 $perPage = (int) $request->query->get('perPage', 30);
35
36 $qb = $this->get('wallabag_core.entry_repository')
37 ->getBuilderForSearchByUser(
38 $this->getUser()->getId(),
39 $term,
40 null
41 );
42
43 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
44 $pager = new Pagerfanta($pagerAdapter);
45
46 $pager->setMaxPerPage($perPage);
47 $pager->setCurrentPage($page);
48
49 $pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
50 $paginatedCollection = $pagerfantaFactory->createRepresentation(
51 $pager,
52 new Route(
53 'api_get_search',
54 [
55 'term' => $term,
56 'page' => $page,
57 'perPage' => $perPage,
58 ],
59 true
60 )
61 );
62
63 return $this->sendResponse($paginatedCollection);
64 }
65}
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
index 7d8cfbba..f18b0910 100644
--- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
@@ -3,6 +3,7 @@
3namespace Wallabag\ApiBundle\Controller; 3namespace Wallabag\ApiBundle\Controller;
4 4
5use FOS\RestBundle\Controller\FOSRestController; 5use FOS\RestBundle\Controller\FOSRestController;
6use JMS\Serializer\SerializationContext;
6use Nelmio\ApiDocBundle\Annotation\ApiDoc; 7use Nelmio\ApiDocBundle\Annotation\ApiDoc;
7use Symfony\Component\HttpFoundation\JsonResponse; 8use Symfony\Component\HttpFoundation\JsonResponse;
8use Symfony\Component\Security\Core\Exception\AccessDeniedException; 9use Symfony\Component\Security\Core\Exception\AccessDeniedException;
@@ -14,6 +15,8 @@ class WallabagRestController extends FOSRestController
14 * 15 *
15 * @ApiDoc() 16 * @ApiDoc()
16 * 17 *
18 * @deprecated Should use info endpoint instead
19 *
17 * @return JsonResponse 20 * @return JsonResponse
18 */ 21 */
19 public function getVersionAction() 22 public function getVersionAction()
@@ -24,6 +27,24 @@ class WallabagRestController extends FOSRestController
24 return (new JsonResponse())->setJson($json); 27 return (new JsonResponse())->setJson($json);
25 } 28 }
26 29
30 /**
31 * Retrieve information about the wallabag instance.
32 *
33 * @ApiDoc()
34 *
35 * @return JsonResponse
36 */
37 public function getInfoAction()
38 {
39 $info = [
40 'appname' => 'wallabag',
41 'version' => $this->container->getParameter('wallabag_core.version'),
42 'allowed_registration' => $this->container->getParameter('wallabag_user.registration_enabled'),
43 ];
44
45 return (new JsonResponse())->setJson($this->get('jms_serializer')->serialize($info, 'json'));
46 }
47
27 protected function validateAuthentication() 48 protected function validateAuthentication()
28 { 49 {
29 if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { 50 if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
@@ -44,4 +65,22 @@ class WallabagRestController extends FOSRestController
44 throw $this->createAccessDeniedException('Access forbidden. Entry user id: ' . $requestUserId . ', logged user id: ' . $user->getId()); 65 throw $this->createAccessDeniedException('Access forbidden. Entry user id: ' . $requestUserId . ', logged user id: ' . $user->getId());
45 } 66 }
46 } 67 }
68
69 /**
70 * Shortcut to send data serialized in json.
71 *
72 * @param mixed $data
73 *
74 * @return JsonResponse
75 */
76 protected function sendResponse($data)
77 {
78 // https://github.com/schmittjoh/JMSSerializerBundle/issues/293
79 $context = new SerializationContext();
80 $context->setSerializeNull(true);
81
82 $json = $this->get('jms_serializer')->serialize($data, 'json', $context);
83
84 return (new JsonResponse())->setJson($json);
85 }
47} 86}
diff --git a/src/Wallabag/ApiBundle/Entity/AccessToken.php b/src/Wallabag/ApiBundle/Entity/AccessToken.php
index c09a0c80..5e4099dd 100644
--- a/src/Wallabag/ApiBundle/Entity/AccessToken.php
+++ b/src/Wallabag/ApiBundle/Entity/AccessToken.php
@@ -8,6 +8,22 @@ use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken;
8/** 8/**
9 * @ORM\Table("oauth2_access_tokens") 9 * @ORM\Table("oauth2_access_tokens")
10 * @ORM\Entity 10 * @ORM\Entity
11 * @ORM\AttributeOverrides({
12 * @ORM\AttributeOverride(name="token",
13 * column=@ORM\Column(
14 * name = "token",
15 * type = "string",
16 * length = 191
17 * )
18 * ),
19 * @ORM\AttributeOverride(name="scope",
20 * column=@ORM\Column(
21 * name = "scope",
22 * type = "string",
23 * length = 191
24 * )
25 * )
26 * })
11 */ 27 */
12class AccessToken extends BaseAccessToken 28class AccessToken extends BaseAccessToken
13{ 29{
diff --git a/src/Wallabag/ApiBundle/Entity/AuthCode.php b/src/Wallabag/ApiBundle/Entity/AuthCode.php
index 4d4b09fe..5fa205ac 100644
--- a/src/Wallabag/ApiBundle/Entity/AuthCode.php
+++ b/src/Wallabag/ApiBundle/Entity/AuthCode.php
@@ -8,6 +8,22 @@ use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode;
8/** 8/**
9 * @ORM\Table("oauth2_auth_codes") 9 * @ORM\Table("oauth2_auth_codes")
10 * @ORM\Entity 10 * @ORM\Entity
11 * @ORM\AttributeOverrides({
12 * @ORM\AttributeOverride(name="token",
13 * column=@ORM\Column(
14 * name = "token",
15 * type = "string",
16 * length = 191
17 * )
18 * ),
19 * @ORM\AttributeOverride(name="scope",
20 * column=@ORM\Column(
21 * name = "scope",
22 * type = "string",
23 * length = 191
24 * )
25 * )
26 * })
11 */ 27 */
12class AuthCode extends BaseAuthCode 28class AuthCode extends BaseAuthCode
13{ 29{
diff --git a/src/Wallabag/ApiBundle/Entity/RefreshToken.php b/src/Wallabag/ApiBundle/Entity/RefreshToken.php
index 822a02d8..dd8e9c63 100644
--- a/src/Wallabag/ApiBundle/Entity/RefreshToken.php
+++ b/src/Wallabag/ApiBundle/Entity/RefreshToken.php
@@ -8,6 +8,22 @@ use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken;
8/** 8/**
9 * @ORM\Table("oauth2_refresh_tokens") 9 * @ORM\Table("oauth2_refresh_tokens")
10 * @ORM\Entity 10 * @ORM\Entity
11 * @ORM\AttributeOverrides({
12 * @ORM\AttributeOverride(name="token",
13 * column=@ORM\Column(
14 * name = "token",
15 * type = "string",
16 * length = 191
17 * )
18 * ),
19 * @ORM\AttributeOverride(name="scope",
20 * column=@ORM\Column(
21 * name = "scope",
22 * type = "string",
23 * length = 191
24 * )
25 * )
26 * })
11 */ 27 */
12class RefreshToken extends BaseRefreshToken 28class RefreshToken extends BaseRefreshToken
13{ 29{
diff --git a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
index c0283e71..06e62c37 100644
--- a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
+++ b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
@@ -3,6 +3,11 @@ entry:
3 resource: "WallabagApiBundle:EntryRest" 3 resource: "WallabagApiBundle:EntryRest"
4 name_prefix: api_ 4 name_prefix: api_
5 5
6search:
7 type: rest
8 resource: "WallabagApiBundle:SearchRest"
9 name_prefix: api_
10
6tag: 11tag:
7 type: rest 12 type: rest
8 resource: "WallabagApiBundle:TagRest" 13 resource: "WallabagApiBundle:TagRest"
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index 3c76545c..49c84178 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -94,8 +94,9 @@ class InstallCommand extends ContainerAwareCommand
94 $status = '<info>OK!</info>'; 94 $status = '<info>OK!</info>';
95 $help = ''; 95 $help = '';
96 96
97 $conn = $this->getContainer()->get('doctrine')->getManager()->getConnection();
98
97 try { 99 try {
98 $conn = $this->getContainer()->get('doctrine')->getManager()->getConnection();
99 $conn->connect(); 100 $conn->connect();
100 } catch (\Exception $e) { 101 } catch (\Exception $e) {
101 if (false === strpos($e->getMessage(), 'Unknown database') 102 if (false === strpos($e->getMessage(), 'Unknown database')
diff --git a/src/Wallabag/CoreBundle/Command/ShowUserCommand.php b/src/Wallabag/CoreBundle/Command/ShowUserCommand.php
index a0184267..c95efbf3 100644
--- a/src/Wallabag/CoreBundle/Command/ShowUserCommand.php
+++ b/src/Wallabag/CoreBundle/Command/ShowUserCommand.php
@@ -57,7 +57,8 @@ class ShowUserCommand extends ContainerAwareCommand
57 sprintf('Display name: %s', $user->getName()), 57 sprintf('Display name: %s', $user->getName()),
58 sprintf('Creation date: %s', $user->getCreatedAt()->format('Y-m-d H:i:s')), 58 sprintf('Creation date: %s', $user->getCreatedAt()->format('Y-m-d H:i:s')),
59 sprintf('Last login: %s', null !== $user->getLastLogin() ? $user->getLastLogin()->format('Y-m-d H:i:s') : 'never'), 59 sprintf('Last login: %s', null !== $user->getLastLogin() ? $user->getLastLogin()->format('Y-m-d H:i:s') : 'never'),
60 sprintf('2FA activated: %s', $user->isTwoFactorAuthentication() ? 'yes' : 'no'), 60 sprintf('2FA (email) activated: %s', $user->isEmailTwoFactor() ? 'yes' : 'no'),
61 sprintf('2FA (OTP) activated: %s', $user->isGoogleAuthenticatorEnabled() ? 'yes' : 'no'),
61 ]); 62 ]);
62 } 63 }
63 64
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
index b999c539..9257ab18 100644
--- a/src/Wallabag/CoreBundle/Controller/ConfigController.php
+++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php
@@ -2,12 +2,14 @@
2 2
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 5use PragmaRX\Recovery\Recovery as BackupCodes;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 6use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\JsonResponse; 7use Symfony\Component\HttpFoundation\JsonResponse;
8use Symfony\Component\HttpFoundation\RedirectResponse; 8use Symfony\Component\HttpFoundation\RedirectResponse;
9use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; 10use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
11use Symfony\Component\Routing\Annotation\Route;
12use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint;
11use Wallabag\CoreBundle\Entity\Config; 13use Wallabag\CoreBundle\Entity\Config;
12use Wallabag\CoreBundle\Entity\TaggingRule; 14use Wallabag\CoreBundle\Entity\TaggingRule;
13use Wallabag\CoreBundle\Form\Type\ChangePasswordType; 15use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
@@ -45,7 +47,7 @@ class ConfigController extends Controller
45 $activeTheme = $this->get('liip_theme.active_theme'); 47 $activeTheme = $this->get('liip_theme.active_theme');
46 $activeTheme->setName($config->getTheme()); 48 $activeTheme->setName($config->getTheme());
47 49
48 $this->get('session')->getFlashBag()->add( 50 $this->addFlash(
49 'notice', 51 'notice',
50 'flashes.config.notice.config_saved' 52 'flashes.config.notice.config_saved'
51 ); 53 );
@@ -67,7 +69,7 @@ class ConfigController extends Controller
67 $userManager->updateUser($user, true); 69 $userManager->updateUser($user, true);
68 } 70 }
69 71
70 $this->get('session')->getFlashBag()->add('notice', $message); 72 $this->addFlash('notice', $message);
71 73
72 return $this->redirect($this->generateUrl('config') . '#set4'); 74 return $this->redirect($this->generateUrl('config') . '#set4');
73 } 75 }
@@ -82,7 +84,7 @@ class ConfigController extends Controller
82 if ($userForm->isSubmitted() && $userForm->isValid()) { 84 if ($userForm->isSubmitted() && $userForm->isValid()) {
83 $userManager->updateUser($user, true); 85 $userManager->updateUser($user, true);
84 86
85 $this->get('session')->getFlashBag()->add( 87 $this->addFlash(
86 'notice', 88 'notice',
87 'flashes.config.notice.user_updated' 89 'flashes.config.notice.user_updated'
88 ); 90 );
@@ -98,7 +100,7 @@ class ConfigController extends Controller
98 $em->persist($config); 100 $em->persist($config);
99 $em->flush(); 101 $em->flush();
100 102
101 $this->get('session')->getFlashBag()->add( 103 $this->addFlash(
102 'notice', 104 'notice',
103 'flashes.config.notice.rss_updated' 105 'flashes.config.notice.rss_updated'
104 ); 106 );
@@ -130,7 +132,7 @@ class ConfigController extends Controller
130 $em->persist($taggingRule); 132 $em->persist($taggingRule);
131 $em->flush(); 133 $em->flush();
132 134
133 $this->get('session')->getFlashBag()->add( 135 $this->addFlash(
134 'notice', 136 'notice',
135 'flashes.config.notice.tagging_rules_updated' 137 'flashes.config.notice.tagging_rules_updated'
136 ); 138 );
@@ -152,12 +154,124 @@ class ConfigController extends Controller
152 ], 154 ],
153 'twofactor_auth' => $this->getParameter('twofactor_auth'), 155 'twofactor_auth' => $this->getParameter('twofactor_auth'),
154 'wallabag_url' => $this->getParameter('domain_name'), 156 'wallabag_url' => $this->getParameter('domain_name'),
155 'enabled_users' => $this->get('wallabag_user.user_repository') 157 'enabled_users' => $this->get('wallabag_user.user_repository')->getSumEnabledUsers(),
156 ->getSumEnabledUsers(),
157 ]); 158 ]);
158 } 159 }
159 160
160 /** 161 /**
162 * Enable 2FA using email.
163 *
164 * @Route("/config/otp/email", name="config_otp_email")
165 */
166 public function otpEmailAction()
167 {
168 if (!$this->getParameter('twofactor_auth')) {
169 return $this->createNotFoundException('two_factor not enabled');
170 }
171
172 $user = $this->getUser();
173
174 $user->setGoogleAuthenticatorSecret(null);
175 $user->setBackupCodes(null);
176 $user->setEmailTwoFactor(true);
177
178 $this->container->get('fos_user.user_manager')->updateUser($user, true);
179
180 $this->addFlash(
181 'notice',
182 'flashes.config.notice.otp_enabled'
183 );
184
185 return $this->redirect($this->generateUrl('config') . '#set3');
186 }
187
188 /**
189 * Enable 2FA using OTP app, user will need to confirm the generated code from the app.
190 *
191 * @Route("/config/otp/app", name="config_otp_app")
192 */
193 public function otpAppAction()
194 {
195 if (!$this->getParameter('twofactor_auth')) {
196 return $this->createNotFoundException('two_factor not enabled');
197 }
198
199 $user = $this->getUser();
200 $secret = $this->get('scheb_two_factor.security.google_authenticator')->generateSecret();
201
202 $user->setGoogleAuthenticatorSecret($secret);
203 $user->setEmailTwoFactor(false);
204
205 $backupCodes = (new BackupCodes())->toArray();
206 $backupCodesHashed = array_map(
207 function ($backupCode) {
208 return password_hash($backupCode, PASSWORD_DEFAULT);
209 },
210 $backupCodes
211 );
212
213 $user->setBackupCodes($backupCodesHashed);
214
215 $this->container->get('fos_user.user_manager')->updateUser($user, true);
216
217 return $this->render('WallabagCoreBundle:Config:otp_app.html.twig', [
218 'backupCodes' => $backupCodes,
219 'qr_code' => $this->get('scheb_two_factor.security.google_authenticator')->getQRContent($user),
220 ]);
221 }
222
223 /**
224 * Cancelling 2FA using OTP app.
225 *
226 * @Route("/config/otp/app/cancel", name="config_otp_app_cancel")
227 */
228 public function otpAppCancelAction()
229 {
230 if (!$this->getParameter('twofactor_auth')) {
231 return $this->createNotFoundException('two_factor not enabled');
232 }
233
234 $user = $this->getUser();
235 $user->setGoogleAuthenticatorSecret(null);
236 $user->setBackupCodes(null);
237
238 $this->container->get('fos_user.user_manager')->updateUser($user, true);
239
240 return $this->redirect($this->generateUrl('config') . '#set3');
241 }
242
243 /**
244 * Validate OTP code.
245 *
246 * @param Request $request
247 *
248 * @Route("/config/otp/app/check", name="config_otp_app_check")
249 */
250 public function otpAppCheckAction(Request $request)
251 {
252 $isValid = $this->get('scheb_two_factor.security.google_authenticator')->checkCode(
253 $this->getUser(),
254 $request->get('_auth_code')
255 );
256
257 if (true === $isValid) {
258 $this->addFlash(
259 'notice',
260 'flashes.config.notice.otp_enabled'
261 );
262
263 return $this->redirect($this->generateUrl('config') . '#set3');
264 }
265
266 $this->addFlash(
267 'two_factor',
268 'scheb_two_factor.code_invalid'
269 );
270
271 return $this->redirect($this->generateUrl('config_otp_app'));
272 }
273
274 /**
161 * @param Request $request 275 * @param Request $request
162 * 276 *
163 * @Route("/generate-token", name="generate_token") 277 * @Route("/generate-token", name="generate_token")
@@ -177,7 +291,7 @@ class ConfigController extends Controller
177 return new JsonResponse(['token' => $config->getRssToken()]); 291 return new JsonResponse(['token' => $config->getRssToken()]);
178 } 292 }
179 293
180 $this->get('session')->getFlashBag()->add( 294 $this->addFlash(
181 'notice', 295 'notice',
182 'flashes.config.notice.rss_token_updated' 296 'flashes.config.notice.rss_token_updated'
183 ); 297 );
@@ -202,7 +316,7 @@ class ConfigController extends Controller
202 $em->remove($rule); 316 $em->remove($rule);
203 $em->flush(); 317 $em->flush();
204 318
205 $this->get('session')->getFlashBag()->add( 319 $this->addFlash(
206 'notice', 320 'notice',
207 'flashes.config.notice.tagging_rules_deleted' 321 'flashes.config.notice.tagging_rules_deleted'
208 ); 322 );
@@ -268,7 +382,7 @@ class ConfigController extends Controller
268 break; 382 break;
269 } 383 }
270 384
271 $this->get('session')->getFlashBag()->add( 385 $this->addFlash(
272 'notice', 386 'notice',
273 'flashes.config.notice.' . $type . '_reset' 387 'flashes.config.notice.' . $type . '_reset'
274 ); 388 );
@@ -330,6 +444,27 @@ class ConfigController extends Controller
330 } 444 }
331 445
332 /** 446 /**
447 * Change the locale for the current user.
448 *
449 * @param Request $request
450 * @param string $language
451 *
452 * @Route("/locale/{language}", name="changeLocale")
453 *
454 * @return \Symfony\Component\HttpFoundation\RedirectResponse
455 */
456 public function setLocaleAction(Request $request, $language = null)
457 {
458 $errors = $this->get('validator')->validate($language, (new LocaleConstraint()));
459
460 if (0 === \count($errors)) {
461 $request->getSession()->set('_locale', $language);
462 }
463
464 return $this->redirect($request->headers->get('referer', $this->generateUrl('homepage')));
465 }
466
467 /**
333 * Remove all tags for given tags and a given user and cleanup orphan tags. 468 * Remove all tags for given tags and a given user and cleanup orphan tags.
334 * 469 *
335 * @param array $tags 470 * @param array $tags
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index b7fdea27..5c8ecb40 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -2,12 +2,13 @@
2 2
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Doctrine\ORM\NoResultException;
5use Pagerfanta\Adapter\DoctrineORMAdapter; 6use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 7use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; 8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller; 9use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\Request; 10use Symfony\Component\HttpFoundation\Request;
11use Symfony\Component\Routing\Annotation\Route;
11use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 12use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
12use Wallabag\CoreBundle\Entity\Entry; 13use Wallabag\CoreBundle\Entity\Entry;
13use Wallabag\CoreBundle\Event\EntryDeletedEvent; 14use Wallabag\CoreBundle\Event\EntryDeletedEvent;
@@ -233,6 +234,46 @@ class EntryController extends Controller
233 } 234 }
234 235
235 /** 236 /**
237 * Shows untagged articles for current user.
238 *
239 * @param Request $request
240 * @param int $page
241 *
242 * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"})
243 *
244 * @return \Symfony\Component\HttpFoundation\Response
245 */
246 public function showUntaggedEntriesAction(Request $request, $page)
247 {
248 return $this->showEntries('untagged', $request, $page);
249 }
250
251 /**
252 * Shows random entry depending on the given type.
253 *
254 * @param string $type
255 *
256 * @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|all"})
257 *
258 * @return \Symfony\Component\HttpFoundation\RedirectResponse
259 */
260 public function redirectRandomEntryAction($type = 'all')
261 {
262 try {
263 $entry = $this->get('wallabag_core.entry_repository')
264 ->getRandomEntry($this->getUser()->getId(), $type);
265 } catch (NoResultException $e) {
266 $bag = $this->get('session')->getFlashBag();
267 $bag->clear();
268 $bag->add('notice', 'flashes.entry.notice.no_random_entry');
269
270 return $this->redirect($this->generateUrl($type));
271 }
272
273 return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()]));
274 }
275
276 /**
236 * Shows entry content. 277 * Shows entry content.
237 * 278 *
238 * @param Entry $entry 279 * @param Entry $entry
@@ -466,54 +507,6 @@ class EntryController extends Controller
466 } 507 }
467 508
468 /** 509 /**
469 * Shows untagged articles for current user.
470 *
471 * @param Request $request
472 * @param int $page
473 *
474 * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"})
475 *
476 * @return \Symfony\Component\HttpFoundation\Response
477 */
478 public function showUntaggedEntriesAction(Request $request, $page)
479 {
480 return $this->showEntries('untagged', $request, $page);
481 }
482
483 /**
484 * Fetch content and update entry.
485 * In case it fails, $entry->getContent will return an error message.
486 *
487 * @param Entry $entry
488 * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded
489 */
490 private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved')
491 {
492 $message = 'flashes.entry.notice.' . $prefixMessage;
493
494 try {
495 $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
496 } catch (\Exception $e) {
497 $this->get('logger')->error('Error while saving an entry', [
498 'exception' => $e,
499 'entry' => $entry,
500 ]);
501
502 $message = 'flashes.entry.notice.' . $prefixMessage . '_failed';
503 }
504
505 if (empty($entry->getDomainName())) {
506 $this->get('wallabag_core.content_proxy')->setEntryDomainName($entry);
507 }
508
509 if (empty($entry->getTitle())) {
510 $this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry);
511 }
512
513 $this->get('session')->getFlashBag()->add('notice', $message);
514 }
515
516 /**
517 * Global method to retrieve entries depending on the given type 510 * Global method to retrieve entries depending on the given type
518 * It returns the response to be send. 511 * It returns the response to be send.
519 * 512 *
@@ -532,11 +525,9 @@ class EntryController extends Controller
532 switch ($type) { 525 switch ($type) {
533 case 'search': 526 case 'search':
534 $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute); 527 $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute);
535
536 break; 528 break;
537 case 'untagged': 529 case 'untagged':
538 $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); 530 $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId());
539
540 break; 531 break;
541 case 'starred': 532 case 'starred':
542 $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); 533 $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId());
@@ -588,6 +579,39 @@ class EntryController extends Controller
588 } 579 }
589 580
590 /** 581 /**
582 * Fetch content and update entry.
583 * In case it fails, $entry->getContent will return an error message.
584 *
585 * @param Entry $entry
586 * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded
587 */
588 private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved')
589 {
590 $message = 'flashes.entry.notice.' . $prefixMessage;
591
592 try {
593 $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
594 } catch (\Exception $e) {
595 $this->get('logger')->error('Error while saving an entry', [
596 'exception' => $e,
597 'entry' => $entry,
598 ]);
599
600 $message = 'flashes.entry.notice.' . $prefixMessage . '_failed';
601 }
602
603 if (empty($entry->getDomainName())) {
604 $this->get('wallabag_core.content_proxy')->setEntryDomainName($entry);
605 }
606
607 if (empty($entry->getTitle())) {
608 $this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry);
609 }
610
611 $this->get('session')->getFlashBag()->add('notice', $message);
612 }
613
614 /**
591 * Check if the logged user can manage the given entry. 615 * Check if the logged user can manage the given entry.
592 * 616 *
593 * @param Entry $entry 617 * @param Entry $entry
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php
index 9e9dbe49..9ff35ff5 100644
--- a/src/Wallabag/CoreBundle/Controller/ExportController.php
+++ b/src/Wallabag/CoreBundle/Controller/ExportController.php
@@ -2,10 +2,10 @@
2 2
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; 7use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
8use Symfony\Component\Routing\Annotation\Route;
9use Wallabag\CoreBundle\Entity\Entry; 9use Wallabag\CoreBundle\Entity\Entry;
10 10
11/** 11/**
diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/RssController.php
index 848bb814..1c831c03 100644
--- a/src/Wallabag/CoreBundle/Controller/RssController.php
+++ b/src/Wallabag/CoreBundle/Controller/RssController.php
@@ -7,10 +7,10 @@ use Pagerfanta\Adapter\DoctrineORMAdapter;
7use Pagerfanta\Exception\OutOfRangeCurrentPageException; 7use Pagerfanta\Exception\OutOfRangeCurrentPageException;
8use Pagerfanta\Pagerfanta; 8use Pagerfanta\Pagerfanta;
9use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 9use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
10use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
11use Symfony\Bundle\FrameworkBundle\Controller\Controller; 10use Symfony\Bundle\FrameworkBundle\Controller\Controller;
12use Symfony\Component\HttpFoundation\Request; 11use Symfony\Component\HttpFoundation\Request;
13use Symfony\Component\HttpFoundation\Response; 12use Symfony\Component\HttpFoundation\Response;
13use Symfony\Component\Routing\Annotation\Route;
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15use Wallabag\CoreBundle\Entity\Tag; 15use Wallabag\CoreBundle\Entity\Tag;
16use Wallabag\UserBundle\Entity\User; 16use Wallabag\UserBundle\Entity\User;
diff --git a/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php b/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php
index 548de744..51bc1d94 100644
--- a/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php
+++ b/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php
@@ -2,10 +2,9 @@
2 2
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
6use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
7use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
8use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Routing\Annotation\Route;
9use Wallabag\CoreBundle\Entity\SiteCredential; 8use Wallabag\CoreBundle\Entity\SiteCredential;
10use Wallabag\UserBundle\Entity\User; 9use Wallabag\UserBundle\Entity\User;
11 10
@@ -19,8 +18,7 @@ class SiteCredentialController extends Controller
19 /** 18 /**
20 * Lists all User entities. 19 * Lists all User entities.
21 * 20 *
22 * @Route("/", name="site_credentials_index") 21 * @Route("/", name="site_credentials_index", methods={"GET"})
23 * @Method("GET")
24 */ 22 */
25 public function indexAction() 23 public function indexAction()
26 { 24 {
@@ -36,8 +34,7 @@ class SiteCredentialController extends Controller
36 /** 34 /**
37 * Creates a new site credential entity. 35 * Creates a new site credential entity.
38 * 36 *
39 * @Route("/new", name="site_credentials_new") 37 * @Route("/new", name="site_credentials_new", methods={"GET", "POST"})
40 * @Method({"GET", "POST"})
41 * 38 *
42 * @param Request $request 39 * @param Request $request
43 * 40 *
@@ -77,8 +74,7 @@ class SiteCredentialController extends Controller
77 /** 74 /**
78 * Displays a form to edit an existing site credential entity. 75 * Displays a form to edit an existing site credential entity.
79 * 76 *
80 * @Route("/{id}/edit", name="site_credentials_edit") 77 * @Route("/{id}/edit", name="site_credentials_edit", methods={"GET", "POST"})
81 * @Method({"GET", "POST"})
82 * 78 *
83 * @param Request $request 79 * @param Request $request
84 * @param SiteCredential $siteCredential 80 * @param SiteCredential $siteCredential
@@ -121,8 +117,7 @@ class SiteCredentialController extends Controller
121 /** 117 /**
122 * Deletes a site credential entity. 118 * Deletes a site credential entity.
123 * 119 *
124 * @Route("/{id}", name="site_credentials_delete") 120 * @Route("/{id}", name="site_credentials_delete", methods={"DELETE"})
125 * @Method("DELETE")
126 * 121 *
127 * @param Request $request 122 * @param Request $request
128 * @param SiteCredential $siteCredential 123 * @param SiteCredential $siteCredential
diff --git a/src/Wallabag/CoreBundle/Controller/StaticController.php b/src/Wallabag/CoreBundle/Controller/StaticController.php
index 318af303..fa760c14 100644
--- a/src/Wallabag/CoreBundle/Controller/StaticController.php
+++ b/src/Wallabag/CoreBundle/Controller/StaticController.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class StaticController extends Controller 8class StaticController extends Controller
9{ 9{
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php
index b6d28e59..d0155c60 100644
--- a/src/Wallabag/CoreBundle/Controller/TagController.php
+++ b/src/Wallabag/CoreBundle/Controller/TagController.php
@@ -5,12 +5,13 @@ namespace Wallabag\CoreBundle\Controller;
5use Pagerfanta\Adapter\ArrayAdapter; 5use Pagerfanta\Adapter\ArrayAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 7use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller; 8use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\Routing\Annotation\Route;
11use Wallabag\CoreBundle\Entity\Entry; 11use Wallabag\CoreBundle\Entity\Entry;
12use Wallabag\CoreBundle\Entity\Tag; 12use Wallabag\CoreBundle\Entity\Tag;
13use Wallabag\CoreBundle\Form\Type\NewTagType; 13use Wallabag\CoreBundle\Form\Type\NewTagType;
14use Wallabag\CoreBundle\Form\Type\RenameTagType;
14 15
15class TagController extends Controller 16class TagController extends Controller
16{ 17{
@@ -87,8 +88,14 @@ class TagController extends Controller
87 $tags = $this->get('wallabag_core.tag_repository') 88 $tags = $this->get('wallabag_core.tag_repository')
88 ->findAllFlatTagsWithNbEntries($this->getUser()->getId()); 89 ->findAllFlatTagsWithNbEntries($this->getUser()->getId());
89 90
91 $renameForms = [];
92 foreach ($tags as $tag) {
93 $renameForms[$tag['id']] = $this->createForm(RenameTagType::class, new Tag())->createView();
94 }
95
90 return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [ 96 return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [
91 'tags' => $tags, 97 'tags' => $tags,
98 'renameForms' => $renameForms,
92 ]); 99 ]);
93 } 100 }
94 101
@@ -130,4 +137,48 @@ class TagController extends Controller
130 'tag' => $tag, 137 'tag' => $tag,
131 ]); 138 ]);
132 } 139 }
140
141 /**
142 * Rename a given tag with a new label
143 * Create a new tag with the new name and drop the old one.
144 *
145 * @param Tag $tag
146 * @param Request $request
147 *
148 * @Route("/tag/rename/{slug}", name="tag_rename")
149 * @ParamConverter("tag", options={"mapping": {"slug": "slug"}})
150 *
151 * @return \Symfony\Component\HttpFoundation\Response
152 */
153 public function renameTagAction(Tag $tag, Request $request)
154 {
155 $form = $this->createForm(RenameTagType::class, new Tag());
156 $form->handleRequest($request);
157
158 if ($form->isSubmitted() && $form->isValid()) {
159 $entries = $this->get('wallabag_core.entry_repository')->findAllByTagId(
160 $this->getUser()->getId(),
161 $tag->getId()
162 );
163 foreach ($entries as $entry) {
164 $this->get('wallabag_core.tags_assigner')->assignTagsToEntry(
165 $entry,
166 $form->get('label')->getData()
167 );
168 $entry->removeTag($tag);
169 }
170
171 $em = $this->getDoctrine()->getManager();
172 $em->flush();
173 }
174
175 $this->get('session')->getFlashBag()->add(
176 'notice',
177 'flashes.tag.notice.tag_renamed'
178 );
179
180 $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'), '', true);
181
182 return $this->redirect($redirectUrl);
183 }
133} 184}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php b/src/Wallabag/CoreBundle/DataFixtures/ConfigFixtures.php
index 3d4d5def..c54e9f2c 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ConfigFixtures.php
@@ -1,13 +1,14 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\DataFixtures\ORM; 3namespace Wallabag\CoreBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 6use Doctrine\Common\DataFixtures\DependentFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 7use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\CoreBundle\Entity\Config; 8use Wallabag\CoreBundle\Entity\Config;
9use Wallabag\UserBundle\DataFixtures\UserFixtures;
9 10
10class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface 11class ConfigFixtures extends Fixture implements DependentFixtureInterface
11{ 12{
12 /** 13 /**
13 * {@inheritdoc} 14 * {@inheritdoc}
@@ -60,8 +61,10 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
60 /** 61 /**
61 * {@inheritdoc} 62 * {@inheritdoc}
62 */ 63 */
63 public function getOrder() 64 public function getDependencies()
64 { 65 {
65 return 20; 66 return [
67 UserFixtures::class,
68 ];
66 } 69 }
67} 70}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php b/src/Wallabag/CoreBundle/DataFixtures/EntryFixtures.php
index 8e7a1d2a..024fcfdc 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/EntryFixtures.php
@@ -1,13 +1,14 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\DataFixtures\ORM; 3namespace Wallabag\CoreBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 6use Doctrine\Common\DataFixtures\DependentFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 7use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\CoreBundle\Entity\Entry; 8use Wallabag\CoreBundle\Entity\Entry;
9use Wallabag\UserBundle\DataFixtures\UserFixtures;
9 10
10class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface 11class EntryFixtures extends Fixture implements DependentFixtureInterface
11{ 12{
12 /** 13 /**
13 * {@inheritdoc} 14 * {@inheritdoc}
@@ -127,8 +128,11 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
127 /** 128 /**
128 * {@inheritdoc} 129 * {@inheritdoc}
129 */ 130 */
130 public function getOrder() 131 public function getDependencies()
131 { 132 {
132 return 30; 133 return [
134 UserFixtures::class,
135 TagFixtures::class,
136 ];
133 } 137 }
134} 138}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php b/src/Wallabag/CoreBundle/DataFixtures/SettingFixtures.php
index 3fe88e7f..cc7d1f59 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/SettingFixtures.php
@@ -1,15 +1,14 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\DataFixtures\ORM; 3namespace Wallabag\CoreBundle\DataFixtures;
4 4
5use Craue\ConfigBundle\Entity\Setting; 5use Craue\ConfigBundle\Entity\Setting;
6use Doctrine\Common\DataFixtures\AbstractFixture; 6use Doctrine\Bundle\FixturesBundle\Fixture;
7use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
8use Doctrine\Common\Persistence\ObjectManager; 7use Doctrine\Common\Persistence\ObjectManager;
9use Symfony\Component\DependencyInjection\ContainerAwareInterface; 8use Symfony\Component\DependencyInjection\ContainerAwareInterface;
10use Symfony\Component\DependencyInjection\ContainerInterface; 9use Symfony\Component\DependencyInjection\ContainerInterface;
11 10
12class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface 11class SettingFixtures extends Fixture implements ContainerAwareInterface
13{ 12{
14 /** 13 /**
15 * @var ContainerInterface 14 * @var ContainerInterface
@@ -36,12 +35,4 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
36 35
37 $manager->flush(); 36 $manager->flush();
38 } 37 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function getOrder()
44 {
45 return 29;
46 }
47} 38}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSiteCredentialData.php b/src/Wallabag/CoreBundle/DataFixtures/SiteCredentialFixtures.php
index 866f55a4..c73173e8 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSiteCredentialData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/SiteCredentialFixtures.php
@@ -1,13 +1,14 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\DataFixtures\ORM; 3namespace Wallabag\CoreBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 6use Doctrine\Common\DataFixtures\DependentFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 7use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\CoreBundle\Entity\SiteCredential; 8use Wallabag\CoreBundle\Entity\SiteCredential;
9use Wallabag\UserBundle\DataFixtures\UserFixtures;
9 10
10class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureInterface 11class SiteCredentialFixtures extends Fixture implements DependentFixtureInterface
11{ 12{
12 /** 13 /**
13 * {@inheritdoc} 14 * {@inheritdoc}
@@ -27,8 +28,10 @@ class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureIn
27 /** 28 /**
28 * {@inheritdoc} 29 * {@inheritdoc}
29 */ 30 */
30 public function getOrder() 31 public function getDependencies()
31 { 32 {
32 return 50; 33 return [
34 UserFixtures::class,
35 ];
33 } 36 }
34} 37}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php b/src/Wallabag/CoreBundle/DataFixtures/TagFixtures.php
index 485445c1..58a0d799 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/TagFixtures.php
@@ -1,13 +1,12 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\DataFixtures\ORM; 3namespace Wallabag\CoreBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 6use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\CoreBundle\Entity\Tag; 7use Wallabag\CoreBundle\Entity\Tag;
9 8
10class LoadTagData extends AbstractFixture implements OrderedFixtureInterface 9class TagFixtures extends Fixture
11{ 10{
12 /** 11 /**
13 * {@inheritdoc} 12 * {@inheritdoc}
@@ -33,12 +32,4 @@ class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
33 32
34 $manager->flush(); 33 $manager->flush();
35 } 34 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function getOrder()
41 {
42 return 25;
43 }
44} 35}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php b/src/Wallabag/CoreBundle/DataFixtures/TaggingRuleFixtures.php
index 55abd63c..78ff314a 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTaggingRuleData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/TaggingRuleFixtures.php
@@ -1,13 +1,13 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\DataFixtures\ORM; 3namespace Wallabag\CoreBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 6use Doctrine\Common\DataFixtures\DependentFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 7use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\CoreBundle\Entity\TaggingRule; 8use Wallabag\CoreBundle\Entity\TaggingRule;
9 9
10class LoadTaggingRuleData extends AbstractFixture implements OrderedFixtureInterface 10class TaggingRuleFixtures extends Fixture implements DependentFixtureInterface
11{ 11{
12 /** 12 /**
13 * {@inheritdoc} 13 * {@inheritdoc}
@@ -49,8 +49,10 @@ class LoadTaggingRuleData extends AbstractFixture implements OrderedFixtureInter
49 /** 49 /**
50 * {@inheritdoc} 50 * {@inheritdoc}
51 */ 51 */
52 public function getOrder() 52 public function getDependencies()
53 { 53 {
54 return 40; 54 return [
55 ConfigFixtures::class,
56 ];
55 } 57 }
56} 58}
diff --git a/src/Wallabag/CoreBundle/Doctrine/DBAL/Driver/CustomPostgreSQLDriver.php b/src/Wallabag/CoreBundle/Doctrine/DBAL/Driver/CustomPostgreSQLDriver.php
deleted file mode 100644
index eb5b203f..00000000
--- a/src/Wallabag/CoreBundle/Doctrine/DBAL/Driver/CustomPostgreSQLDriver.php
+++ /dev/null
@@ -1,25 +0,0 @@
1<?php
2
3namespace Wallabag\CoreBundle\Doctrine\DBAL\Driver;
4
5use Doctrine\DBAL\Connection;
6use Doctrine\DBAL\Driver\PDOPgSql\Driver;
7use Wallabag\CoreBundle\Doctrine\DBAL\Schema\CustomPostgreSqlSchemaManager;
8
9/**
10 * This custom driver allow to use a different schema manager
11 * So we can fix the PostgreSQL 10 problem.
12 *
13 * @see https://github.com/wallabag/wallabag/issues/3479
14 * @see https://github.com/doctrine/dbal/issues/2868
15 */
16class CustomPostgreSQLDriver extends Driver
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getSchemaManager(Connection $conn)
22 {
23 return new CustomPostgreSqlSchemaManager($conn);
24 }
25}
diff --git a/src/Wallabag/CoreBundle/Doctrine/DBAL/Schema/CustomPostgreSqlSchemaManager.php b/src/Wallabag/CoreBundle/Doctrine/DBAL/Schema/CustomPostgreSqlSchemaManager.php
deleted file mode 100644
index 439ae17d..00000000
--- a/src/Wallabag/CoreBundle/Doctrine/DBAL/Schema/CustomPostgreSqlSchemaManager.php
+++ /dev/null
@@ -1,38 +0,0 @@
1<?php
2
3namespace Wallabag\CoreBundle\Doctrine\DBAL\Schema;
4
5use Doctrine\DBAL\Schema\PostgreSqlSchemaManager;
6use Doctrine\DBAL\Schema\Sequence;
7
8/**
9 * This custom schema manager fix the PostgreSQL 10 problem.
10 *
11 * @see https://github.com/wallabag/wallabag/issues/3479
12 * @see https://github.com/doctrine/dbal/issues/2868
13 */
14class CustomPostgreSqlSchemaManager extends PostgreSqlSchemaManager
15{
16 /**
17 * {@inheritdoc}
18 */
19 protected function _getPortableSequenceDefinition($sequence)
20 {
21 $sequenceName = $sequence['relname'];
22 if ('public' !== $sequence['schemaname']) {
23 $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname'];
24 }
25
26 $query = 'SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName);
27
28 // the `method_exists` is only to avoid test to fail:
29 // DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticConnection doesn't support the `getServerVersion`
30 if (method_exists($this->_conn->getWrappedConnection(), 'getServerVersion') && (float) ($this->_conn->getWrappedConnection()->getServerVersion()) >= 10) {
31 $query = "SELECT min_value, increment_by FROM pg_sequences WHERE schemaname = 'public' AND sequencename = " . $this->_conn->quote($sequenceName);
32 }
33
34 $data = $this->_conn->fetchAll($query);
35
36 return new Sequence($sequenceName, $data[0]['increment_by'], $data[0]['min_value']);
37 }
38}
diff --git a/src/Wallabag/CoreBundle/Doctrine/WallabagMigration.php b/src/Wallabag/CoreBundle/Doctrine/WallabagMigration.php
index 7aa2409a..4a3fef3b 100644
--- a/src/Wallabag/CoreBundle/Doctrine/WallabagMigration.php
+++ b/src/Wallabag/CoreBundle/Doctrine/WallabagMigration.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\CoreBundle\Doctrine; 3namespace Wallabag\CoreBundle\Doctrine;
4 4
5use Doctrine\DBAL\Migrations\AbstractMigration;
6use Doctrine\DBAL\Schema\Schema; 5use Doctrine\DBAL\Schema\Schema;
6use Doctrine\Migrations\AbstractMigration;
7use Symfony\Component\DependencyInjection\ContainerAwareInterface; 7use Symfony\Component\DependencyInjection\ContainerAwareInterface;
8use Symfony\Component\DependencyInjection\ContainerInterface; 8use Symfony\Component\DependencyInjection\ContainerInterface;
9 9
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index 2b1f2e05..b3cfdc4a 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -87,6 +87,15 @@ class Entry
87 private $isArchived = false; 87 private $isArchived = false;
88 88
89 /** 89 /**
90 * @var \DateTime
91 *
92 * @ORM\Column(name="archived_at", type="datetime", nullable=true)
93 *
94 * @Groups({"entries_for_user", "export_all"})
95 */
96 private $archivedAt = null;
97
98 /**
90 * @var bool 99 * @var bool
91 * 100 *
92 * @Exclude 101 * @Exclude
@@ -336,6 +345,44 @@ class Entry
336 } 345 }
337 346
338 /** 347 /**
348 * update isArchived and archive_at fields.
349 *
350 * @param bool $isArchived
351 *
352 * @return Entry
353 */
354 public function updateArchived($isArchived = false)
355 {
356 $this->setArchived($isArchived);
357 $this->setArchivedAt(null);
358 if ($this->isArchived()) {
359 $this->setArchivedAt(new \DateTime());
360 }
361
362 return $this;
363 }
364
365 /**
366 * @return \DateTime|null
367 */
368 public function getArchivedAt()
369 {
370 return $this->archivedAt;
371 }
372
373 /**
374 * @param \DateTime|null $archivedAt
375 *
376 * @return Entry
377 */
378 public function setArchivedAt($archivedAt = null)
379 {
380 $this->archivedAt = $archivedAt;
381
382 return $this;
383 }
384
385 /**
339 * Get isArchived. 386 * Get isArchived.
340 * 387 *
341 * @return bool 388 * @return bool
@@ -357,7 +404,7 @@ class Entry
357 404
358 public function toggleArchive() 405 public function toggleArchive()
359 { 406 {
360 $this->isArchived = $this->isArchived() ^ 1; 407 $this->updateArchived($this->isArchived() ^ 1);
361 408
362 return $this; 409 return $this;
363 } 410 }
diff --git a/src/Wallabag/CoreBundle/Entity/SiteCredential.php b/src/Wallabag/CoreBundle/Entity/SiteCredential.php
index ac714359..dee48fd5 100644
--- a/src/Wallabag/CoreBundle/Entity/SiteCredential.php
+++ b/src/Wallabag/CoreBundle/Entity/SiteCredential.php
@@ -60,6 +60,13 @@ class SiteCredential
60 private $createdAt; 60 private $createdAt;
61 61
62 /** 62 /**
63 * @var \DateTime
64 *
65 * @ORM\Column(name="updated_at", type="datetime")
66 */
67 private $updatedAt;
68
69 /**
63 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="siteCredentials") 70 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="siteCredentials")
64 */ 71 */
65 private $user; 72 private $user;
@@ -179,6 +186,16 @@ class SiteCredential
179 } 186 }
180 187
181 /** 188 /**
189 * Get updatedAt.
190 *
191 * @return \DateTime
192 */
193 public function getUpdatedAt()
194 {
195 return $this->updatedAt;
196 }
197
198 /**
182 * @return User 199 * @return User
183 */ 200 */
184 public function getUser() 201 public function getUser()
diff --git a/src/Wallabag/CoreBundle/Entity/TaggingRule.php b/src/Wallabag/CoreBundle/Entity/TaggingRule.php
index 84e11e26..c1be3165 100644
--- a/src/Wallabag/CoreBundle/Entity/TaggingRule.php
+++ b/src/Wallabag/CoreBundle/Entity/TaggingRule.php
@@ -3,7 +3,7 @@
3namespace Wallabag\CoreBundle\Entity; 3namespace Wallabag\CoreBundle\Entity;
4 4
5use Doctrine\ORM\Mapping as ORM; 5use Doctrine\ORM\Mapping as ORM;
6use KPhoen\RulerZBundle\Validator\Constraints as RulerZAssert; 6use Symfony\Bridge\RulerZ\Validator\Constraints as RulerZAssert;
7use Symfony\Component\Validator\Constraints as Assert; 7use Symfony\Component\Validator\Constraints as Assert;
8 8
9/** 9/**
diff --git a/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php b/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php
index 367cdfb0..dc1db5c7 100644
--- a/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php
+++ b/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php
@@ -6,8 +6,10 @@ use Symfony\Component\HttpFoundation\Session\Session;
6use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; 6use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
7 7
8/** 8/**
9 * Stores the locale of the user in the session after the 9 * Stores the locale of the user in the session after the login.
10 * login. This can be used by the LocaleListener afterwards. 10 * If no locale are defined (if user doesn't change it from the login screen), override it with the user's config one.
11 *
12 * This can be used by the LocaleListener afterwards.
11 * 13 *
12 * @see http://symfony.com/doc/master/cookbook/session/locale_sticky_session.html 14 * @see http://symfony.com/doc/master/cookbook/session/locale_sticky_session.html
13 */ 15 */
@@ -30,7 +32,7 @@ class UserLocaleListener
30 { 32 {
31 $user = $event->getAuthenticationToken()->getUser(); 33 $user = $event->getAuthenticationToken()->getUser();
32 34
33 if (null !== $user->getConfig()->getLanguage()) { 35 if (null !== $user->getConfig()->getLanguage() && null === $this->session->get('_locale')) {
34 $this->session->set('_locale', $user->getConfig()->getLanguage()); 36 $this->session->set('_locale', $user->getConfig()->getLanguage());
35 } 37 }
36 } 38 }
diff --git a/src/Wallabag/CoreBundle/Form/Type/RenameTagType.php b/src/Wallabag/CoreBundle/Form/Type/RenameTagType.php
new file mode 100644
index 00000000..e6270048
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Form/Type/RenameTagType.php
@@ -0,0 +1,35 @@
1<?php
2
3namespace Wallabag\CoreBundle\Form\Type;
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 RenameTagType extends AbstractType
11{
12 public function buildForm(FormBuilderInterface $builder, array $options)
13 {
14 $builder
15 ->add('label', TextType::class, [
16 'required' => true,
17 'attr' => [
18 'placeholder' => 'tag.rename.placeholder',
19 ],
20 ])
21 ;
22 }
23
24 public function configureOptions(OptionsResolver $resolver)
25 {
26 $resolver->setDefaults([
27 'data_class' => 'Wallabag\CoreBundle\Entity\Tag',
28 ]);
29 }
30
31 public function getBlockPrefix()
32 {
33 return 'tag';
34 }
35}
diff --git a/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php b/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php
index 07c99949..6e4c9154 100644
--- a/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php
+++ b/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php
@@ -21,9 +21,14 @@ class UserInformationType extends AbstractType
21 ->add('email', EmailType::class, [ 21 ->add('email', EmailType::class, [
22 'label' => 'config.form_user.email_label', 22 'label' => 'config.form_user.email_label',
23 ]) 23 ])
24 ->add('twoFactorAuthentication', CheckboxType::class, [ 24 ->add('emailTwoFactor', CheckboxType::class, [
25 'required' => false, 25 'required' => false,
26 'label' => 'config.form_user.twoFactorAuthentication_label', 26 'label' => 'config.form_user.emailTwoFactor_label',
27 ])
28 ->add('googleTwoFactor', CheckboxType::class, [
29 'required' => false,
30 'label' => 'config.form_user.googleTwoFactor_label',
31 'mapped' => false,
27 ]) 32 ])
28 ->add('save', SubmitType::class, [ 33 ->add('save', SubmitType::class, [
29 'label' => 'config.form.save', 34 'label' => 'config.form.save',
diff --git a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
index 1c2c5093..183d394a 100644
--- a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
+++ b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
@@ -23,7 +23,7 @@ class PreparePagerForEntries
23 * @param AdapterInterface $adapter 23 * @param AdapterInterface $adapter
24 * @param User $user If user isn't logged in, we can force it (like for rss) 24 * @param User $user If user isn't logged in, we can force it (like for rss)
25 * 25 *
26 * @return null|Pagerfanta 26 * @return Pagerfanta|null
27 */ 27 */
28 public function prepare(AdapterInterface $adapter, User $user = null) 28 public function prepare(AdapterInterface $adapter, User $user = null)
29 { 29 {
diff --git a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php
index 63f65067..fbdf2ac7 100644
--- a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php
+++ b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php
@@ -6,6 +6,7 @@ use Psr\Log\LoggerInterface;
6use RulerZ\RulerZ; 6use RulerZ\RulerZ;
7use Wallabag\CoreBundle\Entity\Entry; 7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\CoreBundle\Entity\Tag; 8use Wallabag\CoreBundle\Entity\Tag;
9use Wallabag\CoreBundle\Entity\TaggingRule;
9use Wallabag\CoreBundle\Repository\EntryRepository; 10use Wallabag\CoreBundle\Repository\EntryRepository;
10use Wallabag\CoreBundle\Repository\TagRepository; 11use Wallabag\CoreBundle\Repository\TagRepository;
11use Wallabag\UserBundle\Entity\User; 12use Wallabag\UserBundle\Entity\User;
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
index cebce714..45366623 100644
--- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
@@ -3,6 +3,7 @@
3namespace Wallabag\CoreBundle\Repository; 3namespace Wallabag\CoreBundle\Repository;
4 4
5use Doctrine\ORM\EntityRepository; 5use Doctrine\ORM\EntityRepository;
6use Doctrine\ORM\NoResultException;
6use Doctrine\ORM\QueryBuilder; 7use Doctrine\ORM\QueryBuilder;
7use Pagerfanta\Adapter\DoctrineORMAdapter; 8use Pagerfanta\Adapter\DoctrineORMAdapter;
8use Pagerfanta\Pagerfanta; 9use Pagerfanta\Pagerfanta;
@@ -50,7 +51,7 @@ class EntryRepository extends EntityRepository
50 public function getBuilderForArchiveByUser($userId) 51 public function getBuilderForArchiveByUser($userId)
51 { 52 {
52 return $this 53 return $this
53 ->getSortedQueryBuilderByUser($userId) 54 ->getSortedQueryBuilderByUser($userId, 'archivedAt', 'desc')
54 ->andWhere('e.isArchived = true') 55 ->andWhere('e.isArchived = true')
55 ; 56 ;
56 } 57 }
@@ -110,8 +111,7 @@ class EntryRepository extends EntityRepository
110 */ 111 */
111 public function getBuilderForUntaggedByUser($userId) 112 public function getBuilderForUntaggedByUser($userId)
112 { 113 {
113 return $this 114 return $this->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId));
114 ->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId));
115 } 115 }
116 116
117 /** 117 /**
@@ -193,6 +193,8 @@ class EntryRepository extends EntityRepository
193 $qb->orderBy('e.id', $order); 193 $qb->orderBy('e.id', $order);
194 } elseif ('updated' === $sort) { 194 } elseif ('updated' === $sort) {
195 $qb->orderBy('e.updatedAt', $order); 195 $qb->orderBy('e.updatedAt', $order);
196 } elseif ('archived' === $sort) {
197 $qb->orderBy('e.archivedAt', $order);
196 } 198 }
197 199
198 $pagerAdapter = new DoctrineORMAdapter($qb, true, false); 200 $pagerAdapter = new DoctrineORMAdapter($qb, true, false);
@@ -324,8 +326,8 @@ class EntryRepository extends EntityRepository
324 * Find an entry by its url and its owner. 326 * Find an entry by its url and its owner.
325 * If it exists, return the entry otherwise return false. 327 * If it exists, return the entry otherwise return false.
326 * 328 *
327 * @param $url 329 * @param string $url
328 * @param $userId 330 * @param int $userId
329 * 331 *
330 * @return Entry|bool 332 * @return Entry|bool
331 */ 333 */
@@ -416,8 +418,8 @@ class EntryRepository extends EntityRepository
416 /** 418 /**
417 * Find all entries by url and owner. 419 * Find all entries by url and owner.
418 * 420 *
419 * @param $url 421 * @param string $url
420 * @param $userId 422 * @param int $userId
421 * 423 *
422 * @return array 424 * @return array
423 */ 425 */
@@ -431,6 +433,49 @@ class EntryRepository extends EntityRepository
431 } 433 }
432 434
433 /** 435 /**
436 * Returns a random entry, filtering by status.
437 *
438 * @param int $userId
439 * @param string $type Can be unread, archive, starred, etc
440 *
441 * @throws NoResultException
442 *
443 * @return Entry
444 */
445 public function getRandomEntry($userId, $type = '')
446 {
447 $qb = $this->getQueryBuilderByUser($userId)
448 ->select('e.id');
449
450 switch ($type) {
451 case 'unread':
452 $qb->andWhere('e.isArchived = false');
453 break;
454 case 'archive':
455 $qb->andWhere('e.isArchived = true');
456 break;
457 case 'starred':
458 $qb->andWhere('e.isStarred = true');
459 break;
460 case 'untagged':
461 $qb->leftJoin('e.tags', 't');
462 $qb->andWhere('t.id is null');
463 break;
464 }
465
466 $ids = $qb->getQuery()->getArrayResult();
467
468 if (empty($ids)) {
469 throw new NoResultException();
470 }
471
472 // random select one in the list
473 $randomId = $ids[mt_rand(0, \count($ids) - 1)]['id'];
474
475 return $this->find($randomId);
476 }
477
478 /**
434 * Return a query builder to be used by other getBuilderFor* method. 479 * Return a query builder to be used by other getBuilderFor* method.
435 * 480 *
436 * @param int $userId 481 * @param int $userId
@@ -468,7 +513,6 @@ class EntryRepository extends EntityRepository
468 */ 513 */
469 private function sortQueryBuilder(QueryBuilder $qb, $sortBy = 'createdAt', $direction = 'desc') 514 private function sortQueryBuilder(QueryBuilder $qb, $sortBy = 'createdAt', $direction = 'desc')
470 { 515 {
471 return $qb 516 return $qb->orderBy(sprintf('e.%s', $sortBy), $direction);
472 ->orderBy(sprintf('e.%s', $sortBy), $direction);
473 } 517 }
474} 518}
diff --git a/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php b/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php
index 36906761..b2e212a4 100644
--- a/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php
@@ -22,7 +22,7 @@ class SiteCredentialRepository extends \Doctrine\ORM\EntityRepository
22 * @param string $host 22 * @param string $host
23 * @param int $userId 23 * @param int $userId
24 * 24 *
25 * @return null|array 25 * @return array|null
26 */ 26 */
27 public function findOneByHostAndUser($host, $userId) 27 public function findOneByHostAndUser($host, $userId)
28 { 28 {
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index 85306276..a27dd210 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -181,6 +181,7 @@ services:
181 181
182 wallabag_core.exception_controller: 182 wallabag_core.exception_controller:
183 class: Wallabag\CoreBundle\Controller\ExceptionController 183 class: Wallabag\CoreBundle\Controller\ExceptionController
184 public: true
184 arguments: 185 arguments:
185 - '@twig' 186 - '@twig'
186 - '%kernel.debug%' 187 - '%kernel.debug%'
@@ -218,3 +219,31 @@ services:
218 arguments: 219 arguments:
219 - "%wallabag_core.site_credentials.encryption_key_path%" 220 - "%wallabag_core.site_credentials.encryption_key_path%"
220 - "@logger" 221 - "@logger"
222
223 wallabag_core.command.clean_duplicates:
224 class: Wallabag\CoreBundle\Command\CleanDuplicatesCommand
225 tags: ['console.command']
226
227 wallabag_core.command.export:
228 class: Wallabag\CoreBundle\Command\ExportCommand
229 tags: ['console.command']
230
231 wallabag_core.command.install:
232 class: Wallabag\CoreBundle\Command\InstallCommand
233 tags: ['console.command']
234
235 wallabag_core.command.list_user:
236 class: Wallabag\CoreBundle\Command\ListUserCommand
237 tags: ['console.command']
238
239 wallabag_core.command.reload_entry:
240 class: Wallabag\CoreBundle\Command\ReloadEntryCommand
241 tags: ['console.command']
242
243 wallabag_core.command.show_user:
244 class: Wallabag\CoreBundle\Command\ShowUserCommand
245 tags: ['console.command']
246
247 wallabag_core.command.tag_all:
248 class: Wallabag\CoreBundle\Command\TagAllCommand
249 tags: ['console.command']
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
index 97eb874d..454f547d 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Tilføj ny artikel' 37 add_new_entry: 'Tilføj ny artikel'
38 search: 'Søg' 38 search: 'Søg'
39 filter_entries: 'Filtrer artikler' 39 filter_entries: 'Filtrer artikler'
40 # random_entry: Jump to a random entry from that list
40 # export: 'Export' 41 # export: 'Export'
41 search_form: 42 search_form:
42 input_label: 'Indtast søgning' 43 input_label: 'Indtast søgning'
@@ -58,6 +59,7 @@ config:
58 password: 'Adgangskode' 59 password: 'Adgangskode'
59 # rules: 'Tagging rules' 60 # rules: 'Tagging rules'
60 new_user: 'Tilføj bruger' 61 new_user: 'Tilføj bruger'
62 # reset: 'Reset area'
61 form: 63 form:
62 save: 'Gem' 64 save: 'Gem'
63 form_settings: 65 form_settings:
@@ -97,11 +99,19 @@ config:
97 # all: 'All' 99 # all: 'All'
98 # rss_limit: 'Number of items in the feed' 100 # rss_limit: 'Number of items in the feed'
99 form_user: 101 form_user:
100 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Navn' 103 name_label: 'Navn'
102 email_label: 'Emailadresse' 104 email_label: 'Emailadresse'
103 # twoFactorAuthentication_label: 'Two factor authentication' 105 two_factor:
104 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 106 # emailTwoFactor_label: 'Using email (receive a code by email)'
107 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
108 # table_method: Method
109 # table_state: State
110 # table_action: Action
111 # state_enabled: Enabled
112 # state_disabled: Disabled
113 # action_email: Use email
114 # action_app: Use OTP App
105 delete: 115 delete:
106 # title: Delete my account (a.k.a danger zone) 116 # title: Delete my account (a.k.a danger zone)
107 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 117 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
@@ -159,6 +169,15 @@ config:
159 # and: 'One rule AND another' 169 # and: 'One rule AND another'
160 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 170 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 171 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
172 otp:
173 # page_title: Two-factor authentication
174 # app:
175 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
176 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
177 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
178 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
179 # cancel: Cancel
180 # enable: Enable
162 181
163entry: 182entry:
164 # default_title: 'Title of the entry' 183 # default_title: 'Title of the entry'
@@ -404,6 +423,8 @@ tag:
404 new: 423 new:
405 # add: 'Add' 424 # add: 'Add'
406 # placeholder: 'You can add several tags, separated by a comma.' 425 # placeholder: 'You can add several tags, separated by a comma.'
426 rename:
427 # placeholder: 'You can update tag name.'
407 428
408# export: 429# export:
409# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 430# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +550,8 @@ user:
529 email_label: 'Emailadresse' 550 email_label: 'Emailadresse'
530 # enabled_label: 'Enabled' 551 # enabled_label: 'Enabled'
531 # last_login_label: 'Last login' 552 # last_login_label: 'Last login'
532 # twofactor_label: Two factor authentication 553 # twofactor_email_label: Two factor authentication by email
554 # twofactor_google_label: Two factor authentication by OTP app
533 # save: Save 555 # save: Save
534 # delete: Delete 556 # delete: Delete
535 # delete_confirm: Are you sure? 557 # delete_confirm: Are you sure?
@@ -588,9 +610,11 @@ flashes:
588 entry_starred: 'Artikel markeret som favorit' 610 entry_starred: 'Artikel markeret som favorit'
589 entry_unstarred: 'Artikel ikke længere markeret som favorit' 611 entry_unstarred: 'Artikel ikke længere markeret som favorit'
590 entry_deleted: 'Artikel slettet' 612 entry_deleted: 'Artikel slettet'
613 # no_random_entry: 'No article with these criterias was found'
591 tag: 614 tag:
592 notice: 615 notice:
593 # tag_added: 'Tag added' 616 # tag_added: 'Tag added'
617 # tag_renamed: 'Tag renamed'
594 import: 618 import:
595 notice: 619 notice:
596 # failed: 'Import failed, please try again.' 620 # failed: 'Import failed, please try again.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
index 0cf3b138..dc1d4723 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Neuen Artikel hinzufügen' 37 add_new_entry: 'Neuen Artikel hinzufügen'
38 search: 'Suche' 38 search: 'Suche'
39 filter_entries: 'Artikel filtern' 39 filter_entries: 'Artikel filtern'
40 # random_entry: Jump to a random entry from that list
40 export: 'Exportieren' 41 export: 'Exportieren'
41 search_form: 42 search_form:
42 input_label: 'Suchbegriff hier eingeben' 43 input_label: 'Suchbegriff hier eingeben'
@@ -58,6 +59,7 @@ config:
58 password: 'Kennwort' 59 password: 'Kennwort'
59 rules: 'Tagging-Regeln' 60 rules: 'Tagging-Regeln'
60 new_user: 'Benutzer hinzufügen' 61 new_user: 'Benutzer hinzufügen'
62 reset: 'Zurücksetzen'
61 form: 63 form:
62 save: 'Speichern' 64 save: 'Speichern'
63 form_settings: 65 form_settings:
@@ -97,11 +99,19 @@ config:
97 all: 'Alle' 99 all: 'Alle'
98 rss_limit: 'Anzahl der Einträge pro Feed' 100 rss_limit: 'Anzahl der Einträge pro Feed'
99 form_user: 101 form_user:
100 two_factor_description: "Wenn du die Zwei-Faktor-Authentifizierung aktivierst, erhältst du eine E-Mail mit einem Code bei jeder nicht vertrauenswürdigen Verbindung" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Name' 103 name_label: 'Name'
102 email_label: 'E-Mail-Adresse' 104 email_label: 'E-Mail-Adresse'
103 twoFactorAuthentication_label: 'Zwei-Faktor-Authentifizierung' 105 two_factor:
104 help_twoFactorAuthentication: "Wenn du 2FA aktivierst, wirst du bei jedem Login einen Code per E-Mail bekommen." 106 # emailTwoFactor_label: 'Using email (receive a code by email)'
107 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
108 # table_method: Method
109 # table_state: State
110 # table_action: Action
111 # state_enabled: Enabled
112 # state_disabled: Disabled
113 # action_email: Use email
114 # action_app: Use OTP App
105 delete: 115 delete:
106 title: 'Lösche mein Konto (a.k.a Gefahrenzone)' 116 title: 'Lösche mein Konto (a.k.a Gefahrenzone)'
107 description: 'Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.' 117 description: 'Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.'
@@ -404,6 +414,8 @@ tag:
404 new: 414 new:
405 add: 'Hinzufügen' 415 add: 'Hinzufügen'
406 placeholder: 'Du kannst verschiedene Tags, getrennt von einem Komma, hinzufügen.' 416 placeholder: 'Du kannst verschiedene Tags, getrennt von einem Komma, hinzufügen.'
417 rename:
418 # placeholder: 'You can update tag name.'
407 419
408export: 420export:
409 footer_template: '<div style="text-align:center;"><p>Generiert von wallabag mit Hilfe von %method%</p><p>Bitte öffne <a href="https://github.com/wallabag/wallabag/issues">ein Ticket</a> wenn du ein Problem mit der Darstellung von diesem E-Book auf deinem Gerät hast.</p></div>' 421 footer_template: '<div style="text-align:center;"><p>Generiert von wallabag mit Hilfe von %method%</p><p>Bitte öffne <a href="https://github.com/wallabag/wallabag/issues">ein Ticket</a> wenn du ein Problem mit der Darstellung von diesem E-Book auf deinem Gerät hast.</p></div>'
@@ -529,7 +541,8 @@ user:
529 email_label: 'E-Mail-Adresse' 541 email_label: 'E-Mail-Adresse'
530 enabled_label: 'Aktiviert' 542 enabled_label: 'Aktiviert'
531 last_login_label: 'Letzter Login' 543 last_login_label: 'Letzter Login'
532 twofactor_label: 'Zwei-Faktor-Authentifizierung' 544 # twofactor_email_label: Two factor authentication by email
545 # twofactor_google_label: Two factor authentication by OTP app
533 save: 'Speichern' 546 save: 'Speichern'
534 delete: 'Löschen' 547 delete: 'Löschen'
535 delete_confirm: 'Bist du sicher?' 548 delete_confirm: 'Bist du sicher?'
@@ -588,9 +601,11 @@ flashes:
588 entry_starred: 'Eintrag favorisiert' 601 entry_starred: 'Eintrag favorisiert'
589 entry_unstarred: 'Eintrag defavorisiert' 602 entry_unstarred: 'Eintrag defavorisiert'
590 entry_deleted: 'Eintrag gelöscht' 603 entry_deleted: 'Eintrag gelöscht'
604 # no_random_entry: 'No article with these criterias was found'
591 tag: 605 tag:
592 notice: 606 notice:
593 tag_added: 'Tag hinzugefügt' 607 tag_added: 'Tag hinzugefügt'
608 #tag_renamed: 'Tag renamed'
594 import: 609 import:
595 notice: 610 notice:
596 failed: 'Import fehlgeschlagen, bitte erneut probieren.' 611 failed: 'Import fehlgeschlagen, bitte erneut probieren.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index 6085be14..45145c80 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Add a new entry' 37 add_new_entry: 'Add a new entry'
38 search: 'Search' 38 search: 'Search'
39 filter_entries: 'Filter entries' 39 filter_entries: 'Filter entries'
40 random_entry: Jump to a random entry from that list
40 export: 'Export' 41 export: 'Export'
41 search_form: 42 search_form:
42 input_label: 'Enter your search here' 43 input_label: 'Enter your search here'
@@ -58,6 +59,7 @@ config:
58 password: 'Password' 59 password: 'Password'
59 rules: 'Tagging rules' 60 rules: 'Tagging rules'
60 new_user: 'Add a user' 61 new_user: 'Add a user'
62 reset: 'Reset area'
61 form: 63 form:
62 save: 'Save' 64 save: 'Save'
63 form_settings: 65 form_settings:
@@ -97,11 +99,19 @@ config:
97 all: 'All' 99 all: 'All'
98 rss_limit: 'Number of items in the feed' 100 rss_limit: 'Number of items in the feed'
99 form_user: 101 form_user:
100 two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connection." 102 two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Name' 103 name_label: 'Name'
102 email_label: 'Email' 104 email_label: 'Email'
103 twoFactorAuthentication_label: 'Two factor authentication' 105 two_factor:
104 help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 106 emailTwoFactor_label: 'Using email (receive a code by email)'
107 googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
108 table_method: Method
109 table_state: State
110 table_action: Action
111 state_enabled: Enabled
112 state_disabled: Disabled
113 action_email: Use email
114 action_app: Use OTP App
105 delete: 115 delete:
106 title: Delete my account (a.k.a danger zone) 116 title: Delete my account (a.k.a danger zone)
107 description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 117 description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
@@ -159,6 +169,15 @@ config:
159 and: 'One rule AND another' 169 and: 'One rule AND another'
160 matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 170 matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
161 notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 171 notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
172 otp:
173 page_title: Two-factor authentication
174 app:
175 two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
176 two_factor_code_description_2: 'You can scan that QR Code with your app:'
177 two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
178 two_factor_code_description_4: 'Test an OTP code from your configured app:'
179 cancel: Cancel
180 enable: Enable
162 181
163entry: 182entry:
164 default_title: 'Title of the entry' 183 default_title: 'Title of the entry'
@@ -404,6 +423,8 @@ tag:
404 new: 423 new:
405 add: 'Add' 424 add: 'Add'
406 placeholder: 'You can add several tags, separated by a comma.' 425 placeholder: 'You can add several tags, separated by a comma.'
426 rename:
427 placeholder: 'You can update tag name.'
407 428
408export: 429export:
409 footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 430 footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +550,8 @@ user:
529 email_label: 'Email' 550 email_label: 'Email'
530 enabled_label: 'Enabled' 551 enabled_label: 'Enabled'
531 last_login_label: 'Last login' 552 last_login_label: 'Last login'
532 twofactor_label: Two factor authentication 553 twofactor_email_label: Two factor authentication by email
554 twofactor_google_label: Two factor authentication by OTP app
533 save: Save 555 save: Save
534 delete: Delete 556 delete: Delete
535 delete_confirm: Are you sure? 557 delete_confirm: Are you sure?
@@ -575,6 +597,7 @@ flashes:
575 tags_reset: Tags reset 597 tags_reset: Tags reset
576 entries_reset: Entries reset 598 entries_reset: Entries reset
577 archived_reset: Archived entries deleted 599 archived_reset: Archived entries deleted
600 otp_enabled: Two-factor authentication enabled
578 entry: 601 entry:
579 notice: 602 notice:
580 entry_already_saved: 'Entry already saved on %date%' 603 entry_already_saved: 'Entry already saved on %date%'
@@ -588,9 +611,11 @@ flashes:
588 entry_starred: 'Entry starred' 611 entry_starred: 'Entry starred'
589 entry_unstarred: 'Entry unstarred' 612 entry_unstarred: 'Entry unstarred'
590 entry_deleted: 'Entry deleted' 613 entry_deleted: 'Entry deleted'
614 no_random_entry: 'No article with these criterias was found'
591 tag: 615 tag:
592 notice: 616 notice:
593 tag_added: 'Tag added' 617 tag_added: 'Tag added'
618 tag_renamed: 'Tag renamed'
594 import: 619 import:
595 notice: 620 notice:
596 failed: 'Import failed, please try again.' 621 failed: 'Import failed, please try again.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
index f2a8fb89..c1047e55 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Añadir un nuevo artículo' 37 add_new_entry: 'Añadir un nuevo artículo'
38 search: 'Buscar' 38 search: 'Buscar'
39 filter_entries: 'Filtrar los artículos' 39 filter_entries: 'Filtrar los artículos'
40 # random_entry: Jump to a random entry from that list
40 export: 'Exportar' 41 export: 'Exportar'
41 search_form: 42 search_form:
42 input_label: 'Introduzca su búsqueda aquí' 43 input_label: 'Introduzca su búsqueda aquí'
@@ -58,6 +59,7 @@ config:
58 password: 'Contraseña' 59 password: 'Contraseña'
59 rules: 'Reglas de etiquetado automáticas' 60 rules: 'Reglas de etiquetado automáticas'
60 new_user: 'Añadir un usuario' 61 new_user: 'Añadir un usuario'
62 reset: 'Reiniciar mi cuenta'
61 form: 63 form:
62 save: 'Guardar' 64 save: 'Guardar'
63 form_settings: 65 form_settings:
@@ -97,11 +99,19 @@ config:
97 # all: 'All' 99 # all: 'All'
98 rss_limit: 'Límite de artículos en feed RSS' 100 rss_limit: 'Límite de artículos en feed RSS'
99 form_user: 101 form_user:
100 two_factor_description: "Con la autenticación en dos pasos recibirá código por e-mail en cada nueva conexión que no sea de confianza." 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Nombre' 103 name_label: 'Nombre'
102 email_label: 'Dirección de e-mail' 104 email_label: 'Dirección de e-mail'
103 twoFactorAuthentication_label: 'Autenticación en dos pasos' 105 two_factor:
104 help_twoFactorAuthentication: "Si activas la autenticación en dos pasos, cada vez que quieras iniciar sesión en wallabag recibirás un código por e-mail." 106 # emailTwoFactor_label: 'Using email (receive a code by email)'
107 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
108 # table_method: Method
109 # table_state: State
110 # table_action: Action
111 # state_enabled: Enabled
112 # state_disabled: Disabled
113 # action_email: Use email
114 # action_app: Use OTP App
105 delete: 115 delete:
106 title: Eliminar mi cuenta (Zona peligrosa) 116 title: Eliminar mi cuenta (Zona peligrosa)
107 description: Si eliminas tu cuenta, TODOS tus artículos, TODAS tus etiquetas, TODAS tus anotaciones y tu cuenta serán eliminadas de forma PERMANENTE (no se puede deshacer). Después serás desconectado. 117 description: Si eliminas tu cuenta, TODOS tus artículos, TODAS tus etiquetas, TODAS tus anotaciones y tu cuenta serán eliminadas de forma PERMANENTE (no se puede deshacer). Después serás desconectado.
@@ -159,6 +169,15 @@ config:
159 and: 'Una regla Y la otra' 169 and: 'Una regla Y la otra'
160 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>' 170 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>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 171 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
172 otp:
173 # page_title: Two-factor authentication
174 # app:
175 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
176 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
177 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
178 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
179 # cancel: Cancel
180 # enable: Enable
162 181
163entry: 182entry:
164 default_title: 'Título del artículo' 183 default_title: 'Título del artículo'
@@ -404,6 +423,8 @@ tag:
404 new: 423 new:
405 add: 'Añadir' 424 add: 'Añadir'
406 placeholder: 'Puedes añadir varias etiquetas, separadas por una coma.' 425 placeholder: 'Puedes añadir varias etiquetas, separadas por una coma.'
426 rename:
427 # placeholder: 'You can update tag name.'
407 428
408# export: 429# export:
409# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 430# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +550,8 @@ user:
529 email_label: 'E-mail' 550 email_label: 'E-mail'
530 enabled_label: 'Activado' 551 enabled_label: 'Activado'
531 last_login_label: 'Último inicio de sesión' 552 last_login_label: 'Último inicio de sesión'
532 twofactor_label: Autenticación en dos pasos 553 # twofactor_email_label: Two factor authentication by email
554 # twofactor_google_label: Two factor authentication by OTP app
533 save: Guardar 555 save: Guardar
534 delete: Eliminar 556 delete: Eliminar
535 delete_confirm: ¿Estás seguro? 557 delete_confirm: ¿Estás seguro?
@@ -588,9 +610,11 @@ flashes:
588 entry_starred: 'Artículo marcado como favorito' 610 entry_starred: 'Artículo marcado como favorito'
589 entry_unstarred: 'Artículo desmarcado como favorito' 611 entry_unstarred: 'Artículo desmarcado como favorito'
590 entry_deleted: 'Artículo eliminado' 612 entry_deleted: 'Artículo eliminado'
613 # no_random_entry: 'No article with these criterias was found'
591 tag: 614 tag:
592 notice: 615 notice:
593 tag_added: 'Etiqueta añadida' 616 tag_added: 'Etiqueta añadida'
617 # tag_renamed: 'Tag renamed'
594 import: 618 import:
595 notice: 619 notice:
596 failed: 'Importación fallida, por favor, inténtelo de nuevo.' 620 failed: 'Importación fallida, por favor, inténtelo de nuevo.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
index a5cbd7ec..3042de2e 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'افزودن مقالهٔ تازه' 37 add_new_entry: 'افزودن مقالهٔ تازه'
38 search: 'جستجو' 38 search: 'جستجو'
39 filter_entries: 'فیلترکردن مقاله‌ها' 39 filter_entries: 'فیلترکردن مقاله‌ها'
40 # random_entry: Jump to a random entry from that list
40 export: 'برون‌بری' 41 export: 'برون‌بری'
41 search_form: 42 search_form:
42 input_label: 'جستجوی خود را این‌جا بنویسید:' 43 input_label: 'جستجوی خود را این‌جا بنویسید:'
@@ -58,6 +59,7 @@ config:
58 password: 'رمز' 59 password: 'رمز'
59 rules: 'برچسب‌گذاری خودکار' 60 rules: 'برچسب‌گذاری خودکار'
60 new_user: 'افزودن کاربر' 61 new_user: 'افزودن کاربر'
62 # reset: 'Reset area'
61 form: 63 form:
62 save: 'ذخیره' 64 save: 'ذخیره'
63 form_settings: 65 form_settings:
@@ -97,11 +99,19 @@ config:
97 # all: 'All' 99 # all: 'All'
98 rss_limit: 'محدودیت آر-اس-اس' 100 rss_limit: 'محدودیت آر-اس-اس'
99 form_user: 101 form_user:
100 two_factor_description: "با فعال‌کردن تأیید ۲مرحله‌ای هر بار که اتصال تأییدنشده‌ای برقرار شد، به شما یک کد از راه ایمیل فرستاده می‌شود" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'نام' 103 name_label: 'نام'
102 email_label: 'نشانی ایمیل' 104 email_label: 'نشانی ایمیل'
103 twoFactorAuthentication_label: 'تأیید ۲مرحله‌ای' 105 two_factor:
104 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 106 # emailTwoFactor_label: 'Using email (receive a code by email)'
107 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
108 # table_method: Method
109 # table_state: State
110 # table_action: Action
111 # state_enabled: Enabled
112 # state_disabled: Disabled
113 # action_email: Use email
114 # action_app: Use OTP App
105 delete: 115 delete:
106 # title: Delete my account (a.k.a danger zone) 116 # title: Delete my account (a.k.a danger zone)
107 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 117 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
@@ -159,6 +169,15 @@ config:
159 # and: 'One rule AND another' 169 # and: 'One rule AND another'
160 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 170 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 171 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
172 otp:
173 # page_title: Two-factor authentication
174 # app:
175 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
176 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
177 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
178 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
179 # cancel: Cancel
180 # enable: Enable
162 181
163entry: 182entry:
164 # default_title: 'Title of the entry' 183 # default_title: 'Title of the entry'
@@ -404,6 +423,8 @@ tag:
404 new: 423 new:
405 # add: 'Add' 424 # add: 'Add'
406 # placeholder: 'You can add several tags, separated by a comma.' 425 # placeholder: 'You can add several tags, separated by a comma.'
426 rename:
427 # placeholder: 'You can update tag name.'
407 428
408# export: 429# export:
409# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 430# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +550,8 @@ user:
529 email_label: 'نشانی ایمیل' 550 email_label: 'نشانی ایمیل'
530 # enabled_label: 'Enabled' 551 # enabled_label: 'Enabled'
531 # last_login_label: 'Last login' 552 # last_login_label: 'Last login'
532 # twofactor_label: Two factor authentication 553 # twofactor_email_label: Two factor authentication by email
554 # twofactor_google_label: Two factor authentication by OTP app
533 # save: Save 555 # save: Save
534 # delete: Delete 556 # delete: Delete
535 # delete_confirm: Are you sure? 557 # delete_confirm: Are you sure?
@@ -588,9 +610,11 @@ flashes:
588 entry_starred: 'مقاله برگزیده شد' 610 entry_starred: 'مقاله برگزیده شد'
589 entry_unstarred: 'مقاله نابرگزیده شد' 611 entry_unstarred: 'مقاله نابرگزیده شد'
590 entry_deleted: 'مقاله پاک شد' 612 entry_deleted: 'مقاله پاک شد'
613 # no_random_entry: 'No article with these criterias was found'
591 tag: 614 tag:
592 notice: 615 notice:
593 tag_added: 'برچسب افزوده شد' 616 tag_added: 'برچسب افزوده شد'
617 # tag_renamed: 'Tag renamed'
594 import: 618 import:
595 notice: 619 notice:
596 failed: 'درون‌ریزی شکست خورد. لطفاً دوباره تلاش کنید.' 620 failed: 'درون‌ریزی شکست خورد. لطفاً دوباره تلاش کنید.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index a36d84ae..57740ba2 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: "Sauvegarder un nouvel article" 37 add_new_entry: "Sauvegarder un nouvel article"
38 search: "Rechercher" 38 search: "Rechercher"
39 filter_entries: "Filtrer les articles" 39 filter_entries: "Filtrer les articles"
40 random_entry: Aller à un article aléatoire de cette liste
40 export: "Exporter" 41 export: "Exporter"
41 search_form: 42 search_form:
42 input_label: "Saisissez votre terme de recherche" 43 input_label: "Saisissez votre terme de recherche"
@@ -58,6 +59,7 @@ config:
58 password: "Mot de passe" 59 password: "Mot de passe"
59 rules: "Règles de tag automatiques" 60 rules: "Règles de tag automatiques"
60 new_user: "Créer un compte" 61 new_user: "Créer un compte"
62 reset: "Réinitialisation"
61 form: 63 form:
62 save: "Enregistrer" 64 save: "Enregistrer"
63 form_settings: 65 form_settings:
@@ -97,11 +99,19 @@ config:
97 all: "Tous" 99 all: "Tous"
98 rss_limit: "Nombre d’articles dans le flux" 100 rss_limit: "Nombre d’articles dans le flux"
99 form_user: 101 form_user:
100 two_factor_description: "Activer l’authentification double-facteur veut dire que vous allez recevoir un code par courriel à chaque nouvelle connexion non approuvée." 102 two_factor_description: "Activer l’authentification double-facteur veut dire que vous allez recevoir un code par courriel OU que vous devriez utiliser une application de mot de passe à usage unique (comme Google Authenticator, Authy or FreeOTP) pour obtenir un code temporaire à chaque nouvelle connexion non approuvée. Vous ne pouvez pas choisir les deux options."
101 name_label: "Nom" 103 name_label: "Nom"
102 email_label: "Adresse courriel" 104 email_label: "Adresse courriel"
103 twoFactorAuthentication_label: "Double authentification" 105 two_factor:
104 help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." 106 emailTwoFactor_label: 'En utlisant l’email (recevez un code par email)'
107 googleTwoFactor_label: 'En utilisant une application de mot de passe à usage unique (ouvrez l’app, comme Google Authenticator, Authy or FreeOTP, pour obtenir un mot de passe à usage unique)'
108 table_method: Méthode
109 table_state: État
110 table_action: Action
111 state_enabled: Activé
112 state_disabled: Désactivé
113 action_email: Utiliser l'email
114 action_app: Utiliser une app OTP
105 delete: 115 delete:
106 title: "Supprimer mon compte (attention danger !)" 116 title: "Supprimer mon compte (attention danger !)"
107 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é." 117 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é."
@@ -159,6 +169,15 @@ config:
159 and: "Une règle ET l’autre" 169 and: "Une règle ET l’autre"
160 matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>" 170 matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>"
161 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>" 171 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>"
172 otp:
173 page_title: Authentification double-facteur
174 app:
175 two_factor_code_description_1: Vous venez d’activer l’authentification double-facteur, ouvrez votre application OTP pour configurer la génération du mot de passe à usage unique. Ces informations disparaîtront après un rechargement de la page.
176 two_factor_code_description_2: 'Vous pouvez scanner le QR code avec votre application :'
177 two_factor_code_description_3: 'N’oubliez pas de sauvegarder ces codes de secours dans un endroit sûr, vous pourrez les utiliser si vous ne pouvez plus accéder à votre application OTP :'
178 two_factor_code_description_4: 'Testez un code généré par votre application OTP :'
179 cancel: Annuler
180 enable: Activer
162 181
163entry: 182entry:
164 default_title: "Titre de l’article" 183 default_title: "Titre de l’article"
@@ -404,6 +423,8 @@ tag:
404 new: 423 new:
405 add: "Ajouter" 424 add: "Ajouter"
406 placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule." 425 placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule."
426 rename:
427 placeholder: 'Vous pouvez changer le nom de votre tag.'
407 428
408export: 429export:
409 footer_template: '<div style="text-align:center;"><p>Généré par wallabag with %method%</p><p>Merci d''ouvrir <a href="https://github.com/wallabag/wallabag/issues">un ticket</a> si vous rencontrez des soucis d''affichage avec ce document sur votre support.</p></div>' 430 footer_template: '<div style="text-align:center;"><p>Généré par wallabag with %method%</p><p>Merci d''ouvrir <a href="https://github.com/wallabag/wallabag/issues">un ticket</a> si vous rencontrez des soucis d''affichage avec ce document sur votre support.</p></div>'
@@ -530,6 +551,8 @@ user:
530 enabled_label: "Activé" 551 enabled_label: "Activé"
531 last_login_label: "Dernière connexion" 552 last_login_label: "Dernière connexion"
532 twofactor_label: "Double authentification" 553 twofactor_label: "Double authentification"
554 twofactor_email_label: Double authentification par email
555 twofactor_google_label: Double authentification par OTP app
533 save: "Sauvegarder" 556 save: "Sauvegarder"
534 delete: "Supprimer" 557 delete: "Supprimer"
535 delete_confirm: "Êtes-vous sûr ?" 558 delete_confirm: "Êtes-vous sûr ?"
@@ -575,6 +598,7 @@ flashes:
575 tags_reset: "Tags supprimés" 598 tags_reset: "Tags supprimés"
576 entries_reset: "Articles supprimés" 599 entries_reset: "Articles supprimés"
577 archived_reset: "Articles archivés supprimés" 600 archived_reset: "Articles archivés supprimés"
601 otp_enabled: "Authentification à double-facteur activée"
578 entry: 602 entry:
579 notice: 603 notice:
580 entry_already_saved: "Article déjà sauvegardé le %date%" 604 entry_already_saved: "Article déjà sauvegardé le %date%"
@@ -588,9 +612,11 @@ flashes:
588 entry_starred: "Article ajouté dans les favoris" 612 entry_starred: "Article ajouté dans les favoris"
589 entry_unstarred: "Article retiré des favoris" 613 entry_unstarred: "Article retiré des favoris"
590 entry_deleted: "Article supprimé" 614 entry_deleted: "Article supprimé"
615 no_random_entry: "Aucun article correspond aux critères n'a été trouvé"
591 tag: 616 tag:
592 notice: 617 notice:
593 tag_added: "Tag ajouté" 618 tag_added: "Tag ajouté"
619 tag_renamed: "Tag renommé"
594 import: 620 import:
595 notice: 621 notice:
596 failed: "L’import a échoué, veuillez ré-essayer" 622 failed: "L’import a échoué, veuillez ré-essayer"
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
index 1649c0e4..274e5338 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Aggiungi un nuovo contenuto' 37 add_new_entry: 'Aggiungi un nuovo contenuto'
38 search: 'Cerca' 38 search: 'Cerca'
39 filter_entries: 'Filtra contenuti' 39 filter_entries: 'Filtra contenuti'
40 # random_entry: Jump to a random entry from that list
40 export: 'Esporta' 41 export: 'Esporta'
41 search_form: 42 search_form:
42 input_label: 'Inserisci qui la tua ricerca' 43 input_label: 'Inserisci qui la tua ricerca'
@@ -58,6 +59,7 @@ config:
58 password: 'Password' 59 password: 'Password'
59 rules: 'Regole di etichettatura' 60 rules: 'Regole di etichettatura'
60 new_user: 'Aggiungi utente' 61 new_user: 'Aggiungi utente'
62 reset: 'Area di reset'
61 form: 63 form:
62 save: 'Salva' 64 save: 'Salva'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 # all: 'All' 99 # all: 'All'
98 rss_limit: 'Numero di elementi nel feed' 100 rss_limit: 'Numero di elementi nel feed'
99 form_user: 101 form_user:
100 two_factor_description: "Abilitando l'autenticazione a due fattori riceverai una e-mail con un codice per ogni nuova connesione non verificata" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Nome' 103 name_label: 'Nome'
102 email_label: 'E-mail' 104 email_label: 'E-mail'
103 twoFactorAuthentication_label: 'Autenticazione a due fattori' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 help_twoFactorAuthentication: "Se abiliti l'autenticazione a due fattori, ogni volta che vorrai connetterti a wallabag, riceverai un codice via E-mail." 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 title: Cancella il mio account (zona pericolosa) 115 title: Cancella il mio account (zona pericolosa)
107 description: Rimuovendo il tuo account, TUTTI i tuoi articoli, TUTTE le tue etichette, TUTTE le tue annotazioni ed il tuo account verranno rimossi PERMANENTEMENTE (impossibile da ANNULLARE). Verrai poi disconnesso. 116 description: Rimuovendo il tuo account, TUTTI i tuoi articoli, TUTTE le tue etichette, TUTTE le tue annotazioni ed il tuo account verranno rimossi PERMANENTEMENTE (impossibile da ANNULLARE). Verrai poi disconnesso.
@@ -159,6 +168,15 @@ config:
159 and: "Una regola E un'altra" 168 and: "Una regola E un'altra"
160 matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>' 169 matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 170 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 default_title: "Titolo del contenuto" 182 default_title: "Titolo del contenuto"
@@ -404,6 +422,8 @@ tag:
404 new: 422 new:
405 add: 'Aggiungi' 423 add: 'Aggiungi'
406 placeholder: 'Puoi aggiungere varie etichette, separate da una virgola.' 424 placeholder: 'Puoi aggiungere varie etichette, separate da una virgola.'
425 rename:
426 # placeholder: 'You can update tag name.'
407 427
408# export: 428# export:
409# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 429# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +549,8 @@ user:
529 email_label: 'E-mail' 549 email_label: 'E-mail'
530 enabled_label: 'Abilitato' 550 enabled_label: 'Abilitato'
531 last_login_label: 'Ultima connessione' 551 last_login_label: 'Ultima connessione'
532 twofactor_label: Autenticazione a due fattori 552 # twofactor_email_label: Two factor authentication by email
553 # twofactor_google_label: Two factor authentication by OTP app
533 save: Salva 554 save: Salva
534 delete: Cancella 555 delete: Cancella
535 delete_confirm: Sei sicuro? 556 delete_confirm: Sei sicuro?
@@ -588,9 +609,11 @@ flashes:
588 entry_starred: 'Contenuto segnato come preferito' 609 entry_starred: 'Contenuto segnato come preferito'
589 entry_unstarred: 'Contenuto rimosso dai preferiti' 610 entry_unstarred: 'Contenuto rimosso dai preferiti'
590 entry_deleted: 'Contenuto eliminato' 611 entry_deleted: 'Contenuto eliminato'
612 # no_random_entry: 'No article with these criterias was found'
591 tag: 613 tag:
592 notice: 614 notice:
593 tag_added: 'Etichetta aggiunta' 615 tag_added: 'Etichetta aggiunta'
616 # tag_renamed: 'Tag renamed'
594 import: 617 import:
595 notice: 618 notice:
596 failed: 'Importazione fallita, riprova.' 619 failed: 'Importazione fallita, riprova.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
index e2298f1f..4e5370f9 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Enregistrar un novèl article' 37 add_new_entry: 'Enregistrar un novèl article'
38 search: 'Cercar' 38 search: 'Cercar'
39 filter_entries: 'Filtrar los articles' 39 filter_entries: 'Filtrar los articles'
40 # random_entry: Jump to a random entry from that list
40 export: 'Exportar' 41 export: 'Exportar'
41 search_form: 42 search_form:
42 input_label: 'Picatz vòstre mot-clau a cercar aquí' 43 input_label: 'Picatz vòstre mot-clau a cercar aquí'
@@ -58,6 +59,7 @@ config:
58 password: 'Senhal' 59 password: 'Senhal'
59 rules: "Règlas d'etiquetas automaticas" 60 rules: "Règlas d'etiquetas automaticas"
60 new_user: 'Crear un compte' 61 new_user: 'Crear un compte'
62 reset: 'Zòna de reïnicializacion'
61 form: 63 form:
62 save: 'Enregistrar' 64 save: 'Enregistrar'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 all: 'Totes' 99 all: 'Totes'
98 rss_limit: "Nombre d'articles dins un flux RSS" 100 rss_limit: "Nombre d'articles dins un flux RSS"
99 form_user: 101 form_user:
100 two_factor_description: "Activar l'autentificacion en dos temps vòl dire que recebretz un còdi per corrièl per cada novèla connexion pas aprovada." 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Nom' 103 name_label: 'Nom'
102 email_label: 'Adreça de corrièl' 104 email_label: 'Adreça de corrièl'
103 twoFactorAuthentication_label: 'Dobla autentificacion' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 help_twoFactorAuthentication: "S'avètz activat l'autentificacion en dos temps, cada còp que volètz vos connectar a wallabag, recebretz un còdi per corrièl." 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 title: Suprimir mon compte (Mèfi zòna perilhosa) 115 title: Suprimir mon compte (Mèfi zòna perilhosa)
107 description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat. 116 description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat.
@@ -159,6 +168,15 @@ config:
159 and: "Una règla E l'autra" 168 and: "Una règla E l'autra"
160 matches: 'Teste se un <i>subjècte</i> correspond a una <i>recèrca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>' 169 matches: 'Teste se un <i>subjècte</i> correspond a una <i>recèrca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>'
161 notmatches: 'Teste se <i>subjècte</i> correspond pas a una <i>recèrca</i> (sensibla a la cassa).<br />Example : <code>title notmatches "football"</code>' 170 notmatches: 'Teste se <i>subjècte</i> correspond pas a una <i>recèrca</i> (sensibla a la cassa).<br />Example : <code>title notmatches "football"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 default_title: "Títol de l'article" 182 default_title: "Títol de l'article"
@@ -404,6 +422,8 @@ tag:
404 new: 422 new:
405 add: 'Ajustar' 423 add: 'Ajustar'
406 placeholder: "Podètz ajustar mai qu'una etiqueta, separadas per de virgula." 424 placeholder: "Podètz ajustar mai qu'una etiqueta, separadas per de virgula."
425 rename:
426 # placeholder: 'You can update tag name.'
407 427
408export: 428export:
409 footer_template: '<div style="text-align:center;"><p>Produch per wallabag amb %method%</p><p>Mercés de dobrir <a href="https://github.com/wallabag/wallabag/issues">una sollicitacion</a> s’avètz de problèmas amb l’afichatge d’aqueste E-Book sus vòstre periferic.</p></div>' 429 footer_template: '<div style="text-align:center;"><p>Produch per wallabag amb %method%</p><p>Mercés de dobrir <a href="https://github.com/wallabag/wallabag/issues">una sollicitacion</a> s’avètz de problèmas amb l’afichatge d’aqueste E-Book sus vòstre periferic.</p></div>'
@@ -529,7 +549,8 @@ user:
529 email_label: 'Adreça de corrièl' 549 email_label: 'Adreça de corrièl'
530 enabled_label: 'Actiu' 550 enabled_label: 'Actiu'
531 last_login_label: 'Darrièra connexion' 551 last_login_label: 'Darrièra connexion'
532 twofactor_label: 'Autentificacion doble-factor' 552 # twofactor_email_label: Two factor authentication by email
553 # twofactor_google_label: Two factor authentication by OTP app
533 save: 'Enregistrar' 554 save: 'Enregistrar'
534 delete: 'Suprimir' 555 delete: 'Suprimir'
535 delete_confirm: 'Sètz segur ?' 556 delete_confirm: 'Sètz segur ?'
@@ -588,9 +609,11 @@ flashes:
588 entry_starred: 'Article ajustat dins los favorits' 609 entry_starred: 'Article ajustat dins los favorits'
589 entry_unstarred: 'Article quitat dels favorits' 610 entry_unstarred: 'Article quitat dels favorits'
590 entry_deleted: 'Article suprimit' 611 entry_deleted: 'Article suprimit'
612 # no_random_entry: 'No article with these criterias was found'
591 tag: 613 tag:
592 notice: 614 notice:
593 tag_added: 'Etiqueta ajustada' 615 tag_added: 'Etiqueta ajustada'
616 # tag_renamed: 'Tag renamed'
594 import: 617 import:
595 notice: 618 notice:
596 failed: "L'importacion a fracassat, mercés de tornar ensajar." 619 failed: "L'importacion a fracassat, mercés de tornar ensajar."
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
index a5712733..a7a4d6c3 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Dodaj nowy wpis' 37 add_new_entry: 'Dodaj nowy wpis'
38 search: 'Szukaj' 38 search: 'Szukaj'
39 filter_entries: 'Filtruj wpisy' 39 filter_entries: 'Filtruj wpisy'
40 # random_entry: Jump to a random entry from that list
40 export: 'Eksportuj' 41 export: 'Eksportuj'
41 search_form: 42 search_form:
42 input_label: 'Wpisz swoje zapytanie tutaj' 43 input_label: 'Wpisz swoje zapytanie tutaj'
@@ -58,6 +59,7 @@ config:
58 password: 'Hasło' 59 password: 'Hasło'
59 rules: 'Zasady tagowania' 60 rules: 'Zasady tagowania'
60 new_user: 'Dodaj użytkownika' 61 new_user: 'Dodaj użytkownika'
62 reset: 'Reset'
61 form: 63 form:
62 save: 'Zapisz' 64 save: 'Zapisz'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 all: 'Wszystkie' 99 all: 'Wszystkie'
98 rss_limit: 'Link do RSS' 100 rss_limit: 'Link do RSS'
99 form_user: 101 form_user:
100 two_factor_description: "Włączenie autoryzacji dwuetapowej oznacza, że będziesz otrzymywał maile z kodem przy każdym nowym, niezaufanym połączeniu" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Nazwa' 103 name_label: 'Nazwa'
102 email_label: 'Adres email' 104 email_label: 'Adres email'
103 twoFactorAuthentication_label: 'Autoryzacja dwuetapowa' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 help_twoFactorAuthentication: "Jeżeli włączysz autoryzację dwuetapową. Za każdym razem, kiedy będziesz chciał się zalogować, dostaniesz kod na swój e-mail." 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 title: Usuń moje konto (niebezpieczna strefa !) 115 title: Usuń moje konto (niebezpieczna strefa !)
107 description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany. 116 description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany.
@@ -159,6 +168,15 @@ config:
159 and: 'Jedna reguła I inna' 168 and: 'Jedna reguła I inna'
160 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>' 169 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>'
161 notmatches: 'Sprawdź czy <i>temat</i> nie zawiera <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł nie zawiera "piłka nożna"</code>' 170 notmatches: 'Sprawdź czy <i>temat</i> nie zawiera <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł nie zawiera "piłka nożna"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 default_title: 'Tytuł wpisu' 182 default_title: 'Tytuł wpisu'
@@ -404,6 +422,8 @@ tag:
404 new: 422 new:
405 add: 'Dodaj' 423 add: 'Dodaj'
406 placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.' 424 placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.'
425 rename:
426 placeholder: 'Możesz zaktualizować nazwę taga.'
407 427
408export: 428export:
409 footer_template: '<div style="text-align:center;"><p>Stworzone przez wallabag z %method%</p><p>Proszę zgłoś <a href="https://github.com/wallabag/wallabag/issues">sprawę</a>, jeżeli masz problem z wyświetleniem tego e-booka na swoim urządzeniu.</p></div>' 429 footer_template: '<div style="text-align:center;"><p>Stworzone przez wallabag z %method%</p><p>Proszę zgłoś <a href="https://github.com/wallabag/wallabag/issues">sprawę</a>, jeżeli masz problem z wyświetleniem tego e-booka na swoim urządzeniu.</p></div>'
@@ -529,7 +549,8 @@ user:
529 email_label: 'Adres email' 549 email_label: 'Adres email'
530 enabled_label: 'Włączony' 550 enabled_label: 'Włączony'
531 last_login_label: 'Ostatnie logowanie' 551 last_login_label: 'Ostatnie logowanie'
532 twofactor_label: Autoryzacja dwuetapowa 552 # twofactor_email_label: Two factor authentication by email
553 # twofactor_google_label: Two factor authentication by OTP app
533 save: Zapisz 554 save: Zapisz
534 delete: Usuń 555 delete: Usuń
535 delete_confirm: Jesteś pewien? 556 delete_confirm: Jesteś pewien?
@@ -588,9 +609,11 @@ flashes:
588 entry_starred: 'Wpis oznaczony gwiazdką' 609 entry_starred: 'Wpis oznaczony gwiazdką'
589 entry_unstarred: 'Wpis odznaczony gwiazdką' 610 entry_unstarred: 'Wpis odznaczony gwiazdką'
590 entry_deleted: 'Wpis usunięty' 611 entry_deleted: 'Wpis usunięty'
612 # no_random_entry: 'No article with these criterias was found'
591 tag: 613 tag:
592 notice: 614 notice:
593 tag_added: 'Tag dodany' 615 tag_added: 'Tag dodany'
616 tag_renamed: 'Nazwa taga zmieniona'
594 import: 617 import:
595 notice: 618 notice:
596 failed: 'Nieudany import, prosimy spróbować ponownie.' 619 failed: 'Nieudany import, prosimy spróbować ponownie.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
index 1ccf49e1..a5483a6d 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Adicionar uma nova entrada' 37 add_new_entry: 'Adicionar uma nova entrada'
38 search: 'Pesquisa' 38 search: 'Pesquisa'
39 filter_entries: 'Filtrar entradas' 39 filter_entries: 'Filtrar entradas'
40 # random_entry: Jump to a random entry from that list
40 export: 'Exportar' 41 export: 'Exportar'
41 search_form: 42 search_form:
42 input_label: 'Digite aqui sua pesquisa' 43 input_label: 'Digite aqui sua pesquisa'
@@ -58,6 +59,7 @@ config:
58 password: 'Senha' 59 password: 'Senha'
59 rules: 'Regras de tags' 60 rules: 'Regras de tags'
60 new_user: 'Adicionar um usuário' 61 new_user: 'Adicionar um usuário'
62 # reset: 'Reset area'
61 form: 63 form:
62 save: 'Salvar' 64 save: 'Salvar'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 # all: 'All' 99 # all: 'All'
98 rss_limit: 'Número de itens no feed' 100 rss_limit: 'Número de itens no feed'
99 form_user: 101 form_user:
100 two_factor_description: 'Habilitar autenticação de dois passos significa que você receberá um e-mail com um código a cada nova conexão desconhecida.' 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Nome' 103 name_label: 'Nome'
102 email_label: 'E-mail' 104 email_label: 'E-mail'
103 twoFactorAuthentication_label: 'Autenticação de dois passos' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 # title: Delete my account (a.k.a danger zone) 115 # title: Delete my account (a.k.a danger zone)
107 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 116 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
@@ -159,6 +168,15 @@ config:
159 and: 'Uma regra E outra' 168 and: 'Uma regra E outra'
160 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>' 169 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>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 170 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 default_title: 'Título da entrada' 182 default_title: 'Título da entrada'
@@ -404,6 +422,8 @@ tag:
404 new: 422 new:
405 # add: 'Add' 423 # add: 'Add'
406 # placeholder: 'You can add several tags, separated by a comma.' 424 # placeholder: 'You can add several tags, separated by a comma.'
425 rename:
426 # placeholder: 'You can update tag name.'
407 427
408# export: 428# export:
409# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 429# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +549,8 @@ user:
529 email_label: 'E-mail' 549 email_label: 'E-mail'
530 enabled_label: 'Habilitado' 550 enabled_label: 'Habilitado'
531 last_login_label: 'Último login' 551 last_login_label: 'Último login'
532 twofactor_label: 'Autenticação de dois passos' 552 # twofactor_email_label: Two factor authentication by email
553 # twofactor_google_label: Two factor authentication by OTP app
533 save: 'Salvar' 554 save: 'Salvar'
534 delete: 'Apagar' 555 delete: 'Apagar'
535 delete_confirm: 'Tem certeza?' 556 delete_confirm: 'Tem certeza?'
@@ -588,9 +609,11 @@ flashes:
588 entry_starred: 'Entrada destacada' 609 entry_starred: 'Entrada destacada'
589 entry_unstarred: 'Entrada não destacada' 610 entry_unstarred: 'Entrada não destacada'
590 entry_deleted: 'Entrada apagada' 611 entry_deleted: 'Entrada apagada'
612 # no_random_entry: 'No article with these criterias was found'
591 tag: 613 tag:
592 notice: 614 notice:
593 tag_added: 'Tag adicionada' 615 tag_added: 'Tag adicionada'
616 # tag_renamed: 'Tag renamed'
594 import: 617 import:
595 notice: 618 notice:
596 failed: 'Importação falhou, por favor tente novamente.' 619 failed: 'Importação falhou, por favor tente novamente.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
index 6c0e18e1..3b7fbd69 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Introdu un nou articol' 37 add_new_entry: 'Introdu un nou articol'
38 search: 'Căutare' 38 search: 'Căutare'
39 filter_entries: 'Filtrează articolele' 39 filter_entries: 'Filtrează articolele'
40 # random_entry: Jump to a random entry from that list
40 # export: 'Export' 41 # export: 'Export'
41 search_form: 42 search_form:
42 input_label: 'Introdu căutarea ta' 43 input_label: 'Introdu căutarea ta'
@@ -58,6 +59,7 @@ config:
58 password: 'Parolă' 59 password: 'Parolă'
59 # rules: 'Tagging rules' 60 # rules: 'Tagging rules'
60 new_user: 'Crează un utilizator' 61 new_user: 'Crează un utilizator'
62 # reset: 'Reset area'
61 form: 63 form:
62 save: 'Salvează' 64 save: 'Salvează'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 # all: 'All' 99 # all: 'All'
98 rss_limit: 'Limită RSS' 100 rss_limit: 'Limită RSS'
99 form_user: 101 form_user:
100 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'Nume' 103 name_label: 'Nume'
102 email_label: 'E-mail' 104 email_label: 'E-mail'
103 # twoFactorAuthentication_label: 'Two factor authentication' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 # title: Delete my account (a.k.a danger zone) 115 # title: Delete my account (a.k.a danger zone)
107 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 116 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
@@ -159,6 +168,15 @@ config:
159 # and: 'One rule AND another' 168 # and: 'One rule AND another'
160 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 169 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 170 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 # default_title: 'Title of the entry' 182 # default_title: 'Title of the entry'
@@ -404,6 +422,8 @@ tag:
404 new: 422 new:
405 # add: 'Add' 423 # add: 'Add'
406 # placeholder: 'You can add several tags, separated by a comma.' 424 # placeholder: 'You can add several tags, separated by a comma.'
425 rename:
426 # placeholder: 'You can update tag name.'
407 427
408# export: 428# export:
409# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 429# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -529,7 +549,8 @@ user:
529 email_label: 'E-mail' 549 email_label: 'E-mail'
530 # enabled_label: 'Enabled' 550 # enabled_label: 'Enabled'
531 # last_login_label: 'Last login' 551 # last_login_label: 'Last login'
532 # twofactor_label: Two factor authentication 552 # twofactor_email_label: Two factor authentication by email
553 # twofactor_google_label: Two factor authentication by OTP app
533 # save: Save 554 # save: Save
534 # delete: Delete 555 # delete: Delete
535 # delete_confirm: Are you sure? 556 # delete_confirm: Are you sure?
@@ -588,9 +609,11 @@ flashes:
588 entry_starred: 'Articol adăugat la favorite' 609 entry_starred: 'Articol adăugat la favorite'
589 entry_unstarred: 'Articol șters de la favorite' 610 entry_unstarred: 'Articol șters de la favorite'
590 entry_deleted: 'Articol șters' 611 entry_deleted: 'Articol șters'
612 # no_random_entry: 'No article with these criterias was found'
591 tag: 613 tag:
592 notice: 614 notice:
593 # tag_added: 'Tag added' 615 # tag_added: 'Tag added'
616 # tag_renamed: 'Tag renamed'
594 import: 617 import:
595 notice: 618 notice:
596 # failed: 'Import failed, please try again.' 619 # failed: 'Import failed, please try again.'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml
index 48753b55..92746631 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml
@@ -36,6 +36,7 @@ menu:
36 add_new_entry: 'Добавить новую запись' 36 add_new_entry: 'Добавить новую запись'
37 search: 'Поиск' 37 search: 'Поиск'
38 filter_entries: 'Фильтр записей' 38 filter_entries: 'Фильтр записей'
39 # random_entry: Jump to a random entry from that list
39 export: 'Экспорт' 40 export: 'Экспорт'
40 search_form: 41 search_form:
41 input_label: 'Введите текст для поиска' 42 input_label: 'Введите текст для поиска'
@@ -57,6 +58,7 @@ config:
57 password: 'Пароль' 58 password: 'Пароль'
58 rules: 'Правила настройки простановки тегов' 59 rules: 'Правила настройки простановки тегов'
59 new_user: 'Добавить пользователя' 60 new_user: 'Добавить пользователя'
61 reset: 'Сброс данных'
60 form: 62 form:
61 save: 'Сохранить' 63 save: 'Сохранить'
62 form_settings: 64 form_settings:
@@ -94,11 +96,18 @@ config:
94 archive: 'архивные' 96 archive: 'архивные'
95 rss_limit: 'Количество записей в фиде' 97 rss_limit: 'Количество записей в фиде'
96 form_user: 98 form_user:
97 two_factor_description: "Включить двухфакторную аутентификацию, Вы получите сообщение на указанный email с кодом, при каждом новом непроверенном подключении." 99 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
98 name_label: 'Имя' 100 name_label: 'Имя'
99 email_label: 'Email' 101 email_label: 'Email'
100 twoFactorAuthentication_label: 'Двухфакторная аутентификация' 102 # emailTwoFactor_label: 'Using email (receive a code by email)'
101 help_twoFactorAuthentication: "Если Вы включите двухфакторную аутентификацию, то Вы будете получать код на указанный ранее email, каждый раз при входе в wallabag." 103 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
104 # table_method: Method
105 # table_state: State
106 # table_action: Action
107 # state_enabled: Enabled
108 # state_disabled: Disabled
109 # action_email: Use email
110 # action_app: Use OTP App
102 delete: 111 delete:
103 title: "Удалить мой аккаунт (или опасная зона)" 112 title: "Удалить мой аккаунт (или опасная зона)"
104 description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы." 113 description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы."
@@ -154,6 +163,15 @@ config:
154 or: 'Одно правило ИЛИ другое' 163 or: 'Одно правило ИЛИ другое'
155 and: 'Одно правило И другое' 164 and: 'Одно правило И другое'
156 matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>' 165 matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>'
166 otp:
167 # page_title: Two-factor authentication
168 # app:
169 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
170 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
171 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
172 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
173 # cancel: Cancel
174 # enable: Enable
157 175
158entry: 176entry:
159 default_title: 'Название записи' 177 default_title: 'Название записи'
@@ -392,6 +410,8 @@ tag:
392 new: 410 new:
393 add: 'Добавить' 411 add: 'Добавить'
394 placeholder: 'Вы можете добавить несколько тегов, разделенных запятой.' 412 placeholder: 'Вы можете добавить несколько тегов, разделенных запятой.'
413 rename:
414 # placeholder: 'You can update tag name.'
395 415
396# export: 416# export:
397# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 417# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -517,7 +537,8 @@ user:
517 email_label: 'Email' 537 email_label: 'Email'
518 enabled_label: 'Включить' 538 enabled_label: 'Включить'
519 last_login_label: 'Последний вход' 539 last_login_label: 'Последний вход'
520 twofactor_label: "Двухфакторная аутентификация" 540 # twofactor_email_label: Two factor authentication by email
541 # twofactor_google_label: Two factor authentication by OTP app
521 save: "Сохранить" 542 save: "Сохранить"
522 delete: "Удалить" 543 delete: "Удалить"
523 delete_confirm: "Вы уверены?" 544 delete_confirm: "Вы уверены?"
@@ -553,9 +574,11 @@ flashes:
553 entry_starred: 'Запись помечена звездочкой' 574 entry_starred: 'Запись помечена звездочкой'
554 entry_unstarred: 'Пометка звездочкой у записи убрана' 575 entry_unstarred: 'Пометка звездочкой у записи убрана'
555 entry_deleted: 'Запись удалена' 576 entry_deleted: 'Запись удалена'
577 # no_random_entry: 'No article with these criterias was found'
556 tag: 578 tag:
557 notice: 579 notice:
558 tag_added: 'Тег добавлен' 580 tag_added: 'Тег добавлен'
581 # tag_renamed: 'Tag renamed'
559 import: 582 import:
560 notice: 583 notice:
561 failed: 'Во время импорта произошла ошибка, повторите попытку.' 584 failed: 'Во время импорта произошла ошибка, повторите попытку.'
@@ -573,4 +596,4 @@ flashes:
573 notice: 596 notice:
574 added: 'Пользователь "%username%" добавлен' 597 added: 'Пользователь "%username%" добавлен'
575 updated: 'Пользователь "%username%" обновлен' 598 updated: 'Пользователь "%username%" обновлен'
576 deleted: 'Пользователь "%username%" удален' \ No newline at end of file 599 deleted: 'Пользователь "%username%" удален'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml
index 5524b1f1..1fe4fa0e 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'เพิ่มรายการใหม่' 37 add_new_entry: 'เพิ่มรายการใหม่'
38 search: 'ค้นหา' 38 search: 'ค้นหา'
39 filter_entries: 'ตัวกรองรายการ' 39 filter_entries: 'ตัวกรองรายการ'
40 # random_entry: Jump to a random entry from that list
40 export: 'นำข้อมูลออก' 41 export: 'นำข้อมูลออก'
41 search_form: 42 search_form:
42 input_label: 'ค้นหาที่นี้' 43 input_label: 'ค้นหาที่นี้'
@@ -58,6 +59,7 @@ config:
58 password: 'รหัสผ่าน' 59 password: 'รหัสผ่าน'
59 rules: 'การแท็กข้อบังคับ' 60 rules: 'การแท็กข้อบังคับ'
60 new_user: 'เพิ่มผู้ใช้' 61 new_user: 'เพิ่มผู้ใช้'
62 reset: 'รีเซ็ตพื้นที่ '
61 form: 63 form:
62 save: 'บันทึก' 64 save: 'บันทึก'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 all: 'ทั้งหมด' 99 all: 'ทั้งหมด'
98 rss_limit: 'จำนวนไอเทมที่เก็บ' 100 rss_limit: 'จำนวนไอเทมที่เก็บ'
99 form_user: 101 form_user:
100 two_factor_description: "การเปิดใช้งาน two factor authentication คือคุณจะต้องได้รับอีเมลกับ code ที่ยังไม่ตรวจสอบในการเชื่อมต่อ" 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'ชื่อ' 103 name_label: 'ชื่อ'
102 email_label: 'อีเมล' 104 email_label: 'อีเมล'
103 twoFactorAuthentication_label: 'Two factor authentication' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 help_twoFactorAuthentication: "ถ้าคุณเปิด 2FA, ในแต่ละช่วงเวลาที่คุณต้องการลงชื่อเข้าใช wallabag, คุณจะต้องได้รับ code จากอีเมล" 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 title: ลบบัญชีของฉัน (โซนที่เป็นภัย!) 115 title: ลบบัญชีของฉัน (โซนที่เป็นภัย!)
107 description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก 116 description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก
@@ -159,6 +168,15 @@ config:
159 and: 'หนึ่งข้อบังคับและอื่นๆ' 168 and: 'หนึ่งข้อบังคับและอื่นๆ'
160 matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>' 169 matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>'
161 notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>' 170 notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 default_title: 'หัวข้อรายการ' 182 default_title: 'หัวข้อรายการ'
@@ -402,6 +420,8 @@ tag:
402 new: 420 new:
403 add: 'เพิ่ม' 421 add: 'เพิ่ม'
404 placeholder: 'คุณสามารถเพิ่มได้หลายแท็ก, จากการแบ่งโดย comma' 422 placeholder: 'คุณสามารถเพิ่มได้หลายแท็ก, จากการแบ่งโดย comma'
423 rename:
424 # placeholder: 'You can update tag name.'
405 425
406export: 426export:
407 footer_template: '<div style="text-align:center;"><p>ผลิตโดย wallabag กับ %method%</p><p>ให้ทำการเปิด <a href="https://github.com/wallabag/wallabag/issues">ฉบับนี้</a> ถ้าคุณมีข้อบกพร่องif you have trouble with the display of this E-Book on your device.</p></div>' 427 footer_template: '<div style="text-align:center;"><p>ผลิตโดย wallabag กับ %method%</p><p>ให้ทำการเปิด <a href="https://github.com/wallabag/wallabag/issues">ฉบับนี้</a> ถ้าคุณมีข้อบกพร่องif you have trouble with the display of this E-Book on your device.</p></div>'
@@ -527,7 +547,8 @@ user:
527 email_label: 'อีเมล' 547 email_label: 'อีเมล'
528 enabled_label: 'เปิดใช้งาน' 548 enabled_label: 'เปิดใช้งาน'
529 last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย' 549 last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย'
530 twofactor_label: Two factor authentication 550 # twofactor_email_label: Two factor authentication by email
551 # twofactor_google_label: Two factor authentication by OTP app
531 save: บันทึก 552 save: บันทึก
532 delete: ลบ 553 delete: ลบ
533 delete_confirm: ตุณแน่ใจหรือไม่? 554 delete_confirm: ตุณแน่ใจหรือไม่?
@@ -586,9 +607,11 @@ flashes:
586 entry_starred: 'รายการที่แสดง' 607 entry_starred: 'รายการที่แสดง'
587 entry_unstarred: 'รายการที่ไม่ได้แสดง' 608 entry_unstarred: 'รายการที่ไม่ได้แสดง'
588 entry_deleted: 'รายการที่ถูกลบ' 609 entry_deleted: 'รายการที่ถูกลบ'
610 # no_random_entry: 'No article with these criterias was found'
589 tag: 611 tag:
590 notice: 612 notice:
591 tag_added: 'แท็กที่เพิ่ม' 613 tag_added: 'แท็กที่เพิ่ม'
614 # tag_renamed: 'Tag renamed'
592 import: 615 import:
593 notice: 616 notice:
594 failed: 'นำข้อมูลเข้าล้มเหลว, ลองใหม่อีกครั้ง' 617 failed: 'นำข้อมูลเข้าล้มเหลว, ลองใหม่อีกครั้ง'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
index e2156d47..3b8a0d59 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
@@ -37,6 +37,7 @@ menu:
37 add_new_entry: 'Yeni bir makale ekle' 37 add_new_entry: 'Yeni bir makale ekle'
38 search: 'Ara' 38 search: 'Ara'
39 filter_entries: 'Filtrele' 39 filter_entries: 'Filtrele'
40 # random_entry: Jump to a random entry from that list
40 export: 'Dışa Aktar' 41 export: 'Dışa Aktar'
41 search_form: 42 search_form:
42 input_label: 'Aramak istediğiniz herhangi bir şey yazın' 43 input_label: 'Aramak istediğiniz herhangi bir şey yazın'
@@ -58,6 +59,7 @@ config:
58 password: 'Şifre' 59 password: 'Şifre'
59 rules: 'Etiketleme kuralları' 60 rules: 'Etiketleme kuralları'
60 new_user: 'Bir kullanıcı ekle' 61 new_user: 'Bir kullanıcı ekle'
62 # reset: 'Reset area'
61 form: 63 form:
62 save: 'Kaydet' 64 save: 'Kaydet'
63 form_settings: 65 form_settings:
@@ -97,11 +99,18 @@ config:
97 # all: 'All' 99 # all: 'All'
98 rss_limit: 'RSS içeriğinden talep edilecek makale limiti' 100 rss_limit: 'RSS içeriğinden talep edilecek makale limiti'
99 form_user: 101 form_user:
100 two_factor_description: "İki adımlı doğrulamayı aktifleştirdiğinizde, her yeni güvenilmeyen bağlantılarda size e-posta ile bir kod alacaksınız." 102 # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
101 name_label: 'İsim' 103 name_label: 'İsim'
102 email_label: 'E-posta' 104 email_label: 'E-posta'
103 twoFactorAuthentication_label: 'İki adımlı doğrulama' 105 # emailTwoFactor_label: 'Using email (receive a code by email)'
104 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 106 # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
107 # table_method: Method
108 # table_state: State
109 # table_action: Action
110 # state_enabled: Enabled
111 # state_disabled: Disabled
112 # action_email: Use email
113 # action_app: Use OTP App
105 delete: 114 delete:
106 # title: Delete my account (a.k.a danger zone) 115 # title: Delete my account (a.k.a danger zone)
107 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 116 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
@@ -159,6 +168,15 @@ config:
159 and: 'Bir kural ve diğeri' 168 and: 'Bir kural ve diğeri'
160 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' 169 # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
161 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' 170 # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
171 otp:
172 # page_title: Two-factor authentication
173 # app:
174 # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
175 # two_factor_code_description_2: 'You can scan that QR Code with your app:'
176 # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
177 # two_factor_code_description_4: 'Test an OTP code from your configured app:'
178 # cancel: Cancel
179 # enable: Enable
162 180
163entry: 181entry:
164 default_title: 'Makalenin başlığı' 182 default_title: 'Makalenin başlığı'
@@ -402,6 +420,8 @@ tag:
402 new: 420 new:
403 # add: 'Add' 421 # add: 'Add'
404 # placeholder: 'You can add several tags, separated by a comma.' 422 # placeholder: 'You can add several tags, separated by a comma.'
423 rename:
424 # placeholder: 'You can update tag name.'
405 425
406# export: 426# export:
407# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>' 427# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
@@ -527,7 +547,8 @@ user:
527 email_label: 'E-posta' 547 email_label: 'E-posta'
528 # enabled_label: 'Enabled' 548 # enabled_label: 'Enabled'
529 # last_login_label: 'Last login' 549 # last_login_label: 'Last login'
530 # twofactor_label: Two factor authentication 550 # twofactor_email_label: Two factor authentication by email
551 # twofactor_google_label: Two factor authentication by OTP app
531 # save: Save 552 # save: Save
532 # delete: Delete 553 # delete: Delete
533 # delete_confirm: Are you sure? 554 # delete_confirm: Are you sure?
@@ -566,9 +587,11 @@ flashes:
566 entry_starred: 'Makale favorilere eklendi' 587 entry_starred: 'Makale favorilere eklendi'
567 entry_unstarred: 'Makale favorilerden çıkartıldı' 588 entry_unstarred: 'Makale favorilerden çıkartıldı'
568 entry_deleted: 'Makale silindi' 589 entry_deleted: 'Makale silindi'
590 # no_random_entry: 'No article with these criterias was found'
569 tag: 591 tag:
570 notice: 592 notice:
571 tag_added: 'Etiket eklendi' 593 tag_added: 'Etiket eklendi'
594 # tag_renamed: 'Tag renamed'
572 import: 595 import:
573 notice: 596 notice:
574 # failed: 'Import failed, please try again.' 597 # failed: 'Import failed, please try again.'
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 bcc57dac..93f8ddf8 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
@@ -86,8 +86,7 @@
86 <br/> 86 <br/>
87 <img id="androidQrcode" /> 87 <img id="androidQrcode" />
88 <script> 88 <script>
89 const imgBase64 = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}'); 89 document.getElementById('androidQrcode').src = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}');
90 document.getElementById('androidQrcode').src = imgBase64;
91 </script> 90 </script>
92 </div> 91 </div>
93 </fieldset> 92 </fieldset>
@@ -169,52 +168,41 @@
169 </div> 168 </div>
170 </fieldset> 169 </fieldset>
171 170
171 {{ form_widget(form.user.save) }}
172
172 {% if twofactor_auth %} 173 {% if twofactor_auth %}
174 <h5>{{ 'config.otp.page_title'|trans }}</h5>
175
173 <div class="row"> 176 <div class="row">
174 {{ 'config.form_user.two_factor_description'|trans }} 177 {{ 'config.form_user.two_factor_description'|trans }}
175 </div> 178 </div>
176 179
177 <fieldset class="w500p inline"> 180 <table>
178 <div class="row"> 181 <thead>
179 {{ form_label(form.user.twoFactorAuthentication) }} 182 <tr>
180 {{ form_errors(form.user.twoFactorAuthentication) }} 183 <th>{{ 'config.form_user.two_factor.table_method'|trans }}</th>
181 {{ form_widget(form.user.twoFactorAuthentication) }} 184 <th>{{ 'config.form_user.two_factor.table_state'|trans }}</th>
182 </div> 185 <th>{{ 'config.form_user.two_factor.table_action'|trans }}</th>
183 <a href="#" title="{{ 'config.form_user.help_twoFactorAuthentication'|trans }}"> 186 </tr>
184 <i class="material-icons">live_help</i> 187 </thead>
185 </a>
186 </fieldset>
187 {% endif %}
188 188
189 <h2>{{ 'config.reset.title'|trans }}</h2> 189 <tbody>
190 <fieldset class="w500p inline"> 190 <tr>
191 <p>{{ 'config.reset.description'|trans }}</p> 191 <td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td>
192 <ul> 192 <td>{% if app.user.isEmailTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
193 <li> 193 <td><a href="{{ path('config_otp_email') }}" class="waves-effect waves-light btn{% if app.user.isEmailTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_email'|trans }}</a></td>
194 <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> 194 </tr>
195 {{ 'config.reset.annotations'|trans }} 195 <tr>
196 </a> 196 <td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td>
197 </li> 197 <td>{% if app.user.isGoogleTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
198 <li> 198 <td><a href="{{ path('config_otp_app') }}" class="waves-effect waves-light btn{% if app.user.isGoogleTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_app'|trans }}</a></td>
199 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> 199 </tr>
200 {{ 'config.reset.tags'|trans }} 200 </tbody>
201 </a> 201 </table>
202 </li> 202
203 <li> 203 {% endif %}
204 <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
205 {{ 'config.reset.archived'|trans }}
206 </a>
207 </li>
208 <li>
209 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
210 {{ 'config.reset.entries'|trans }}
211 </a>
212 </li>
213 </ul>
214 </fieldset>
215 204
216 {{ form_widget(form.user._token) }} 205 {{ form_widget(form.user._token) }}
217 {{ form_widget(form.user.save) }}
218 </form> 206 </form>
219 207
220 {% if enabled_users > 1 %} 208 {% if enabled_users > 1 %}
@@ -277,7 +265,7 @@
277 {% endfor %} 265 {% endfor %}
278 </ul> 266 </ul>
279 267
280 {{ form_start(form.new_tagging_rule) }} 268 {{ form_start(form.new_tagging_rule) }}
281 {{ form_errors(form.new_tagging_rule) }} 269 {{ form_errors(form.new_tagging_rule) }}
282 270
283 <fieldset class="w500p inline"> 271 <fieldset class="w500p inline">
@@ -382,4 +370,31 @@
382 </table> 370 </table>
383 </div> 371 </div>
384 </div> 372 </div>
373
374 <h2>{{ 'config.reset.title'|trans }}</h2>
375 <fieldset class="w500p inline">
376 <p>{{ 'config.reset.description'|trans }}</p>
377 <ul>
378 <li>
379 <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
380 {{ 'config.reset.annotations'|trans }}
381 </a>
382 </li>
383 <li>
384 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
385 {{ 'config.reset.tags'|trans }}
386 </a>
387 </li>
388 <li>
389 <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
390 {{ 'config.reset.archived'|trans }}
391 </a>
392 </li>
393 <li>
394 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
395 {{ 'config.reset.entries'|trans }}
396 </a>
397 </li>
398 </ul>
399 </fieldset>
385{% endblock %} 400{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig
new file mode 100644
index 00000000..0919646e
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig
@@ -0,0 +1,55 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'config.page_title'|trans }} > {{ 'config.otp.page_title'|trans }}{% endblock %}
4
5{% block content %}
6 <h5>{{ 'config.otp.page_title'|trans }}</h5>
7
8 <ol>
9 <li>
10 <p>{{ 'config.otp.app.two_factor_code_description_1'|trans }}</p>
11 <p>{{ 'config.otp.app.two_factor_code_description_2'|trans }}</p>
12
13 <p>
14 <img id="2faQrcode" class="hide-on-med-and-down" />
15 <script>
16 document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ qr_code }}');
17 </script>
18 </p>
19 </li>
20 <li>
21 <p>{{ 'config.otp.app.two_factor_code_description_3'|trans }}</p>
22
23 <p><strong>{{ backupCodes|join("\n")|nl2br }}</strong></p>
24 </li>
25 <li>
26 <p>{{ 'config.otp.app.two_factor_code_description_4'|trans }}</p>
27
28 {% for flashMessage in app.session.flashbag.get("two_factor") %}
29 <div class="card-panel red darken-1 black-text">
30 {{ flashMessage|trans }}
31 </div>
32 {% endfor %}
33
34 <form class="form" action="{{ path("config_otp_app_check") }}" method="post">
35 <div class="card-content">
36 <div class="row">
37 <div class="input-field col s12">
38 <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label>
39 <input id="_auth_code" type="text" autocomplete="off" name="_auth_code" />
40 </div>
41 </div>
42 </div>
43 <div class="card-action">
44 <a href="{{ path('config_otp_app_cancel') }}" class="waves-effect waves-light grey btn">
45 {{ 'config.otp.app.cancel'|trans }}
46 </a>
47 <button class="btn waves-effect waves-light" type="submit" name="send">
48 {{ 'config.otp.app.enable'|trans }}
49 <i class="material-icons right">send</i>
50 </button>
51 </div>
52 </form>
53 </li>
54 </ol>
55{% endblock %}
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 832112be..fb296c9d 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
@@ -20,6 +20,9 @@
20 20
21{% block content %} 21{% block content %}
22 {% set currentRoute = app.request.attributes.get('_route') %} 22 {% set currentRoute = app.request.attributes.get('_route') %}
23 {% if currentRoute == 'homepage' %}
24 {% set currentRoute = 'unread' %}
25 {% endif %}
23 {% set listMode = app.user.config.listMode %} 26 {% set listMode = app.user.config.listMode %}
24 <div class="results"> 27 <div class="results">
25 <div class="nb-results">{{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}</div> 28 <div class="nb-results">{{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}</div>
@@ -28,6 +31,9 @@
28 {% if app.user.config.rssToken %} 31 {% if app.user.config.rssToken %}
29 {% include "@WallabagCore/themes/common/Entry/_rss_link.html.twig" %} 32 {% include "@WallabagCore/themes/common/Entry/_rss_link.html.twig" %}
30 {% endif %} 33 {% endif %}
34 {% if currentRoute in ['unread', 'starred', 'archive', 'untagged', 'all'] %}
35 <a href="{{ path('random_entry', { 'type': currentRoute }) }}"><i class="btn-clickable material-icons md-24 js-random-action">casino</i></a>
36 {% endif %}
31 <i class="btn-clickable download-btn material-icons md-24 js-export-action">file_download</i> 37 <i class="btn-clickable download-btn material-icons md-24 js-export-action">file_download</i>
32 <i class="btn-clickable filter-btn material-icons md-24 js-filters-action">filter_list</i> 38 <i class="btn-clickable filter-btn material-icons md-24 js-filters-action">filter_list</i>
33 {% if entries.getNbPages > 1 %} 39 {% if entries.getNbPages > 1 %}
@@ -90,9 +96,6 @@
90 {% if tag is defined %} 96 {% if tag is defined %}
91 {% set currentTag = tag %} 97 {% set currentTag = tag %}
92 {% endif %} 98 {% endif %}
93 {% if currentRoute == 'homepage' %}
94 {% set currentRoute = 'unread' %}
95 {% endif %}
96 <h2>{{ 'entry.list.export_title'|trans }}</h2> 99 <h2>{{ 'entry.list.export_title'|trans }}</h2>
97 <a href="javascript: void(null);" id="download-form-close" class="close-button--popup close-button">&times;</a> 100 <a href="javascript: void(null);" id="download-form-close" class="close-button--popup close-button">&times;</a>
98 <ul> 101 <ul>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig
index 070d5629..35351ab1 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig
@@ -10,10 +10,22 @@
10 <ul> 10 <ul>
11 {% for tag in tags %} 11 {% for tag in tags %}
12 <li id="tag-{{ tag.id|e }}"> 12 <li id="tag-{{ tag.id|e }}">
13 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.nbEntries }})</a> 13 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}" data-handle="tag-link">{{ tag.label }}&nbsp;({{ tag.nbEntries }})</a>
14 <a rel="alternate" type="application/rss+xml" href="{{ path('tag_rss', {'username': app.user.username, 'token': app.user.config.rssToken, 'slug': tag.slug}) }}" class="right"> 14
15 <i class="material-icons md-24">rss_feed</i> 15 {% if renameForms is defined and renameForms[tag.id] is defined %}
16 <form class="card-tag-form hidden" data-handle="tag-rename-form" action="{{ path('tag_rename', {'slug': tag.slug})}}" method="POST">
17 {{ form_widget(renameForms[tag.id].label, {'attr': {'value': tag.label}}) }}
18 {{ form_rest(renameForms[tag.id]) }}
19 </form>
20 <a class="card-tag-rename" data-handler="tag-rename" href="javascript:void(0);">
21 <i class="material-icons">mode_edit</i>
16 </a> 22 </a>
23 {% endif %}
24 {% if app.user.config.rssToken %}
25 <a rel="alternate" type="application/rss+xml" href="{{ path('tag_rss', {'username': app.user.username, 'token': app.user.config.rssToken, 'slug': tag.slug}) }}" class="right">
26 <i class="material-icons md-24">rss_feed</i>
27 </a>
28 {% endif %}
17 </li> 29 </li>
18 {% endfor %} 30 {% endfor %}
19 </ul> 31 </ul>
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 f896fe2d..412c18f4 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
@@ -16,6 +16,7 @@
16 <li class="tab col s12 m6 l3"><a href="#set3">{{ 'config.tab_menu.user_info'|trans }}</a></li> 16 <li class="tab col s12 m6 l3"><a href="#set3">{{ 'config.tab_menu.user_info'|trans }}</a></li>
17 <li class="tab col s12 m6 l3"><a href="#set4">{{ 'config.tab_menu.password'|trans }}</a></li> 17 <li class="tab col s12 m6 l3"><a href="#set4">{{ 'config.tab_menu.password'|trans }}</a></li>
18 <li class="tab col s12 m6 l3"><a href="#set5">{{ 'config.tab_menu.rules'|trans }}</a></li> 18 <li class="tab col s12 m6 l3"><a href="#set5">{{ 'config.tab_menu.rules'|trans }}</a></li>
19 <li class="tab col s12 m6 l3"><a href="#set6">{{ 'config.tab_menu.reset'|trans }}</a></li>
19 </ul> 20 </ul>
20 </div> 21 </div>
21 22
@@ -111,8 +112,7 @@
111 <img id="androidQrcode" class="hide-on-med-and-down" /> 112 <img id="androidQrcode" class="hide-on-med-and-down" />
112 </div> 113 </div>
113 <script> 114 <script>
114 const imgBase64 = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}'); 115 document.getElementById('androidQrcode').src = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}');
115 document.getElementById('androidQrcode').src = imgBase64;
116 </script> 116 </script>
117 </div> 117 </div>
118 118
@@ -196,59 +196,42 @@
196 </div> 196 </div>
197 </div> 197 </div>
198 198
199 {% if twofactor_auth %} 199 {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
200 <div class="row">
201 <div class="input-field col s11">
202 {{ 'config.form_user.two_factor_description'|trans }}
203
204 <br />
205 200
206 {{ form_widget(form.user.twoFactorAuthentication) }} 201 {% if twofactor_auth %}
207 {{ form_label(form.user.twoFactorAuthentication) }} 202 <br/>
208 {{ form_errors(form.user.twoFactorAuthentication) }} 203 <br/>
209 </div> 204 <div class="row">
210 <div class="input-field col s1"> 205 <h5>{{ 'config.otp.page_title'|trans }}</h5>
211 <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_user.help_twoFactorAuthentication'|trans }}"> 206
212 <i class="material-icons">live_help</i> 207 <p>{{ 'config.form_user.two_factor_description'|trans }}</p>
213 </a> 208
209 <table>
210 <thead>
211 <tr>
212 <th>{{ 'config.form_user.two_factor.table_method'|trans }}</th>
213 <th>{{ 'config.form_user.two_factor.table_state'|trans }}</th>
214 <th>{{ 'config.form_user.two_factor.table_action'|trans }}</th>
215 </tr>
216 </thead>
217
218 <tbody>
219 <tr>
220 <td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td>
221 <td>{% if app.user.isEmailTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
222 <td><a href="{{ path('config_otp_email') }}" class="waves-effect waves-light btn{% if app.user.isEmailTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_email'|trans }}</a></td>
223 </tr>
224 <tr>
225 <td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td>
226 <td>{% if app.user.isGoogleTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
227 <td><a href="{{ path('config_otp_app') }}" class="waves-effect waves-light btn{% if app.user.isGoogleTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_app'|trans }}</a></td>
228 </tr>
229 </tbody>
230 </table>
214 </div> 231 </div>
215 </div>
216 {% endif %} 232 {% endif %}
217
218 {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
219 {{ form_widget(form.user._token) }} 233 {{ form_widget(form.user._token) }}
220 </form> 234 </form>
221
222 <br /><hr /><br />
223
224 <div class="row">
225 <h5>{{ 'config.reset.title'|trans }}</h5>
226 <p>{{ 'config.reset.description'|trans }}</p>
227 <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
228 {{ 'config.reset.annotations'|trans }}
229 </a>
230 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
231 {{ 'config.reset.tags'|trans }}
232 </a>
233 <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
234 {{ 'config.reset.archived'|trans }}
235 </a>
236 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
237 {{ 'config.reset.entries'|trans }}
238 </a>
239 </div>
240
241 {% if enabled_users > 1 %}
242 <br /><hr /><br />
243
244 <div class="row">
245 <h5>{{ 'config.form_user.delete.title'|trans }}</h5>
246 <p>{{ 'config.form_user.delete.description'|trans }}</p>
247 <a href="{{ path('delete_account') }}" onclick="return confirm('{{ 'config.form_user.delete.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red delete-account">
248 {{ 'config.form_user.delete.button'|trans }}
249 </a>
250 </div>
251 {% endif %}
252 </div> 235 </div>
253 236
254 <div id="set4" class="col s12"> 237 <div id="set4" class="col s12">
@@ -422,6 +405,37 @@
422 </div> 405 </div>
423 </div> 406 </div>
424 </div> 407 </div>
408
409 <div id="set6" class="col s12">
410 <div class="row">
411 <h5>{{ 'config.reset.title'|trans }}</h5>
412 <p>{{ 'config.reset.description'|trans }}</p>
413 <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
414 {{ 'config.reset.annotations'|trans }}
415 </a>
416 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
417 {{ 'config.reset.tags'|trans }}
418 </a>
419 <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
420 {{ 'config.reset.archived'|trans }}
421 </a>
422 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
423 {{ 'config.reset.entries'|trans }}
424 </a>
425 </div>
426
427 {% if enabled_users > 1 %}
428 <br /><hr /><br />
429
430 <div class="row">
431 <h5>{{ 'config.form_user.delete.title'|trans }}</h5>
432 <p>{{ 'config.form_user.delete.description'|trans }}</p>
433 <a href="{{ path('delete_account') }}" onclick="return confirm('{{ 'config.form_user.delete.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red delete-account">
434 {{ 'config.form_user.delete.button'|trans }}
435 </a>
436 </div>
437 {% endif %}
438 </div>
425 </div> 439 </div>
426 440
427 </div> 441 </div>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig
new file mode 100644
index 00000000..7875d787
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig
@@ -0,0 +1,63 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'config.page_title'|trans }} > {{ 'config.otp.page_title'|trans }}{% endblock %}
4
5{% block content %}
6 <div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9 <div class="row">
10 <h5>{{ 'config.otp.page_title'|trans }}</h5>
11
12 <ol>
13 <li>
14 <p>{{ 'config.otp.app.two_factor_code_description_1'|trans }}</p>
15 <p>{{ 'config.otp.app.two_factor_code_description_2'|trans }}</p>
16
17 <p>
18 <img id="2faQrcode" class="hide-on-med-and-down" />
19 <script>
20 document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ qr_code }}');
21 </script>
22 </p>
23 </li>
24 <li>
25 <p>{{ 'config.otp.app.two_factor_code_description_3'|trans }}</p>
26
27 <p><strong>{{ backupCodes|join("\n")|nl2br }}</strong></p>
28 </li>
29 <li>
30 <p>{{ 'config.otp.app.two_factor_code_description_4'|trans }}</p>
31
32 {% for flashMessage in app.session.flashbag.get("two_factor") %}
33 <div class="card-panel red darken-1 black-text">
34 {{ flashMessage|trans }}
35 </div>
36 {% endfor %}
37
38 <form class="form" action="{{ path("config_otp_app_check") }}" method="post">
39 <div class="card-content">
40 <div class="row">
41 <div class="input-field col s12">
42 <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label>
43 <input id="_auth_code" type="text" autocomplete="off" name="_auth_code" />
44 </div>
45 </div>
46 </div>
47 <div class="card-action">
48 <a href="{{ path('config_otp_app_cancel') }}" class="waves-effect waves-light grey btn">
49 {{ 'config.otp.app.cancel'|trans }}
50 </a>
51 <button class="btn waves-effect waves-light" type="submit" name="send">
52 {{ 'config.otp.app.enable'|trans }}
53 <i class="material-icons right">send</i>
54 </button>
55 </div>
56 </form>
57 </li>
58 </ol>
59 </div>
60 </div>
61 </div>
62 </div>
63{% endblock %}
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 742dd330..067c8975 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
@@ -21,6 +21,9 @@
21{% block content %} 21{% block content %}
22 {% set listMode = app.user.config.listMode %} 22 {% set listMode = app.user.config.listMode %}
23 {% set currentRoute = app.request.attributes.get('_route') %} 23 {% set currentRoute = app.request.attributes.get('_route') %}
24 {% if currentRoute == 'homepage' %}
25 {% set currentRoute = 'unread' %}
26 {% endif %}
24 <div class="results"> 27 <div class="results">
25 <div class="nb-results"> 28 <div class="nb-results">
26 {{ 'entry.list.number_on_the_page'|transchoice(entries.count) }} 29 {{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}
@@ -60,9 +63,6 @@
60 {% if tag is defined %} 63 {% if tag is defined %}
61 {% set currentTag = tag.slug %} 64 {% set currentTag = tag.slug %}
62 {% endif %} 65 {% endif %}
63 {% if currentRoute == 'homepage' %}
64 {% set currentRoute = 'unread' %}
65 {% endif %}
66 <h4 class="center">{{ 'entry.list.export_title'|trans }}</h4> 66 <h4 class="center">{{ 'entry.list.export_title'|trans }}</h4>
67 <ul> 67 <ul>
68 {% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %} 68 {% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
index c15b5146..21e88a9a 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
@@ -13,7 +13,18 @@
13 <ul class="card-tag-labels"> 13 <ul class="card-tag-labels">
14 {% for tag in tags %} 14 {% for tag in tags %}
15 <li title="{{tag.label}} ({{ tag.nbEntries }})" id="tag-{{ tag.id }}"> 15 <li title="{{tag.label}} ({{ tag.nbEntries }})" id="tag-{{ tag.id }}">
16 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}" class="card-tag-link">{{tag.label}} ({{ tag.nbEntries }})</a> 16 <a href="{{ path('tag_entries', {'slug': tag.slug}) }}" class="card-tag-link" data-handle="tag-link">
17 {{ tag.label }}&nbsp;({{ tag.nbEntries }})
18 </a>
19 {% if renameForms is defined and renameForms[tag.id] is defined %}
20 <form class="card-tag-form hidden" data-handle="tag-rename-form" action="{{ path('tag_rename', {'slug': tag.slug})}}" method="POST">
21 {{ form_widget(renameForms[tag.id].label, {'attr': {'value': tag.label}}) }}
22 {{ form_rest(renameForms[tag.id]) }}
23 </form>
24 <a class="card-tag-rename" data-handler="tag-rename" href="javascript:void(0);">
25 <i class="material-icons">mode_edit</i>
26 </a>
27 {% endif %}
17 {% if app.user.config.rssToken %} 28 {% if app.user.config.rssToken %}
18 <a rel="alternate" type="application/rss+xml" href="{{ path('tag_rss', {'username': app.user.username, 'token': app.user.config.rssToken, 'slug': tag.slug}) }}" class="card-tag-rss"><i class="material-icons">rss_feed</i></a> 29 <a rel="alternate" type="application/rss+xml" href="{{ path('tag_rss', {'username': app.user.username, 'token': app.user.config.rssToken, 'slug': tag.slug}) }}" class="card-tag-rss"><i class="material-icons">rss_feed</i></a>
19 {% endif %} 30 {% endif %}
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 052a8c01..b9c45567 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -46,6 +46,8 @@
46 {% set activeRoute = 'starred' %} 46 {% set activeRoute = 'starred' %}
47 {% elseif currentRoute == 'unread' or currentRoute == 'homepage' or currentRouteFromQueryParams == 'unread' %} 47 {% elseif currentRoute == 'unread' or currentRoute == 'homepage' or currentRouteFromQueryParams == 'unread' %}
48 {% set activeRoute = 'unread' %} 48 {% set activeRoute = 'unread' %}
49 {% elseif currentRoute == 'untagged' %}
50 {% set activeRoute = 'untagged' %}
49 {% endif %} 51 {% endif %}
50 52
51 <li class="bold {% if activeRoute == 'unread' %}active{% endif %}"> 53 <li class="bold {% if activeRoute == 'unread' %}active{% endif %}">
@@ -113,6 +115,13 @@
113 <i class="material-icons">search</i> 115 <i class="material-icons">search</i>
114 </a> 116 </a>
115 </li> 117 </li>
118 {% if activeRoute %}
119 <li id="button_random">
120 <a class="waves-effect tooltipped js-random-action" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.random_entry'|trans }}" href="{{ path('random_entry', { 'type': activeRoute }) }}">
121 <i class="material-icons">casino</i>
122 </a>
123 </li>
124 {% endif %}
116 <li id="button_filters"> 125 <li id="button_filters">
117 <a class="nav-panel-menu button-collapse-right tooltipped js-filters-action" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.filter_entries'|trans }}" href="#" data-activates="filters"> 126 <a class="nav-panel-menu button-collapse-right tooltipped js-filters-action" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.filter_entries'|trans }}" href="#" data-activates="filters">
118 <i class="material-icons">filter_list</i> 127 <i class="material-icons">filter_list</i>
@@ -125,7 +134,7 @@
125 </li> 134 </li>
126 </ul> 135 </ul>
127 </div> 136 </div>
128 {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': app.request.attributes.get('_route')})) }} 137 {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': currentRoute})) }}
129 {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }} 138 {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }}
130 </div> 139 </div>
131 </nav> 140 </nav>
diff --git a/src/Wallabag/ImportBundle/Controller/BrowserController.php b/src/Wallabag/ImportBundle/Controller/BrowserController.php
index 6418925c..58d2a730 100644
--- a/src/Wallabag/ImportBundle/Controller/BrowserController.php
+++ b/src/Wallabag/ImportBundle/Controller/BrowserController.php
@@ -2,10 +2,10 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\HttpFoundation\Response; 7use Symfony\Component\HttpFoundation\Response;
8use Symfony\Component\Routing\Annotation\Route;
9use Wallabag\ImportBundle\Form\Type\UploadImportType; 9use Wallabag\ImportBundle\Form\Type\UploadImportType;
10 10
11abstract class BrowserController extends Controller 11abstract class BrowserController extends Controller
diff --git a/src/Wallabag/ImportBundle/Controller/ChromeController.php b/src/Wallabag/ImportBundle/Controller/ChromeController.php
index 0cb418a1..6628cdb0 100644
--- a/src/Wallabag/ImportBundle/Controller/ChromeController.php
+++ b/src/Wallabag/ImportBundle/Controller/ChromeController.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Component\HttpFoundation\Request; 5use Symfony\Component\HttpFoundation\Request;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class ChromeController extends BrowserController 8class ChromeController extends BrowserController
9{ 9{
diff --git a/src/Wallabag/ImportBundle/Controller/FirefoxController.php b/src/Wallabag/ImportBundle/Controller/FirefoxController.php
index 88697f9d..dce8455f 100644
--- a/src/Wallabag/ImportBundle/Controller/FirefoxController.php
+++ b/src/Wallabag/ImportBundle/Controller/FirefoxController.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Component\HttpFoundation\Request; 5use Symfony\Component\HttpFoundation\Request;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class FirefoxController extends BrowserController 8class FirefoxController extends BrowserController
9{ 9{
diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php
index 7e4fd174..fbd7434e 100644
--- a/src/Wallabag/ImportBundle/Controller/ImportController.php
+++ b/src/Wallabag/ImportBundle/Controller/ImportController.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class ImportController extends Controller 8class ImportController extends Controller
9{ 9{
diff --git a/src/Wallabag/ImportBundle/Controller/InstapaperController.php b/src/Wallabag/ImportBundle/Controller/InstapaperController.php
index f184baf9..faed3b72 100644
--- a/src/Wallabag/ImportBundle/Controller/InstapaperController.php
+++ b/src/Wallabag/ImportBundle/Controller/InstapaperController.php
@@ -2,9 +2,9 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Routing\Annotation\Route;
8use Wallabag\ImportBundle\Form\Type\UploadImportType; 8use Wallabag\ImportBundle\Form\Type\UploadImportType;
9 9
10class InstapaperController extends Controller 10class InstapaperController extends Controller
diff --git a/src/Wallabag/ImportBundle/Controller/PinboardController.php b/src/Wallabag/ImportBundle/Controller/PinboardController.php
index 6f54c69a..cc6fae79 100644
--- a/src/Wallabag/ImportBundle/Controller/PinboardController.php
+++ b/src/Wallabag/ImportBundle/Controller/PinboardController.php
@@ -2,9 +2,9 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Routing\Annotation\Route;
8use Wallabag\ImportBundle\Form\Type\UploadImportType; 8use Wallabag\ImportBundle\Form\Type\UploadImportType;
9 9
10class PinboardController extends Controller 10class PinboardController extends Controller
diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php
index 9f28819a..71ceb427 100644
--- a/src/Wallabag/ImportBundle/Controller/PocketController.php
+++ b/src/Wallabag/ImportBundle/Controller/PocketController.php
@@ -2,10 +2,10 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\Form\Extension\Core\Type\CheckboxType; 6use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
8use Symfony\Component\HttpFoundation\Request; 7use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\Routing\Annotation\Route;
9use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 9use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
10 10
11class PocketController extends Controller 11class PocketController extends Controller
diff --git a/src/Wallabag/ImportBundle/Controller/ReadabilityController.php b/src/Wallabag/ImportBundle/Controller/ReadabilityController.php
index 729a97a3..b120ef96 100644
--- a/src/Wallabag/ImportBundle/Controller/ReadabilityController.php
+++ b/src/Wallabag/ImportBundle/Controller/ReadabilityController.php
@@ -2,9 +2,9 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Routing\Annotation\Route;
8use Wallabag\ImportBundle\Form\Type\UploadImportType; 8use Wallabag\ImportBundle\Form\Type\UploadImportType;
9 9
10class ReadabilityController extends Controller 10class ReadabilityController extends Controller
diff --git a/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php b/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php
index d700d8a8..e1c35343 100644
--- a/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php
+++ b/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Component\HttpFoundation\Request; 5use Symfony\Component\HttpFoundation\Request;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class WallabagV1Controller extends WallabagController 8class WallabagV1Controller extends WallabagController
9{ 9{
diff --git a/src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php b/src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php
index ab26400c..c4116c1d 100644
--- a/src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php
+++ b/src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\ImportBundle\Controller; 3namespace Wallabag\ImportBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Component\HttpFoundation\Request; 5use Symfony\Component\HttpFoundation\Request;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class WallabagV2Controller extends WallabagController 8class WallabagV2Controller extends WallabagController
9{ 9{
diff --git a/src/Wallabag/ImportBundle/Import/BrowserImport.php b/src/Wallabag/ImportBundle/Import/BrowserImport.php
index 4678ae0c..804bc6cd 100644
--- a/src/Wallabag/ImportBundle/Import/BrowserImport.php
+++ b/src/Wallabag/ImportBundle/Import/BrowserImport.php
@@ -133,7 +133,7 @@ abstract class BrowserImport extends AbstractImport
133 ); 133 );
134 } 134 }
135 135
136 $entry->setArchived($data['is_archived']); 136 $entry->updateArchived($data['is_archived']);
137 137
138 if (!empty($data['created_at'])) { 138 if (!empty($data['created_at'])) {
139 $dt = new \DateTime(); 139 $dt = new \DateTime();
diff --git a/src/Wallabag/ImportBundle/Import/InstapaperImport.php b/src/Wallabag/ImportBundle/Import/InstapaperImport.php
index 5a18c7c0..439c978c 100644
--- a/src/Wallabag/ImportBundle/Import/InstapaperImport.php
+++ b/src/Wallabag/ImportBundle/Import/InstapaperImport.php
@@ -62,7 +62,7 @@ class InstapaperImport extends AbstractImport
62 } 62 }
63 63
64 $entries = []; 64 $entries = [];
65 $handle = fopen($this->filepath, 'rb'); 65 $handle = fopen($this->filepath, 'r');
66 while (false !== ($data = fgetcsv($handle, 10240))) { 66 while (false !== ($data = fgetcsv($handle, 10240))) {
67 if ('URL' === $data[0]) { 67 if ('URL' === $data[0]) {
68 continue; 68 continue;
@@ -79,7 +79,6 @@ class InstapaperImport extends AbstractImport
79 $entries[] = [ 79 $entries[] = [
80 'url' => $data[0], 80 'url' => $data[0],
81 'title' => $data[1], 81 'title' => $data[1],
82 'status' => $data[3],
83 'is_archived' => 'Archive' === $data[3] || 'Starred' === $data[3], 82 'is_archived' => 'Archive' === $data[3] || 'Starred' === $data[3],
84 'is_starred' => 'Starred' === $data[3], 83 'is_starred' => 'Starred' === $data[3],
85 'html' => false, 84 'html' => false,
@@ -147,7 +146,7 @@ class InstapaperImport extends AbstractImport
147 ); 146 );
148 } 147 }
149 148
150 $entry->setArchived($importedEntry['is_archived']); 149 $entry->updateArchived($importedEntry['is_archived']);
151 $entry->setStarred($importedEntry['is_starred']); 150 $entry->setStarred($importedEntry['is_starred']);
152 151
153 $this->em->persist($entry); 152 $this->em->persist($entry);
diff --git a/src/Wallabag/ImportBundle/Import/PinboardImport.php b/src/Wallabag/ImportBundle/Import/PinboardImport.php
index 995d1f2c..202eb1b3 100644
--- a/src/Wallabag/ImportBundle/Import/PinboardImport.php
+++ b/src/Wallabag/ImportBundle/Import/PinboardImport.php
@@ -131,7 +131,7 @@ class PinboardImport extends AbstractImport
131 ); 131 );
132 } 132 }
133 133
134 $entry->setArchived($data['is_archived']); 134 $entry->updateArchived($data['is_archived']);
135 $entry->setStarred($data['is_starred']); 135 $entry->setStarred($data['is_starred']);
136 $entry->setCreatedAt(new \DateTime($data['created_at'])); 136 $entry->setCreatedAt(new \DateTime($data['created_at']));
137 137
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php
index 5737928d..a39d8156 100644
--- a/src/Wallabag/ImportBundle/Import/PocketImport.php
+++ b/src/Wallabag/ImportBundle/Import/PocketImport.php
@@ -206,7 +206,7 @@ class PocketImport extends AbstractImport
206 $this->fetchContent($entry, $url); 206 $this->fetchContent($entry, $url);
207 207
208 // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted 208 // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted
209 $entry->setArchived(1 === (int) $importedEntry['status'] || $this->markAsRead); 209 $entry->updateArchived(1 === (int) $importedEntry['status'] || $this->markAsRead);
210 210
211 // 0 or 1 - 1 if the item is starred 211 // 0 or 1 - 1 if the item is starred
212 $entry->setStarred(1 === (int) $importedEntry['favorite']); 212 $entry->setStarred(1 === (int) $importedEntry['favorite']);
diff --git a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
index a5f3798e..c5abf189 100644
--- a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
+++ b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
@@ -123,7 +123,7 @@ class ReadabilityImport extends AbstractImport
123 // update entry with content (in case fetching failed, the given entry will be return) 123 // update entry with content (in case fetching failed, the given entry will be return)
124 $this->fetchContent($entry, $data['url'], $data); 124 $this->fetchContent($entry, $data['url'], $data);
125 125
126 $entry->setArchived($data['is_archived']); 126 $entry->updateArchived($data['is_archived']);
127 $entry->setStarred($data['is_starred']); 127 $entry->setStarred($data['is_starred']);
128 $entry->setCreatedAt(new \DateTime($data['created_at'])); 128 $entry->setCreatedAt(new \DateTime($data['created_at']));
129 129
diff --git a/src/Wallabag/ImportBundle/Import/WallabagImport.php b/src/Wallabag/ImportBundle/Import/WallabagImport.php
index 350d0600..c3a142b9 100644
--- a/src/Wallabag/ImportBundle/Import/WallabagImport.php
+++ b/src/Wallabag/ImportBundle/Import/WallabagImport.php
@@ -134,7 +134,7 @@ abstract class WallabagImport extends AbstractImport
134 $entry->setPreviewPicture($importedEntry['preview_picture']); 134 $entry->setPreviewPicture($importedEntry['preview_picture']);
135 } 135 }
136 136
137 $entry->setArchived($data['is_archived']); 137 $entry->updateArchived($data['is_archived']);
138 $entry->setStarred($data['is_starred']); 138 $entry->setStarred($data['is_starred']);
139 139
140 if (!empty($data['created_at'])) { 140 if (!empty($data['created_at'])) {
diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml
index b224a6a2..2dd7dff8 100644
--- a/src/Wallabag/ImportBundle/Resources/config/services.yml
+++ b/src/Wallabag/ImportBundle/Resources/config/services.yml
@@ -112,3 +112,11 @@ services:
112 - [ setLogger, [ "@logger" ]] 112 - [ setLogger, [ "@logger" ]]
113 tags: 113 tags:
114 - { name: wallabag_import.import, alias: chrome } 114 - { name: wallabag_import.import, alias: chrome }
115
116 wallabag_import.command.import:
117 class: Wallabag\ImportBundle\Command\ImportCommand
118 tags: ['console.command']
119
120 wallabag_import.command.redis_worker:
121 class: Wallabag\ImportBundle\Command\RedisWorkerCommand
122 tags: ['console.command']
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php
index f3de656f..63a06206 100644
--- a/src/Wallabag/UserBundle/Controller/ManageController.php
+++ b/src/Wallabag/UserBundle/Controller/ManageController.php
@@ -7,10 +7,9 @@ use FOS\UserBundle\FOSUserEvents;
7use Pagerfanta\Adapter\DoctrineORMAdapter; 7use Pagerfanta\Adapter\DoctrineORMAdapter;
8use Pagerfanta\Exception\OutOfRangeCurrentPageException; 8use Pagerfanta\Exception\OutOfRangeCurrentPageException;
9use Pagerfanta\Pagerfanta; 9use Pagerfanta\Pagerfanta;
10use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
11use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
12use Symfony\Bundle\FrameworkBundle\Controller\Controller; 10use Symfony\Bundle\FrameworkBundle\Controller\Controller;
13use Symfony\Component\HttpFoundation\Request; 11use Symfony\Component\HttpFoundation\Request;
12use Symfony\Component\Routing\Annotation\Route;
14use Wallabag\UserBundle\Entity\User; 13use Wallabag\UserBundle\Entity\User;
15use Wallabag\UserBundle\Form\SearchUserType; 14use Wallabag\UserBundle\Form\SearchUserType;
16 15
@@ -22,8 +21,7 @@ class ManageController extends Controller
22 /** 21 /**
23 * Creates a new User entity. 22 * Creates a new User entity.
24 * 23 *
25 * @Route("/new", name="user_new") 24 * @Route("/new", name="user_new", methods={"GET", "POST"})
26 * @Method({"GET", "POST"})
27 */ 25 */
28 public function newAction(Request $request) 26 public function newAction(Request $request)
29 { 27 {
@@ -60,19 +58,33 @@ class ManageController extends Controller
60 /** 58 /**
61 * Displays a form to edit an existing User entity. 59 * Displays a form to edit an existing User entity.
62 * 60 *
63 * @Route("/{id}/edit", name="user_edit") 61 * @Route("/{id}/edit", name="user_edit", methods={"GET", "POST"})
64 * @Method({"GET", "POST"})
65 */ 62 */
66 public function editAction(Request $request, User $user) 63 public function editAction(Request $request, User $user)
67 { 64 {
65 $userManager = $this->container->get('fos_user.user_manager');
66
68 $deleteForm = $this->createDeleteForm($user); 67 $deleteForm = $this->createDeleteForm($user);
69 $editForm = $this->createForm('Wallabag\UserBundle\Form\UserType', $user); 68 $form = $this->createForm('Wallabag\UserBundle\Form\UserType', $user);
70 $editForm->handleRequest($request); 69 $form->handleRequest($request);
71 70
72 if ($editForm->isSubmitted() && $editForm->isValid()) { 71 // `googleTwoFactor` isn't a field within the User entity, we need to define it's value in a different way
73 $em = $this->getDoctrine()->getManager(); 72 if ($this->getParameter('twofactor_auth') && true === $user->isGoogleAuthenticatorEnabled() && false === $form->isSubmitted()) {
74 $em->persist($user); 73 $form->get('googleTwoFactor')->setData(true);
75 $em->flush(); 74 }
75
76 if ($form->isSubmitted() && $form->isValid()) {
77 // handle creation / reset of the OTP secret if checkbox changed from the previous state
78 if ($this->getParameter('twofactor_auth')) {
79 if (true === $form->get('googleTwoFactor')->getData() && false === $user->isGoogleAuthenticatorEnabled()) {
80 $user->setGoogleAuthenticatorSecret($this->get('scheb_two_factor.security.google_authenticator')->generateSecret());
81 $user->setEmailTwoFactor(false);
82 } elseif (false === $form->get('googleTwoFactor')->getData() && true === $user->isGoogleAuthenticatorEnabled()) {
83 $user->setGoogleAuthenticatorSecret(null);
84 }
85 }
86
87 $userManager->updateUser($user);
76 88
77 $this->get('session')->getFlashBag()->add( 89 $this->get('session')->getFlashBag()->add(
78 'notice', 90 'notice',
@@ -84,7 +96,7 @@ class ManageController extends Controller
84 96
85 return $this->render('WallabagUserBundle:Manage:edit.html.twig', [ 97 return $this->render('WallabagUserBundle:Manage:edit.html.twig', [
86 'user' => $user, 98 'user' => $user,
87 'edit_form' => $editForm->createView(), 99 'edit_form' => $form->createView(),
88 'delete_form' => $deleteForm->createView(), 100 'delete_form' => $deleteForm->createView(),
89 'twofactor_auth' => $this->getParameter('twofactor_auth'), 101 'twofactor_auth' => $this->getParameter('twofactor_auth'),
90 ]); 102 ]);
@@ -93,8 +105,7 @@ class ManageController extends Controller
93 /** 105 /**
94 * Deletes a User entity. 106 * Deletes a User entity.
95 * 107 *
96 * @Route("/{id}", name="user_delete") 108 * @Route("/{id}", name="user_delete", methods={"DELETE"})
97 * @Method("DELETE")
98 */ 109 */
99 public function deleteAction(Request $request, User $user) 110 public function deleteAction(Request $request, User $user)
100 { 111 {
@@ -135,8 +146,6 @@ class ManageController extends Controller
135 $form->handleRequest($request); 146 $form->handleRequest($request);
136 147
137 if ($form->isSubmitted() && $form->isValid()) { 148 if ($form->isSubmitted() && $form->isValid()) {
138 $this->get('logger')->info('searching users');
139
140 $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : ''); 149 $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : '');
141 150
142 $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); 151 $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm);
@@ -161,7 +170,7 @@ class ManageController extends Controller
161 } 170 }
162 171
163 /** 172 /**
164 * Creates a form to delete a User entity. 173 * Create a form to delete a User entity.
165 * 174 *
166 * @param User $user The User entity 175 * @param User $user The User entity
167 * 176 *
diff --git a/src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php b/src/Wallabag/UserBundle/DataFixtures/UserFixtures.php
index 26dbda3b..1e375e09 100644
--- a/src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php
+++ b/src/Wallabag/UserBundle/DataFixtures/UserFixtures.php
@@ -1,13 +1,12 @@
1<?php 1<?php
2 2
3namespace Wallabag\UserBundle\DataFixtures\ORM; 3namespace Wallabag\UserBundle\DataFixtures;
4 4
5use Doctrine\Common\DataFixtures\AbstractFixture; 5use Doctrine\Bundle\FixturesBundle\Fixture;
6use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
7use Doctrine\Common\Persistence\ObjectManager; 6use Doctrine\Common\Persistence\ObjectManager;
8use Wallabag\UserBundle\Entity\User; 7use Wallabag\UserBundle\Entity\User;
9 8
10class LoadUserData extends AbstractFixture implements OrderedFixtureInterface 9class UserFixtures extends Fixture
11{ 10{
12 /** 11 /**
13 * {@inheritdoc} 12 * {@inheritdoc}
@@ -50,12 +49,4 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
50 49
51 $manager->flush(); 50 $manager->flush();
52 } 51 }
53
54 /**
55 * {@inheritdoc}
56 */
57 public function getOrder()
58 {
59 return 10;
60 }
61} 52}
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
index 48446e3c..43fa6a80 100644
--- a/src/Wallabag/UserBundle/Entity/User.php
+++ b/src/Wallabag/UserBundle/Entity/User.php
@@ -8,8 +8,9 @@ use FOS\UserBundle\Model\User as BaseUser;
8use JMS\Serializer\Annotation\Accessor; 8use JMS\Serializer\Annotation\Accessor;
9use JMS\Serializer\Annotation\Groups; 9use JMS\Serializer\Annotation\Groups;
10use JMS\Serializer\Annotation\XmlRoot; 10use JMS\Serializer\Annotation\XmlRoot;
11use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; 11use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
12use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; 12use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface as EmailTwoFactorInterface;
13use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface as GoogleTwoFactorInterface;
13use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; 14use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
14use Symfony\Component\Security\Core\User\UserInterface; 15use Symfony\Component\Security\Core\User\UserInterface;
15use Wallabag\ApiBundle\Entity\Client; 16use Wallabag\ApiBundle\Entity\Client;
@@ -28,7 +29,7 @@ use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
28 * @UniqueEntity("email") 29 * @UniqueEntity("email")
29 * @UniqueEntity("username") 30 * @UniqueEntity("username")
30 */ 31 */
31class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface 32class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorInterface, BackupCodeInterface
32{ 33{
33 use EntityTimestampsTrait; 34 use EntityTimestampsTrait;
34 35
@@ -123,16 +124,21 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
123 private $authCode; 124 private $authCode;
124 125
125 /** 126 /**
126 * @var bool 127 * @ORM\Column(name="googleAuthenticatorSecret", type="string", nullable=true)
127 *
128 * @ORM\Column(type="boolean")
129 */ 128 */
130 private $twoFactorAuthentication = false; 129 private $googleAuthenticatorSecret;
131 130
132 /** 131 /**
133 * @ORM\Column(type="json_array", nullable=true) 132 * @ORM\Column(type="json_array", nullable=true)
134 */ 133 */
135 private $trusted; 134 private $backupCodes;
135
136 /**
137 * @var bool
138 *
139 * @ORM\Column(type="boolean")
140 */
141 private $emailTwoFactor = false;
136 142
137 public function __construct() 143 public function __construct()
138 { 144 {
@@ -233,49 +239,119 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
233 /** 239 /**
234 * @return bool 240 * @return bool
235 */ 241 */
236 public function isTwoFactorAuthentication() 242 public function isEmailTwoFactor()
237 { 243 {
238 return $this->twoFactorAuthentication; 244 return $this->emailTwoFactor;
239 } 245 }
240 246
241 /** 247 /**
242 * @param bool $twoFactorAuthentication 248 * @param bool $emailTwoFactor
243 */ 249 */
244 public function setTwoFactorAuthentication($twoFactorAuthentication) 250 public function setEmailTwoFactor($emailTwoFactor)
245 { 251 {
246 $this->twoFactorAuthentication = $twoFactorAuthentication; 252 $this->emailTwoFactor = $emailTwoFactor;
247 } 253 }
248 254
249 public function isEmailAuthEnabled() 255 /**
256 * Used in the user config form to be "like" the email option.
257 */
258 public function isGoogleTwoFactor()
259 {
260 return $this->isGoogleAuthenticatorEnabled();
261 }
262
263 /**
264 * {@inheritdoc}
265 */
266 public function isEmailAuthEnabled(): bool
250 { 267 {
251 return $this->twoFactorAuthentication; 268 return $this->emailTwoFactor;
252 } 269 }
253 270
254 public function getEmailAuthCode() 271 /**
272 * {@inheritdoc}
273 */
274 public function getEmailAuthCode(): string
255 { 275 {
256 return $this->authCode; 276 return $this->authCode;
257 } 277 }
258 278
259 public function setEmailAuthCode($authCode) 279 /**
280 * {@inheritdoc}
281 */
282 public function setEmailAuthCode(string $authCode): void
260 { 283 {
261 $this->authCode = $authCode; 284 $this->authCode = $authCode;
262 } 285 }
263 286
264 public function addTrustedComputer($token, \DateTime $validUntil) 287 /**
288 * {@inheritdoc}
289 */
290 public function getEmailAuthRecipient(): string
265 { 291 {
266 $this->trusted[$token] = $validUntil->format('r'); 292 return $this->email;
267 } 293 }
268 294
269 public function isTrustedComputer($token) 295 /**
296 * {@inheritdoc}
297 */
298 public function isGoogleAuthenticatorEnabled(): bool
270 { 299 {
271 if (isset($this->trusted[$token])) { 300 return $this->googleAuthenticatorSecret ? true : false;
272 $now = new \DateTime(); 301 }
273 $validUntil = new \DateTime($this->trusted[$token]);
274 302
275 return $now < $validUntil; 303 /**
276 } 304 * {@inheritdoc}
305 */
306 public function getGoogleAuthenticatorUsername(): string
307 {
308 return $this->username;
309 }
277 310
278 return false; 311 /**
312 * {@inheritdoc}
313 */
314 public function getGoogleAuthenticatorSecret(): string
315 {
316 return $this->googleAuthenticatorSecret;
317 }
318
319 /**
320 * {@inheritdoc}
321 */
322 public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): void
323 {
324 $this->googleAuthenticatorSecret = $googleAuthenticatorSecret;
325 }
326
327 public function setBackupCodes(array $codes = null)
328 {
329 $this->backupCodes = $codes;
330 }
331
332 public function getBackupCodes()
333 {
334 return $this->backupCodes;
335 }
336
337 /**
338 * {@inheritdoc}
339 */
340 public function isBackupCode(string $code): bool
341 {
342 return false === $this->findBackupCode($code) ? false : true;
343 }
344
345 /**
346 * {@inheritdoc}
347 */
348 public function invalidateBackupCode(string $code): void
349 {
350 $key = $this->findBackupCode($code);
351
352 if (false !== $key) {
353 unset($this->backupCodes[$key]);
354 }
279 } 355 }
280 356
281 /** 357 /**
@@ -309,4 +385,24 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
309 return $this->clients->first(); 385 return $this->clients->first();
310 } 386 }
311 } 387 }
388
389 /**
390 * Try to find a backup code from the list of backup codes of the current user.
391 *
392 * @param string $code Given code from the user
393 *
394 * @return string|false
395 */
396 private function findBackupCode(string $code)
397 {
398 foreach ($this->backupCodes as $key => $backupCode) {
399 // backup code are hashed using `password_hash`
400 // see ConfigController->otpAppAction
401 if (password_verify($code, $backupCode)) {
402 return $key;
403 }
404 }
405
406 return false;
407 }
312} 408}
diff --git a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php
index e4d55c19..5cabfd35 100644
--- a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php
+++ b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php
@@ -6,6 +6,7 @@ use Doctrine\ORM\EntityManager;
6use FOS\UserBundle\Event\UserEvent; 6use FOS\UserBundle\Event\UserEvent;
7use FOS\UserBundle\FOSUserEvents; 7use FOS\UserBundle\FOSUserEvents;
8use Symfony\Component\EventDispatcher\EventSubscriberInterface; 8use Symfony\Component\EventDispatcher\EventSubscriberInterface;
9use Symfony\Component\HttpFoundation\Session\Session;
9use Wallabag\CoreBundle\Entity\Config; 10use Wallabag\CoreBundle\Entity\Config;
10 11
11/** 12/**
@@ -22,8 +23,9 @@ class CreateConfigListener implements EventSubscriberInterface
22 private $readingSpeed; 23 private $readingSpeed;
23 private $actionMarkAsRead; 24 private $actionMarkAsRead;
24 private $listMode; 25 private $listMode;
26 private $session;
25 27
26 public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language, $readingSpeed, $actionMarkAsRead, $listMode) 28 public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language, $readingSpeed, $actionMarkAsRead, $listMode, Session $session)
27 { 29 {
28 $this->em = $em; 30 $this->em = $em;
29 $this->theme = $theme; 31 $this->theme = $theme;
@@ -33,6 +35,7 @@ class CreateConfigListener implements EventSubscriberInterface
33 $this->readingSpeed = $readingSpeed; 35 $this->readingSpeed = $readingSpeed;
34 $this->actionMarkAsRead = $actionMarkAsRead; 36 $this->actionMarkAsRead = $actionMarkAsRead;
35 $this->listMode = $listMode; 37 $this->listMode = $listMode;
38 $this->session = $session;
36 } 39 }
37 40
38 public static function getSubscribedEvents() 41 public static function getSubscribedEvents()
@@ -52,7 +55,7 @@ class CreateConfigListener implements EventSubscriberInterface
52 $config->setTheme($this->theme); 55 $config->setTheme($this->theme);
53 $config->setItemsPerPage($this->itemsOnPage); 56 $config->setItemsPerPage($this->itemsOnPage);
54 $config->setRssLimit($this->rssLimit); 57 $config->setRssLimit($this->rssLimit);
55 $config->setLanguage($this->language); 58 $config->setLanguage($this->session->get('_locale', $this->language));
56 $config->setReadingSpeed($this->readingSpeed); 59 $config->setReadingSpeed($this->readingSpeed);
57 $config->setActionMarkAsRead($this->actionMarkAsRead); 60 $config->setActionMarkAsRead($this->actionMarkAsRead);
58 $config->setListMode($this->listMode); 61 $config->setListMode($this->listMode);
diff --git a/src/Wallabag/UserBundle/Form/UserType.php b/src/Wallabag/UserBundle/Form/UserType.php
index 56fea640..026db9a2 100644
--- a/src/Wallabag/UserBundle/Form/UserType.php
+++ b/src/Wallabag/UserBundle/Form/UserType.php
@@ -35,9 +35,14 @@ class UserType extends AbstractType
35 'required' => false, 35 'required' => false,
36 'label' => 'user.form.enabled_label', 36 'label' => 'user.form.enabled_label',
37 ]) 37 ])
38 ->add('twoFactorAuthentication', CheckboxType::class, [ 38 ->add('emailTwoFactor', CheckboxType::class, [
39 'required' => false, 39 'required' => false,
40 'label' => 'user.form.twofactor_label', 40 'label' => 'user.form.twofactor_email_label',
41 ])
42 ->add('googleTwoFactor', CheckboxType::class, [
43 'required' => false,
44 'label' => 'user.form.twofactor_google_label',
45 'mapped' => false,
41 ]) 46 ])
42 ->add('save', SubmitType::class, [ 47 ->add('save', SubmitType::class, [
43 'label' => 'user.form.save', 48 'label' => 'user.form.save',
diff --git a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php
index aed805c9..2797efde 100644
--- a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php
+++ b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php
@@ -78,7 +78,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface
78 * 78 *
79 * @param TwoFactorInterface $user 79 * @param TwoFactorInterface $user
80 */ 80 */
81 public function sendAuthCode(TwoFactorInterface $user) 81 public function sendAuthCode(TwoFactorInterface $user): void
82 { 82 {
83 $template = $this->twig->loadTemplate('WallabagUserBundle:TwoFactor:email_auth_code.html.twig'); 83 $template = $this->twig->loadTemplate('WallabagUserBundle:TwoFactor:email_auth_code.html.twig');
84 84
@@ -97,7 +97,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface
97 97
98 $message = new \Swift_Message(); 98 $message = new \Swift_Message();
99 $message 99 $message
100 ->setTo($user->getEmail()) 100 ->setTo($user->getEmailAuthRecipient())
101 ->setFrom($this->senderEmail, $this->senderName) 101 ->setFrom($this->senderEmail, $this->senderName)
102 ->setSubject($subject) 102 ->setSubject($subject)
103 ->setBody($bodyText, 'text/plain') 103 ->setBody($bodyText, 'text/plain')
diff --git a/src/Wallabag/UserBundle/Resources/config/services.yml b/src/Wallabag/UserBundle/Resources/config/services.yml
index d3925de3..72cda3f8 100644
--- a/src/Wallabag/UserBundle/Resources/config/services.yml
+++ b/src/Wallabag/UserBundle/Resources/config/services.yml
@@ -33,6 +33,7 @@ services:
33 - "%wallabag_core.reading_speed%" 33 - "%wallabag_core.reading_speed%"
34 - "%wallabag_core.action_mark_as_read%" 34 - "%wallabag_core.action_mark_as_read%"
35 - "%wallabag_core.list_mode%" 35 - "%wallabag_core.list_mode%"
36 - "@session"
36 tags: 37 tags:
37 - { name: kernel.event_subscriber } 38 - { name: kernel.event_subscriber }
38 39
diff --git a/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig b/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig
index c8471bdd..47a5cb78 100644
--- a/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig
@@ -1,7 +1,8 @@
1{# Override `vendor/scheb/two-factor-bundle/Resources/views/Authentication/form.html.twig` #}
1{% extends "WallabagUserBundle::layout.html.twig" %} 2{% extends "WallabagUserBundle::layout.html.twig" %}
2 3
3{% block fos_user_content %} 4{% block fos_user_content %}
4<form class="form" action="" method="post"> 5<form class="form" action="{{ path("2fa_login_check") }}" method="post">
5 <div class="card-content"> 6 <div class="card-content">
6 <div class="row"> 7 <div class="row">
7 8
@@ -9,14 +10,19 @@
9 <p class="error">{{ flashMessage|trans }}</p> 10 <p class="error">{{ flashMessage|trans }}</p>
10 {% endfor %} 11 {% endfor %}
11 12
13 {# Authentication errors #}
14 {% if authenticationError %}
15 <p class="error">{{ authenticationError|trans(authenticationErrorData) }}</p>
16 {% endif %}
17
12 <div class="input-field col s12"> 18 <div class="input-field col s12">
13 <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label> 19 <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label>
14 <input id="_auth_code" type="text" autocomplete="off" name="_auth_code" /> 20 <input id="_auth_code" type="text" autocomplete="off" name="{{ authCodeParameterName }}" />
15 </div> 21 </div>
16 22
17 {% if useTrustedOption %} 23 {% if displayTrustedOption %}
18 <div class="input-field col s12"> 24 <div class="input-field col s12">
19 <input id="_trusted" type="checkbox" name="_trusted" /> 25 <input id="_trusted" type="checkbox" name="{{ trustedParameterName }}" />
20 <label for="_trusted">{{ "scheb_two_factor.trusted"|trans }}</label> 26 <label for="_trusted">{{ "scheb_two_factor.trusted"|trans }}</label>
21 </div> 27 </div>
22 {% endif %} 28 {% endif %}
diff --git a/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig b/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig
index 3ffd15f5..2de8f3a5 100644
--- a/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig
@@ -50,9 +50,14 @@
50 {% if twofactor_auth %} 50 {% if twofactor_auth %}
51 <div class="row"> 51 <div class="row">
52 <div class="input-field col s12"> 52 <div class="input-field col s12">
53 {{ form_widget(edit_form.twoFactorAuthentication) }} 53 {{ form_widget(edit_form.emailTwoFactor) }}
54 {{ form_label(edit_form.twoFactorAuthentication) }} 54 {{ form_label(edit_form.emailTwoFactor) }}
55 {{ form_errors(edit_form.twoFactorAuthentication) }} 55 {{ form_errors(edit_form.emailTwoFactor) }}
56 </div>
57 <div class="input-field col s12">
58 {{ form_widget(edit_form.googleTwoFactor) }}
59 {{ form_label(edit_form.googleTwoFactor) }}
60 {{ form_errors(edit_form.googleTwoFactor) }}
56 </div> 61 </div>
57 </div> 62 </div>
58 {% endif %} 63 {% endif %}
diff --git a/src/Wallabag/UserBundle/Resources/views/Registration/register_content.html.twig b/src/Wallabag/UserBundle/Resources/views/Registration/register_content.html.twig
index d0a85fc7..85cd4f0d 100644
--- a/src/Wallabag/UserBundle/Resources/views/Registration/register_content.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Registration/register_content.html.twig
@@ -3,7 +3,6 @@
3{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'), 'attr': {'class': 'fos_user_registration_register'}}) }} 3{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'), 'attr': {'class': 'fos_user_registration_register'}}) }}
4 <div class="card-content"> 4 <div class="card-content">
5 <div class="row"> 5 <div class="row">
6
7 {{ form_widget(form._token) }} 6 {{ form_widget(form._token) }}
8 7
9 {% for flashMessage in app.session.flashbag.get('notice') %} 8 {% for flashMessage in app.session.flashbag.get('notice') %}
diff --git a/src/Wallabag/UserBundle/Resources/views/layout.html.twig b/src/Wallabag/UserBundle/Resources/views/layout.html.twig
index f97e9870..a47b31d0 100644
--- a/src/Wallabag/UserBundle/Resources/views/layout.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/layout.html.twig
@@ -15,6 +15,11 @@
15 {% block fos_user_content %} 15 {% block fos_user_content %}
16 {% endblock fos_user_content %} 16 {% endblock fos_user_content %}
17 </div> 17 </div>
18 <div class="center">
19 <a href="{{ path('changeLocale', {'language': 'de'}) }}">Deutsch</a> –
20 <a href="{{ path('changeLocale', {'language': 'en'}) }}">English</a> –
21 <a href="{{ path('changeLocale', {'language': 'fr'}) }}">Français</a>
22 </div>
18 </div> 23 </div>
19</main> 24</main>
20{% endblock %} 25{% endblock %}