diff options
Diffstat (limited to 'src')
174 files changed, 4481 insertions, 1943 deletions
diff --git a/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php b/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php index 3a7421c7..883ce4a8 100644 --- a/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php +++ b/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php | |||
@@ -16,8 +16,6 @@ class WallabagAnnotationController extends FOSRestController | |||
16 | /** | 16 | /** |
17 | * Retrieve annotations for an entry. | 17 | * Retrieve annotations for an entry. |
18 | * | 18 | * |
19 | * @param Entry $entry | ||
20 | * | ||
21 | * @see Wallabag\ApiBundle\Controller\WallabagRestController | 19 | * @see Wallabag\ApiBundle\Controller\WallabagRestController |
22 | * | 20 | * |
23 | * @return JsonResponse | 21 | * @return JsonResponse |
@@ -39,9 +37,6 @@ class WallabagAnnotationController extends FOSRestController | |||
39 | /** | 37 | /** |
40 | * Creates a new annotation. | 38 | * Creates a new annotation. |
41 | * | 39 | * |
42 | * @param Request $request | ||
43 | * @param Entry $entry | ||
44 | * | ||
45 | * @return JsonResponse | 40 | * @return JsonResponse |
46 | * | 41 | * |
47 | * @see Wallabag\ApiBundle\Controller\WallabagRestController | 42 | * @see Wallabag\ApiBundle\Controller\WallabagRestController |
@@ -79,9 +74,6 @@ class WallabagAnnotationController extends FOSRestController | |||
79 | * | 74 | * |
80 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") | 75 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") |
81 | * | 76 | * |
82 | * @param Annotation $annotation | ||
83 | * @param Request $request | ||
84 | * | ||
85 | * @return JsonResponse | 77 | * @return JsonResponse |
86 | */ | 78 | */ |
87 | public function putAnnotationAction(Annotation $annotation, Request $request) | 79 | public function putAnnotationAction(Annotation $annotation, Request $request) |
@@ -114,8 +106,6 @@ class WallabagAnnotationController extends FOSRestController | |||
114 | * | 106 | * |
115 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") | 107 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") |
116 | * | 108 | * |
117 | * @param Annotation $annotation | ||
118 | * | ||
119 | * @return JsonResponse | 109 | * @return JsonResponse |
120 | */ | 110 | */ |
121 | public function deleteAnnotationAction(Annotation $annotation) | 111 | public function deleteAnnotationAction(Annotation $annotation) |
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 | ||
3 | namespace Wallabag\AnnotationBundle\DataFixtures\ORM; | 3 | namespace Wallabag\AnnotationBundle\DataFixtures; |
4 | 4 | ||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | 5 | use Doctrine\Bundle\FixturesBundle\Fixture; |
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | 6 | use Doctrine\Common\DataFixtures\DependentFixtureInterface; |
7 | use Doctrine\Common\Persistence\ObjectManager; | 7 | use Doctrine\Common\Persistence\ObjectManager; |
8 | use Wallabag\AnnotationBundle\Entity\Annotation; | 8 | use Wallabag\AnnotationBundle\Entity\Annotation; |
9 | use Wallabag\CoreBundle\DataFixtures\EntryFixtures; | ||
10 | use Wallabag\UserBundle\DataFixtures\UserFixtures; | ||
9 | 11 | ||
10 | class LoadAnnotationData extends AbstractFixture implements OrderedFixtureInterface | 12 | class 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/AnnotationBundle/Form/NewAnnotationType.php b/src/Wallabag/AnnotationBundle/Form/NewAnnotationType.php index c73c3ded..48bc2c59 100644 --- a/src/Wallabag/AnnotationBundle/Form/NewAnnotationType.php +++ b/src/Wallabag/AnnotationBundle/Form/NewAnnotationType.php | |||
@@ -17,7 +17,8 @@ class NewAnnotationType extends AbstractType | |||
17 | 'empty_data' => '', | 17 | 'empty_data' => '', |
18 | ]) | 18 | ]) |
19 | ->add('quote', null, [ | 19 | ->add('quote', null, [ |
20 | 'empty_data' => null, | 20 | 'empty_data' => '', |
21 | 'trim' => false, | ||
21 | ]) | 22 | ]) |
22 | ->add('ranges', CollectionType::class, [ | 23 | ->add('ranges', CollectionType::class, [ |
23 | 'entry_type' => RangeType::class, | 24 | 'entry_type' => RangeType::class, |
diff --git a/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php b/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php index 28d55ba9..66693189 100644 --- a/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php +++ b/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php | |||
@@ -20,8 +20,6 @@ class AnnotationRestController extends WallabagRestController | |||
20 | * } | 20 | * } |
21 | * ) | 21 | * ) |
22 | * | 22 | * |
23 | * @param Entry $entry | ||
24 | * | ||
25 | * @return JsonResponse | 23 | * @return JsonResponse |
26 | */ | 24 | */ |
27 | public function getAnnotationsAction(Entry $entry) | 25 | public function getAnnotationsAction(Entry $entry) |
@@ -39,14 +37,11 @@ class AnnotationRestController extends WallabagRestController | |||
39 | * @ApiDoc( | 37 | * @ApiDoc( |
40 | * requirements={ | 38 | * requirements={ |
41 | * {"name"="ranges", "dataType"="array", "requirement"="\w+", "description"="The range array for the annotation"}, | 39 | * {"name"="ranges", "dataType"="array", "requirement"="\w+", "description"="The range array for the annotation"}, |
42 | * {"name"="quote", "dataType"="string", "required"=false, "description"="Optional, quote for the annotation"}, | 40 | * {"name"="quote", "dataType"="string", "description"="The annotated text"}, |
43 | * {"name"="text", "dataType"="string", "required"=true, "description"=""}, | 41 | * {"name"="text", "dataType"="string", "required"=true, "description"="Content of annotation"}, |
44 | * } | 42 | * } |
45 | * ) | 43 | * ) |
46 | * | 44 | * |
47 | * @param Request $request | ||
48 | * @param Entry $entry | ||
49 | * | ||
50 | * @return JsonResponse | 45 | * @return JsonResponse |
51 | */ | 46 | */ |
52 | public function postAnnotationAction(Request $request, Entry $entry) | 47 | public function postAnnotationAction(Request $request, Entry $entry) |
@@ -70,9 +65,6 @@ class AnnotationRestController extends WallabagRestController | |||
70 | * | 65 | * |
71 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") | 66 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") |
72 | * | 67 | * |
73 | * @param Annotation $annotation | ||
74 | * @param Request $request | ||
75 | * | ||
76 | * @return JsonResponse | 68 | * @return JsonResponse |
77 | */ | 69 | */ |
78 | public function putAnnotationAction(Annotation $annotation, Request $request) | 70 | public function putAnnotationAction(Annotation $annotation, Request $request) |
@@ -96,8 +88,6 @@ class AnnotationRestController extends WallabagRestController | |||
96 | * | 88 | * |
97 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") | 89 | * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") |
98 | * | 90 | * |
99 | * @param Annotation $annotation | ||
100 | * | ||
101 | * @return JsonResponse | 91 | * @return JsonResponse |
102 | */ | 92 | */ |
103 | public function deleteAnnotationAction(Annotation $annotation) | 93 | public function deleteAnnotationAction(Annotation $annotation) |
diff --git a/src/Wallabag/ApiBundle/Controller/DeveloperController.php b/src/Wallabag/ApiBundle/Controller/DeveloperController.php index c7178017..3224d789 100644 --- a/src/Wallabag/ApiBundle/Controller/DeveloperController.php +++ b/src/Wallabag/ApiBundle/Controller/DeveloperController.php | |||
@@ -2,9 +2,9 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ApiBundle\Controller; | 3 | namespace Wallabag\ApiBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
7 | use Symfony\Component\Routing\Annotation\Route; | ||
8 | use Wallabag\ApiBundle\Entity\Client; | 8 | use Wallabag\ApiBundle\Entity\Client; |
9 | use Wallabag\ApiBundle\Form\Type\ClientType; | 9 | use Wallabag\ApiBundle\Form\Type\ClientType; |
10 | 10 | ||
@@ -29,8 +29,6 @@ class DeveloperController extends Controller | |||
29 | /** | 29 | /** |
30 | * Create a client (an app). | 30 | * Create a client (an app). |
31 | * | 31 | * |
32 | * @param Request $request | ||
33 | * | ||
34 | * @Route("/developer/client/create", name="developer_create_client") | 32 | * @Route("/developer/client/create", name="developer_create_client") |
35 | * | 33 | * |
36 | * @return \Symfony\Component\HttpFoundation\Response | 34 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -67,8 +65,6 @@ class DeveloperController extends Controller | |||
67 | /** | 65 | /** |
68 | * Remove a client. | 66 | * Remove a client. |
69 | * | 67 | * |
70 | * @param Client $client | ||
71 | * | ||
72 | * @Route("/developer/client/delete/{id}", requirements={"id" = "\d+"}, name="developer_delete_client") | 68 | * @Route("/developer/client/delete/{id}", requirements={"id" = "\d+"}, name="developer_delete_client") |
73 | * | 69 | * |
74 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 70 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php index 0b4e74a0..c09fdaeb 100644 --- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php | |||
@@ -4,17 +4,17 @@ namespace Wallabag\ApiBundle\Controller; | |||
4 | 4 | ||
5 | use Hateoas\Configuration\Route; | 5 | use Hateoas\Configuration\Route; |
6 | use Hateoas\Representation\Factory\PagerfantaFactory; | 6 | use Hateoas\Representation\Factory\PagerfantaFactory; |
7 | use JMS\Serializer\SerializationContext; | ||
8 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | 7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
9 | use Symfony\Component\HttpFoundation\JsonResponse; | 8 | use Symfony\Component\HttpFoundation\JsonResponse; |
10 | use Symfony\Component\HttpFoundation\Request; | 9 | use Symfony\Component\HttpFoundation\Request; |
11 | use Symfony\Component\HttpFoundation\Response; | 10 | use Symfony\Component\HttpFoundation\Response; |
11 | use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; | ||
12 | use Symfony\Component\HttpKernel\Exception\HttpException; | 12 | use Symfony\Component\HttpKernel\Exception\HttpException; |
13 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | ||
14 | use Wallabag\CoreBundle\Entity\Entry; | 13 | use Wallabag\CoreBundle\Entity\Entry; |
15 | use Wallabag\CoreBundle\Entity\Tag; | 14 | use Wallabag\CoreBundle\Entity\Tag; |
16 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; | 15 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; |
17 | use Wallabag\CoreBundle\Event\EntrySavedEvent; | 16 | use Wallabag\CoreBundle\Event\EntrySavedEvent; |
17 | use Wallabag\CoreBundle\Helper\UrlHasher; | ||
18 | 18 | ||
19 | class EntryRestController extends WallabagRestController | 19 | class EntryRestController extends WallabagRestController |
20 | { | 20 | { |
@@ -28,8 +28,10 @@ class EntryRestController extends WallabagRestController | |||
28 | * @ApiDoc( | 28 | * @ApiDoc( |
29 | * parameters={ | 29 | * parameters={ |
30 | * {"name"="return_id", "dataType"="string", "required"=false, "format"="1 or 0", "description"="Set 1 if you want to retrieve ID in case entry(ies) exists, 0 by default"}, | 30 | * {"name"="return_id", "dataType"="string", "required"=false, "format"="1 or 0", "description"="Set 1 if you want to retrieve ID in case entry(ies) exists, 0 by default"}, |
31 | * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}, | 31 | * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="DEPRECATED, use hashed_url instead"}, |
32 | * {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="Urls (as an array) to check if it exists"} | 32 | * {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="DEPRECATED, use hashed_urls instead"}, |
33 | * {"name"="hashed_url", "dataType"="string", "required"=false, "format"="A hashed url", "description"="Hashed url using SHA1 to check if it exists"}, | ||
34 | * {"name"="hashed_urls", "dataType"="string", "required"=false, "format"="An array of hashed urls (?hashed_urls[]=xxx...&hashed_urls[]=xxx...)", "description"="An array of hashed urls using SHA1 to check if they exist"} | ||
33 | * } | 35 | * } |
34 | * ) | 36 | * ) |
35 | * | 37 | * |
@@ -38,38 +40,49 @@ class EntryRestController extends WallabagRestController | |||
38 | public function getEntriesExistsAction(Request $request) | 40 | public function getEntriesExistsAction(Request $request) |
39 | { | 41 | { |
40 | $this->validateAuthentication(); | 42 | $this->validateAuthentication(); |
43 | $repo = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry'); | ||
41 | 44 | ||
42 | $returnId = (null === $request->query->get('return_id')) ? false : (bool) $request->query->get('return_id'); | 45 | $returnId = (null === $request->query->get('return_id')) ? false : (bool) $request->query->get('return_id'); |
43 | $urls = $request->query->get('urls', []); | ||
44 | |||
45 | // handle multiple urls first | ||
46 | if (!empty($urls)) { | ||
47 | $results = []; | ||
48 | foreach ($urls as $url) { | ||
49 | $res = $this->getDoctrine() | ||
50 | ->getRepository('WallabagCoreBundle:Entry') | ||
51 | ->findByUrlAndUserId($url, $this->getUser()->getId()); | ||
52 | 46 | ||
53 | $results[$url] = $this->returnExistInformation($res, $returnId); | 47 | $hashedUrls = $request->query->get('hashed_urls', []); |
54 | } | 48 | $hashedUrl = $request->query->get('hashed_url', ''); |
55 | 49 | if (!empty($hashedUrl)) { | |
56 | return $this->sendResponse($results); | 50 | $hashedUrls[] = $hashedUrl; |
57 | } | 51 | } |
58 | 52 | ||
59 | // let's see if it is a simple url? | 53 | $urls = $request->query->get('urls', []); |
60 | $url = $request->query->get('url', ''); | 54 | $url = $request->query->get('url', ''); |
55 | if (!empty($url)) { | ||
56 | $urls[] = $url; | ||
57 | } | ||
58 | |||
59 | $urlHashMap = []; | ||
60 | foreach ($urls as $urlToHash) { | ||
61 | $urlHash = UrlHasher::hashUrl($urlToHash); | ||
62 | $hashedUrls[] = $urlHash; | ||
63 | $urlHashMap[$urlHash] = $urlToHash; | ||
64 | } | ||
61 | 65 | ||
62 | if (empty($url)) { | 66 | if (empty($hashedUrls)) { |
63 | throw $this->createAccessDeniedException('URL is empty?, logged user id: ' . $this->getUser()->getId()); | 67 | throw $this->createAccessDeniedException('URL is empty?, logged user id: ' . $this->getUser()->getId()); |
64 | } | 68 | } |
65 | 69 | ||
66 | $res = $this->getDoctrine() | 70 | $results = []; |
67 | ->getRepository('WallabagCoreBundle:Entry') | 71 | foreach ($hashedUrls as $hashedUrlToSearch) { |
68 | ->findByUrlAndUserId($url, $this->getUser()->getId()); | 72 | $res = $repo->findByHashedUrlAndUserId($hashedUrlToSearch, $this->getUser()->getId()); |
73 | |||
74 | $results[$hashedUrlToSearch] = $this->returnExistInformation($res, $returnId); | ||
75 | } | ||
76 | |||
77 | $results = $this->replaceUrlHashes($results, $urlHashMap); | ||
69 | 78 | ||
70 | $exists = $this->returnExistInformation($res, $returnId); | 79 | if (!empty($url) || !empty($hashedUrl)) { |
80 | $hu = array_keys($results)[0]; | ||
71 | 81 | ||
72 | return $this->sendResponse(['exists' => $exists]); | 82 | return $this->sendResponse(['exists' => $results[$hu]]); |
83 | } | ||
84 | |||
85 | return $this->sendResponse($results); | ||
73 | } | 86 | } |
74 | 87 | ||
75 | /** | 88 | /** |
@@ -79,13 +92,14 @@ class EntryRestController extends WallabagRestController | |||
79 | * parameters={ | 92 | * parameters={ |
80 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."}, | 93 | * {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."}, |
81 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."}, | 94 | * {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."}, |
82 | * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."}, | 95 | * {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated' or 'archived', default 'created'", "description"="sort entries by date."}, |
83 | * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."}, | 96 | * {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."}, |
84 | * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."}, | 97 | * {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."}, |
85 | * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}, | 98 | * {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}, |
86 | * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."}, | 99 | * {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."}, |
87 | * {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."}, | 100 | * {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."}, |
88 | * {"name"="public", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by entries with a public link"}, | 101 | * {"name"="public", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by entries with a public link"}, |
102 | * {"name"="detail", "dataType"="string", "required"=false, "format"="metadata or full, metadata by default", "description"="include content field if 'full'. 'full' by default for backward compatibility."}, | ||
89 | * } | 103 | * } |
90 | * ) | 104 | * ) |
91 | * | 105 | * |
@@ -98,24 +112,30 @@ class EntryRestController extends WallabagRestController | |||
98 | $isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive'); | 112 | $isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive'); |
99 | $isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred'); | 113 | $isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred'); |
100 | $isPublic = (null === $request->query->get('public')) ? null : (bool) $request->query->get('public'); | 114 | $isPublic = (null === $request->query->get('public')) ? null : (bool) $request->query->get('public'); |
101 | $sort = $request->query->get('sort', 'created'); | 115 | $sort = strtolower($request->query->get('sort', 'created')); |
102 | $order = $request->query->get('order', 'desc'); | 116 | $order = strtolower($request->query->get('order', 'desc')); |
103 | $page = (int) $request->query->get('page', 1); | 117 | $page = (int) $request->query->get('page', 1); |
104 | $perPage = (int) $request->query->get('perPage', 30); | 118 | $perPage = (int) $request->query->get('perPage', 30); |
105 | $tags = \is_array($request->query->get('tags')) ? '' : (string) $request->query->get('tags', ''); | 119 | $tags = \is_array($request->query->get('tags')) ? '' : (string) $request->query->get('tags', ''); |
106 | $since = $request->query->get('since', 0); | 120 | $since = $request->query->get('since', 0); |
121 | $detail = strtolower($request->query->get('detail', 'full')); | ||
107 | 122 | ||
108 | /** @var \Pagerfanta\Pagerfanta $pager */ | 123 | try { |
109 | $pager = $this->get('wallabag_core.entry_repository')->findEntries( | 124 | /** @var \Pagerfanta\Pagerfanta $pager */ |
110 | $this->getUser()->getId(), | 125 | $pager = $this->get('wallabag_core.entry_repository')->findEntries( |
111 | $isArchived, | 126 | $this->getUser()->getId(), |
112 | $isStarred, | 127 | $isArchived, |
113 | $isPublic, | 128 | $isStarred, |
114 | $sort, | 129 | $isPublic, |
115 | $order, | 130 | $sort, |
116 | $since, | 131 | $order, |
117 | $tags | 132 | $since, |
118 | ); | 133 | $tags, |
134 | $detail | ||
135 | ); | ||
136 | } catch (\Exception $e) { | ||
137 | throw new BadRequestHttpException($e->getMessage()); | ||
138 | } | ||
119 | 139 | ||
120 | $pager->setMaxPerPage($perPage); | 140 | $pager->setMaxPerPage($perPage); |
121 | $pager->setCurrentPage($page); | 141 | $pager->setCurrentPage($page); |
@@ -135,8 +155,9 @@ class EntryRestController extends WallabagRestController | |||
135 | 'perPage' => $perPage, | 155 | 'perPage' => $perPage, |
136 | 'tags' => $tags, | 156 | 'tags' => $tags, |
137 | 'since' => $since, | 157 | 'since' => $since, |
158 | 'detail' => $detail, | ||
138 | ], | 159 | ], |
139 | UrlGeneratorInterface::ABSOLUTE_URL | 160 | true |
140 | ) | 161 | ) |
141 | ); | 162 | ); |
142 | 163 | ||
@@ -344,9 +365,7 @@ class EntryRestController extends WallabagRestController | |||
344 | 'language' => !empty($data['language']) ? $data['language'] : $entry->getLanguage(), | 365 | 'language' => !empty($data['language']) ? $data['language'] : $entry->getLanguage(), |
345 | 'date' => !empty($data['publishedAt']) ? $data['publishedAt'] : $entry->getPublishedAt(), | 366 | 'date' => !empty($data['publishedAt']) ? $data['publishedAt'] : $entry->getPublishedAt(), |
346 | // faking the open graph preview picture | 367 | // faking the open graph preview picture |
347 | 'open_graph' => [ | 368 | 'image' => !empty($data['picture']) ? $data['picture'] : $entry->getPreviewPicture(), |
348 | 'og_image' => !empty($data['picture']) ? $data['picture'] : $entry->getPreviewPicture(), | ||
349 | ], | ||
350 | 'authors' => \is_string($data['authors']) ? explode(',', $data['authors']) : $entry->getPublishedBy(), | 369 | 'authors' => \is_string($data['authors']) ? explode(',', $data['authors']) : $entry->getPublishedBy(), |
351 | ] | 370 | ] |
352 | ); | 371 | ); |
@@ -358,7 +377,7 @@ class EntryRestController extends WallabagRestController | |||
358 | } | 377 | } |
359 | 378 | ||
360 | if (null !== $data['isArchived']) { | 379 | if (null !== $data['isArchived']) { |
361 | $entry->setArchived((bool) $data['isArchived']); | 380 | $entry->updateArchived((bool) $data['isArchived']); |
362 | } | 381 | } |
363 | 382 | ||
364 | if (null !== $data['isStarred']) { | 383 | if (null !== $data['isStarred']) { |
@@ -474,7 +493,7 @@ class EntryRestController extends WallabagRestController | |||
474 | } | 493 | } |
475 | 494 | ||
476 | if (null !== $data['isArchived']) { | 495 | if (null !== $data['isArchived']) { |
477 | $entry->setArchived((bool) $data['isArchived']); | 496 | $entry->updateArchived((bool) $data['isArchived']); |
478 | } | 497 | } |
479 | 498 | ||
480 | if (null !== $data['isStarred']) { | 499 | if (null !== $data['isStarred']) { |
@@ -545,7 +564,7 @@ class EntryRestController extends WallabagRestController | |||
545 | } | 564 | } |
546 | 565 | ||
547 | // if refreshing entry failed, don't save it | 566 | // if refreshing entry failed, don't save it |
548 | if ($this->getParameter('wallabag_core.fetching_error_message') === $entry->getContent()) { | 567 | if ($this->container->getParameter('wallabag_core.fetching_error_message') === $entry->getContent()) { |
549 | return new JsonResponse([], 304); | 568 | return new JsonResponse([], 304); |
550 | } | 569 | } |
551 | 570 | ||
@@ -565,18 +584,31 @@ class EntryRestController extends WallabagRestController | |||
565 | * @ApiDoc( | 584 | * @ApiDoc( |
566 | * requirements={ | 585 | * requirements={ |
567 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} | 586 | * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} |
587 | * }, | ||
588 | * parameters={ | ||
589 | * {"name"="expect", "dataType"="string", "required"=false, "format"="id or entry", "description"="Only returns the id instead of the deleted entry's full entity if 'id' is specified. Default to entry"}, | ||
568 | * } | 590 | * } |
569 | * ) | 591 | * ) |
570 | * | 592 | * |
571 | * @return JsonResponse | 593 | * @return JsonResponse |
572 | */ | 594 | */ |
573 | public function deleteEntriesAction(Entry $entry) | 595 | public function deleteEntriesAction(Entry $entry, Request $request) |
574 | { | 596 | { |
597 | $expect = $request->query->get('expect', 'entry'); | ||
598 | if (!\in_array($expect, ['id', 'entry'], true)) { | ||
599 | throw new BadRequestHttpException(sprintf("expect: 'id' or 'entry' expected, %s given", $expect)); | ||
600 | } | ||
575 | $this->validateAuthentication(); | 601 | $this->validateAuthentication(); |
576 | $this->validateUserAccess($entry->getUser()->getId()); | 602 | $this->validateUserAccess($entry->getUser()->getId()); |
577 | 603 | ||
578 | // We copy $entry to keep id in returned object | 604 | $response = $this->sendResponse([ |
579 | $e = $entry; | 605 | 'id' => $entry->getId(), |
606 | ]); | ||
607 | // We clone $entry to keep id in returned object | ||
608 | if ('entry' === $expect) { | ||
609 | $e = clone $entry; | ||
610 | $response = $this->sendResponse($e); | ||
611 | } | ||
580 | 612 | ||
581 | $em = $this->getDoctrine()->getManager(); | 613 | $em = $this->getDoctrine()->getManager(); |
582 | $em->remove($entry); | 614 | $em->remove($entry); |
@@ -585,7 +617,7 @@ class EntryRestController extends WallabagRestController | |||
585 | // entry deleted, dispatch event about it! | 617 | // entry deleted, dispatch event about it! |
586 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); | 618 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); |
587 | 619 | ||
588 | return $this->sendResponse($e); | 620 | return $response; |
589 | } | 621 | } |
590 | 622 | ||
591 | /** | 623 | /** |
@@ -769,29 +801,27 @@ class EntryRestController extends WallabagRestController | |||
769 | } | 801 | } |
770 | 802 | ||
771 | /** | 803 | /** |
772 | * Shortcut to send data serialized in json. | 804 | * Replace the hashedUrl keys in $results with the unhashed URL from the |
773 | * | 805 | * request, as recorded in $urlHashMap. |
774 | * @param mixed $data | ||
775 | * | ||
776 | * @return JsonResponse | ||
777 | */ | 806 | */ |
778 | private function sendResponse($data) | 807 | private function replaceUrlHashes(array $results, array $urlHashMap) |
779 | { | 808 | { |
780 | // https://github.com/schmittjoh/JMSSerializerBundle/issues/293 | 809 | $newResults = []; |
781 | $context = new SerializationContext(); | 810 | foreach ($results as $hash => $res) { |
782 | $context->setSerializeNull(true); | 811 | if (isset($urlHashMap[$hash])) { |
783 | 812 | $newResults[$urlHashMap[$hash]] = $res; | |
784 | $json = $this->get('jms_serializer')->serialize($data, 'json', $context); | 813 | } else { |
814 | $newResults[$hash] = $res; | ||
815 | } | ||
816 | } | ||
785 | 817 | ||
786 | return (new JsonResponse())->setJson($json); | 818 | return $newResults; |
787 | } | 819 | } |
788 | 820 | ||
789 | /** | 821 | /** |
790 | * Retrieve value from the request. | 822 | * Retrieve value from the request. |
791 | * Used for POST & PATCH on a an entry. | 823 | * Used for POST & PATCH on a an entry. |
792 | * | 824 | * |
793 | * @param Request $request | ||
794 | * | ||
795 | * @return array | 825 | * @return array |
796 | */ | 826 | */ |
797 | private function retrieveValueFromRequest(Request $request) | 827 | private function retrieveValueFromRequest(Request $request) |
@@ -814,8 +844,8 @@ class EntryRestController extends WallabagRestController | |||
814 | /** | 844 | /** |
815 | * Return information about the entry if it exist and depending on the id or not. | 845 | * Return information about the entry if it exist and depending on the id or not. |
816 | * | 846 | * |
817 | * @param Entry|null $entry | 847 | * @param Entry|bool|null $entry |
818 | * @param bool $returnId | 848 | * @param bool $returnId |
819 | * | 849 | * |
820 | * @return bool|int | 850 | * @return bool|int |
821 | */ | 851 | */ |
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 | |||
3 | namespace Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use Hateoas\Configuration\Route; | ||
6 | use Hateoas\Representation\Factory\PagerfantaFactory; | ||
7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | ||
8 | use Pagerfanta\Adapter\DoctrineORMAdapter; | ||
9 | use Pagerfanta\Pagerfanta; | ||
10 | use Symfony\Component\HttpFoundation\JsonResponse; | ||
11 | use Symfony\Component\HttpFoundation\Request; | ||
12 | |||
13 | class 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/TagRestController.php b/src/Wallabag/ApiBundle/Controller/TagRestController.php index c6d6df6a..f3498f55 100644 --- a/src/Wallabag/ApiBundle/Controller/TagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/TagRestController.php | |||
@@ -46,12 +46,14 @@ class TagRestController extends WallabagRestController | |||
46 | $this->validateAuthentication(); | 46 | $this->validateAuthentication(); |
47 | $label = $request->get('tag', ''); | 47 | $label = $request->get('tag', ''); |
48 | 48 | ||
49 | $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label); | 49 | $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser([$label], $this->getUser()->getId()); |
50 | 50 | ||
51 | if (empty($tag)) { | 51 | if (empty($tags)) { |
52 | throw $this->createNotFoundException('Tag not found'); | 52 | throw $this->createNotFoundException('Tag not found'); |
53 | } | 53 | } |
54 | 54 | ||
55 | $tag = $tags[0]; | ||
56 | |||
55 | $this->getDoctrine() | 57 | $this->getDoctrine() |
56 | ->getRepository('WallabagCoreBundle:Entry') | 58 | ->getRepository('WallabagCoreBundle:Entry') |
57 | ->removeTag($this->getUser()->getId(), $tag); | 59 | ->removeTag($this->getUser()->getId(), $tag); |
@@ -80,15 +82,7 @@ class TagRestController extends WallabagRestController | |||
80 | 82 | ||
81 | $tagsLabels = $request->get('tags', ''); | 83 | $tagsLabels = $request->get('tags', ''); |
82 | 84 | ||
83 | $tags = []; | 85 | $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser(explode(',', $tagsLabels), $this->getUser()->getId()); |
84 | |||
85 | foreach (explode(',', $tagsLabels) as $tagLabel) { | ||
86 | $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel); | ||
87 | |||
88 | if (!empty($tagEntity)) { | ||
89 | $tags[] = $tagEntity; | ||
90 | } | ||
91 | } | ||
92 | 86 | ||
93 | if (empty($tags)) { | 87 | if (empty($tags)) { |
94 | throw $this->createNotFoundException('Tags not found'); | 88 | throw $this->createNotFoundException('Tags not found'); |
@@ -120,6 +114,12 @@ class TagRestController extends WallabagRestController | |||
120 | { | 114 | { |
121 | $this->validateAuthentication(); | 115 | $this->validateAuthentication(); |
122 | 116 | ||
117 | $tagFromDb = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser([$tag->getLabel()], $this->getUser()->getId()); | ||
118 | |||
119 | if (empty($tagFromDb)) { | ||
120 | throw $this->createNotFoundException('Tag not found'); | ||
121 | } | ||
122 | |||
123 | $this->getDoctrine() | 123 | $this->getDoctrine() |
124 | ->getRepository('WallabagCoreBundle:Entry') | 124 | ->getRepository('WallabagCoreBundle:Entry') |
125 | ->removeTag($this->getUser()->getId(), $tag); | 125 | ->removeTag($this->getUser()->getId(), $tag); |
diff --git a/src/Wallabag/ApiBundle/Controller/TaggingRuleRestController.php b/src/Wallabag/ApiBundle/Controller/TaggingRuleRestController.php new file mode 100644 index 00000000..2496298a --- /dev/null +++ b/src/Wallabag/ApiBundle/Controller/TaggingRuleRestController.php | |||
@@ -0,0 +1,39 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Controller; | ||
4 | |||
5 | use JMS\Serializer\SerializationContext; | ||
6 | use JMS\Serializer\SerializerBuilder; | ||
7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | ||
8 | use Symfony\Component\HttpFoundation\Response; | ||
9 | |||
10 | class TaggingRuleRestController extends WallabagRestController | ||
11 | { | ||
12 | /** | ||
13 | * Export all tagging rules as a json file. | ||
14 | * | ||
15 | * @ApiDoc() | ||
16 | * | ||
17 | * @return Response | ||
18 | */ | ||
19 | public function getTaggingruleExportAction() | ||
20 | { | ||
21 | $this->validateAuthentication(); | ||
22 | |||
23 | $data = SerializerBuilder::create()->build()->serialize( | ||
24 | $this->getUser()->getConfig()->getTaggingRules(), | ||
25 | 'json', | ||
26 | SerializationContext::create()->setGroups(['export_tagging_rule']) | ||
27 | ); | ||
28 | |||
29 | return Response::create( | ||
30 | $data, | ||
31 | 200, | ||
32 | [ | ||
33 | 'Content-type' => 'application/json', | ||
34 | 'Content-Disposition' => 'attachment; filename="tagging_rules_' . $this->getUser()->getUsername() . '.json"', | ||
35 | 'Content-Transfer-Encoding' => 'UTF-8', | ||
36 | ] | ||
37 | ); | ||
38 | } | ||
39 | } | ||
diff --git a/src/Wallabag/ApiBundle/Controller/UserRestController.php b/src/Wallabag/ApiBundle/Controller/UserRestController.php index 3a4dafcd..922ab7bb 100644 --- a/src/Wallabag/ApiBundle/Controller/UserRestController.php +++ b/src/Wallabag/ApiBundle/Controller/UserRestController.php | |||
@@ -45,7 +45,7 @@ class UserRestController extends WallabagRestController | |||
45 | */ | 45 | */ |
46 | public function putUserAction(Request $request) | 46 | public function putUserAction(Request $request) |
47 | { | 47 | { |
48 | if (!$this->getParameter('fosuser_registration') || !$this->get('craue_config')->get('api_user_registration')) { | 48 | if (!$this->container->getParameter('fosuser_registration') || !$this->get('craue_config')->get('api_user_registration')) { |
49 | $json = $this->get('jms_serializer')->serialize(['error' => "Server doesn't allow registrations"], 'json'); | 49 | $json = $this->get('jms_serializer')->serialize(['error' => "Server doesn't allow registrations"], 'json'); |
50 | 50 | ||
51 | return (new JsonResponse()) | 51 | return (new JsonResponse()) |
@@ -119,7 +119,6 @@ class UserRestController extends WallabagRestController | |||
119 | /** | 119 | /** |
120 | * Send user response. | 120 | * Send user response. |
121 | * | 121 | * |
122 | * @param User $user | ||
123 | * @param string $group Used to define with serialized group might be used | 122 | * @param string $group Used to define with serialized group might be used |
124 | * @param int $status HTTP Status code to send | 123 | * @param int $status HTTP Status code to send |
125 | * | 124 | * |
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 7d8cfbba..44fd9683 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php | |||
@@ -2,18 +2,21 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ApiBundle\Controller; | 3 | namespace Wallabag\ApiBundle\Controller; |
4 | 4 | ||
5 | use FOS\RestBundle\Controller\FOSRestController; | 5 | use FOS\RestBundle\Controller\AbstractFOSRestController; |
6 | use JMS\Serializer\SerializationContext; | ||
6 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | 7 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
7 | use Symfony\Component\HttpFoundation\JsonResponse; | 8 | use Symfony\Component\HttpFoundation\JsonResponse; |
8 | use Symfony\Component\Security\Core\Exception\AccessDeniedException; | 9 | use Symfony\Component\Security\Core\Exception\AccessDeniedException; |
9 | 10 | ||
10 | class WallabagRestController extends FOSRestController | 11 | class WallabagRestController extends AbstractFOSRestController |
11 | { | 12 | { |
12 | /** | 13 | /** |
13 | * Retrieve version number. | 14 | * Retrieve version number. |
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..98e0af3e 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 | */ |
12 | class AccessToken extends BaseAccessToken | 28 | class AccessToken extends BaseAccessToken |
13 | { | 29 | { |
@@ -26,6 +42,7 @@ class AccessToken extends BaseAccessToken | |||
26 | 42 | ||
27 | /** | 43 | /** |
28 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") | 44 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") |
45 | * @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE") | ||
29 | */ | 46 | */ |
30 | protected $user; | 47 | protected $user; |
31 | } | 48 | } |
diff --git a/src/Wallabag/ApiBundle/Entity/AuthCode.php b/src/Wallabag/ApiBundle/Entity/AuthCode.php index 4d4b09fe..7c9c8539 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 | */ |
12 | class AuthCode extends BaseAuthCode | 28 | class AuthCode extends BaseAuthCode |
13 | { | 29 | { |
@@ -26,6 +42,7 @@ class AuthCode extends BaseAuthCode | |||
26 | 42 | ||
27 | /** | 43 | /** |
28 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") | 44 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") |
45 | * @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE") | ||
29 | */ | 46 | */ |
30 | protected $user; | 47 | protected $user; |
31 | } | 48 | } |
diff --git a/src/Wallabag/ApiBundle/Entity/Client.php b/src/Wallabag/ApiBundle/Entity/Client.php index e6f98f98..78349820 100644 --- a/src/Wallabag/ApiBundle/Entity/Client.php +++ b/src/Wallabag/ApiBundle/Entity/Client.php | |||
@@ -11,7 +11,7 @@ use Wallabag\UserBundle\Entity\User; | |||
11 | 11 | ||
12 | /** | 12 | /** |
13 | * @ORM\Table("oauth2_clients") | 13 | * @ORM\Table("oauth2_clients") |
14 | * @ORM\Entity | 14 | * @ORM\Entity(repositoryClass="Wallabag\ApiBundle\Repository\ClientRepository") |
15 | */ | 15 | */ |
16 | class Client extends BaseClient | 16 | class Client extends BaseClient |
17 | { | 17 | { |
diff --git a/src/Wallabag/ApiBundle/Entity/RefreshToken.php b/src/Wallabag/ApiBundle/Entity/RefreshToken.php index 822a02d8..55a507e1 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 | */ |
12 | class RefreshToken extends BaseRefreshToken | 28 | class RefreshToken extends BaseRefreshToken |
13 | { | 29 | { |
@@ -26,6 +42,7 @@ class RefreshToken extends BaseRefreshToken | |||
26 | 42 | ||
27 | /** | 43 | /** |
28 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") | 44 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") |
45 | * @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE") | ||
29 | */ | 46 | */ |
30 | protected $user; | 47 | protected $user; |
31 | } | 48 | } |
diff --git a/src/Wallabag/ApiBundle/Form/Type/ClientType.php b/src/Wallabag/ApiBundle/Form/Type/ClientType.php index fc22538f..14dc5c44 100644 --- a/src/Wallabag/ApiBundle/Form/Type/ClientType.php +++ b/src/Wallabag/ApiBundle/Form/Type/ClientType.php | |||
@@ -20,6 +20,7 @@ class ClientType extends AbstractType | |||
20 | 'required' => false, | 20 | 'required' => false, |
21 | 'label' => 'developer.client.form.redirect_uris_label', | 21 | 'label' => 'developer.client.form.redirect_uris_label', |
22 | 'property_path' => 'redirectUris', | 22 | 'property_path' => 'redirectUris', |
23 | 'default_protocol' => null, | ||
23 | ]) | 24 | ]) |
24 | ->add('save', SubmitType::class, ['label' => 'developer.client.form.save_label']) | 25 | ->add('save', SubmitType::class, ['label' => 'developer.client.form.save_label']) |
25 | ; | 26 | ; |
diff --git a/src/Wallabag/ApiBundle/Repository/ClientRepository.php b/src/Wallabag/ApiBundle/Repository/ClientRepository.php new file mode 100644 index 00000000..fc14262e --- /dev/null +++ b/src/Wallabag/ApiBundle/Repository/ClientRepository.php | |||
@@ -0,0 +1,19 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Repository; | ||
4 | |||
5 | use Doctrine\ORM\EntityRepository; | ||
6 | |||
7 | class ClientRepository extends EntityRepository | ||
8 | { | ||
9 | public function findOneBy(array $criteria, array $orderBy = null) | ||
10 | { | ||
11 | if (!empty($criteria['id'])) { | ||
12 | // cast client id to be an integer to avoid postgres error: | ||
13 | // "invalid input syntax for integer" | ||
14 | $criteria['id'] = (int) $criteria['id']; | ||
15 | } | ||
16 | |||
17 | return parent::findOneBy($criteria, $orderBy); | ||
18 | } | ||
19 | } | ||
diff --git a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml index c0283e71..98efeeb1 100644 --- a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml +++ b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml | |||
@@ -3,11 +3,21 @@ entry: | |||
3 | resource: "WallabagApiBundle:EntryRest" | 3 | resource: "WallabagApiBundle:EntryRest" |
4 | name_prefix: api_ | 4 | name_prefix: api_ |
5 | 5 | ||
6 | search: | ||
7 | type: rest | ||
8 | resource: "WallabagApiBundle:SearchRest" | ||
9 | name_prefix: api_ | ||
10 | |||
6 | tag: | 11 | tag: |
7 | type: rest | 12 | type: rest |
8 | resource: "WallabagApiBundle:TagRest" | 13 | resource: "WallabagApiBundle:TagRest" |
9 | name_prefix: api_ | 14 | name_prefix: api_ |
10 | 15 | ||
16 | tagging_rule: | ||
17 | type: rest | ||
18 | resource: "WallabagApiBundle:TaggingRuleRest" | ||
19 | name_prefix: api_ | ||
20 | |||
11 | annotation: | 21 | annotation: |
12 | type: rest | 22 | type: rest |
13 | resource: "WallabagApiBundle:AnnotationRest" | 23 | resource: "WallabagApiBundle:AnnotationRest" |
diff --git a/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php b/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php index 99170967..64b91520 100644 --- a/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php +++ b/src/Wallabag/CoreBundle/Command/CleanDuplicatesCommand.php | |||
@@ -63,9 +63,6 @@ class CleanDuplicatesCommand extends ContainerAwareCommand | |||
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | /** | ||
67 | * @param User $user | ||
68 | */ | ||
69 | private function cleanDuplicates(User $user) | 66 | private function cleanDuplicates(User $user) |
70 | { | 67 | { |
71 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); | 68 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); |
diff --git a/src/Wallabag/CoreBundle/Command/GenerateUrlHashesCommand.php b/src/Wallabag/CoreBundle/Command/GenerateUrlHashesCommand.php new file mode 100644 index 00000000..a0e9221e --- /dev/null +++ b/src/Wallabag/CoreBundle/Command/GenerateUrlHashesCommand.php | |||
@@ -0,0 +1,96 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Command; | ||
4 | |||
5 | use Doctrine\ORM\NoResultException; | ||
6 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; | ||
7 | use Symfony\Component\Console\Input\InputArgument; | ||
8 | use Symfony\Component\Console\Input\InputInterface; | ||
9 | use Symfony\Component\Console\Output\OutputInterface; | ||
10 | use Wallabag\CoreBundle\Helper\UrlHasher; | ||
11 | use Wallabag\UserBundle\Entity\User; | ||
12 | |||
13 | class GenerateUrlHashesCommand extends ContainerAwareCommand | ||
14 | { | ||
15 | /** @var OutputInterface */ | ||
16 | protected $output; | ||
17 | |||
18 | protected function configure() | ||
19 | { | ||
20 | $this | ||
21 | ->setName('wallabag:generate-hashed-urls') | ||
22 | ->setDescription('Generates hashed urls for each entry') | ||
23 | ->setHelp('This command helps you to generates hashes of the url of each entry, to check through API if an URL is already saved') | ||
24 | ->addArgument('username', InputArgument::OPTIONAL, 'User to process entries'); | ||
25 | } | ||
26 | |||
27 | protected function execute(InputInterface $input, OutputInterface $output) | ||
28 | { | ||
29 | $this->output = $output; | ||
30 | |||
31 | $username = (string) $input->getArgument('username'); | ||
32 | |||
33 | if ($username) { | ||
34 | try { | ||
35 | $user = $this->getUser($username); | ||
36 | $this->generateHashedUrls($user); | ||
37 | } catch (NoResultException $e) { | ||
38 | $output->writeln(sprintf('<error>User "%s" not found.</error>', $username)); | ||
39 | |||
40 | return 1; | ||
41 | } | ||
42 | } else { | ||
43 | $users = $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findAll(); | ||
44 | |||
45 | $output->writeln(sprintf('Generating hashed urls for "%d" users', \count($users))); | ||
46 | |||
47 | foreach ($users as $user) { | ||
48 | $output->writeln(sprintf('Processing user: %s', $user->getUsername())); | ||
49 | $this->generateHashedUrls($user); | ||
50 | } | ||
51 | $output->writeln('Finished generated hashed urls'); | ||
52 | } | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | private function generateHashedUrls(User $user) | ||
58 | { | ||
59 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); | ||
60 | $repo = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry'); | ||
61 | |||
62 | $entries = $repo->findByUser($user->getId()); | ||
63 | |||
64 | $i = 1; | ||
65 | foreach ($entries as $entry) { | ||
66 | $entry->setHashedUrl(UrlHasher::hashUrl($entry->getUrl())); | ||
67 | $em->persist($entry); | ||
68 | |||
69 | if (0 === ($i % 20)) { | ||
70 | $em->flush(); | ||
71 | } | ||
72 | ++$i; | ||
73 | } | ||
74 | |||
75 | $em->flush(); | ||
76 | |||
77 | $this->output->writeln(sprintf('Generated hashed urls for user: %s', $user->getUserName())); | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * Fetches a user from its username. | ||
82 | * | ||
83 | * @param string $username | ||
84 | * | ||
85 | * @return User | ||
86 | */ | ||
87 | private function getUser($username) | ||
88 | { | ||
89 | return $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findOneByUserName($username); | ||
90 | } | ||
91 | |||
92 | private function getDoctrine() | ||
93 | { | ||
94 | return $this->getContainer()->get('doctrine'); | ||
95 | } | ||
96 | } | ||
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index 3c76545c..3aa332f1 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Command; | 3 | namespace Wallabag\CoreBundle\Command; |
4 | 4 | ||
5 | use Craue\ConfigBundle\Entity\Setting; | ||
6 | use FOS\UserBundle\Event\UserEvent; | 5 | use FOS\UserBundle\Event\UserEvent; |
7 | use FOS\UserBundle\FOSUserEvents; | 6 | use FOS\UserBundle\FOSUserEvents; |
8 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; | 7 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; |
@@ -13,6 +12,7 @@ use Symfony\Component\Console\Output\BufferedOutput; | |||
13 | use Symfony\Component\Console\Output\OutputInterface; | 12 | use Symfony\Component\Console\Output\OutputInterface; |
14 | use Symfony\Component\Console\Question\Question; | 13 | use Symfony\Component\Console\Question\Question; |
15 | use Symfony\Component\Console\Style\SymfonyStyle; | 14 | use Symfony\Component\Console\Style\SymfonyStyle; |
15 | use Wallabag\CoreBundle\Entity\InternalSetting; | ||
16 | 16 | ||
17 | class InstallCommand extends ContainerAwareCommand | 17 | class InstallCommand extends ContainerAwareCommand |
18 | { | 18 | { |
@@ -54,7 +54,7 @@ class InstallCommand extends ContainerAwareCommand | |||
54 | 54 | ||
55 | $this->io = new SymfonyStyle($input, $output); | 55 | $this->io = new SymfonyStyle($input, $output); |
56 | 56 | ||
57 | $this->io->title('Wallabag installer'); | 57 | $this->io->title('wallabag installer'); |
58 | 58 | ||
59 | $this | 59 | $this |
60 | ->checkRequirements() | 60 | ->checkRequirements() |
@@ -63,7 +63,7 @@ class InstallCommand extends ContainerAwareCommand | |||
63 | ->setupConfig() | 63 | ->setupConfig() |
64 | ; | 64 | ; |
65 | 65 | ||
66 | $this->io->success('Wallabag has been successfully installed.'); | 66 | $this->io->success('wallabag has been successfully installed.'); |
67 | $this->io->success('You can now configure your web server, see https://doc.wallabag.org'); | 67 | $this->io->success('You can now configure your web server, see https://doc.wallabag.org'); |
68 | } | 68 | } |
69 | 69 | ||
@@ -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') |
@@ -253,7 +254,7 @@ class InstallCommand extends ContainerAwareCommand | |||
253 | $question->setHidden(true); | 254 | $question->setHidden(true); |
254 | $user->setPlainPassword($this->io->askQuestion($question)); | 255 | $user->setPlainPassword($this->io->askQuestion($question)); |
255 | 256 | ||
256 | $user->setEmail($this->io->ask('Email', '')); | 257 | $user->setEmail($this->io->ask('Email', 'wallabag@wallabag.io')); |
257 | 258 | ||
258 | $user->setEnabled(true); | 259 | $user->setEnabled(true); |
259 | $user->addRole('ROLE_SUPER_ADMIN'); | 260 | $user->addRole('ROLE_SUPER_ADMIN'); |
@@ -275,10 +276,10 @@ class InstallCommand extends ContainerAwareCommand | |||
275 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); | 276 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); |
276 | 277 | ||
277 | // cleanup before insert new stuff | 278 | // cleanup before insert new stuff |
278 | $em->createQuery('DELETE FROM CraueConfigBundle:Setting')->execute(); | 279 | $em->createQuery('DELETE FROM WallabagCoreBundle:InternalSetting')->execute(); |
279 | 280 | ||
280 | foreach ($this->getContainer()->getParameter('wallabag_core.default_internal_settings') as $setting) { | 281 | foreach ($this->getContainer()->getParameter('wallabag_core.default_internal_settings') as $setting) { |
281 | $newSetting = new Setting(); | 282 | $newSetting = new InternalSetting(); |
282 | $newSetting->setName($setting['name']); | 283 | $newSetting->setName($setting['name']); |
283 | $newSetting->setValue($setting['value']); | 284 | $newSetting->setValue($setting['value']); |
284 | $newSetting->setSection($setting['section']); | 285 | $newSetting->setSection($setting['section']); |
@@ -325,9 +326,7 @@ class InstallCommand extends ContainerAwareCommand | |||
325 | if (0 !== $exitCode) { | 326 | if (0 !== $exitCode) { |
326 | $this->getApplication()->setAutoExit(true); | 327 | $this->getApplication()->setAutoExit(true); |
327 | 328 | ||
328 | throw new \RuntimeException( | 329 | throw new \RuntimeException('The command "' . $command . "\" generates some errors: \n\n" . $output->fetch()); |
329 | 'The command "' . $command . "\" generates some errors: \n\n" | ||
330 | . $output->fetch()); | ||
331 | } | 330 | } |
332 | 331 | ||
333 | return $this; | 332 | return $this; |
diff --git a/src/Wallabag/CoreBundle/Command/ShowUserCommand.php b/src/Wallabag/CoreBundle/Command/ShowUserCommand.php index a0184267..87bccf71 100644 --- a/src/Wallabag/CoreBundle/Command/ShowUserCommand.php +++ b/src/Wallabag/CoreBundle/Command/ShowUserCommand.php | |||
@@ -46,9 +46,6 @@ class ShowUserCommand extends ContainerAwareCommand | |||
46 | return 0; | 46 | return 0; |
47 | } | 47 | } |
48 | 48 | ||
49 | /** | ||
50 | * @param User $user | ||
51 | */ | ||
52 | private function showUser(User $user) | 49 | private function showUser(User $user) |
53 | { | 50 | { |
54 | $this->io->listing([ | 51 | $this->io->listing([ |
@@ -57,7 +54,8 @@ class ShowUserCommand extends ContainerAwareCommand | |||
57 | sprintf('Display name: %s', $user->getName()), | 54 | sprintf('Display name: %s', $user->getName()), |
58 | sprintf('Creation date: %s', $user->getCreatedAt()->format('Y-m-d H:i:s')), | 55 | 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'), | 56 | 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'), | 57 | sprintf('2FA (email) activated: %s', $user->isEmailTwoFactor() ? 'yes' : 'no'), |
58 | sprintf('2FA (OTP) activated: %s', $user->isGoogleAuthenticatorEnabled() ? 'yes' : 'no'), | ||
61 | ]); | 59 | ]); |
62 | } | 60 | } |
63 | 61 | ||
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index b999c539..6655ef93 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php | |||
@@ -2,17 +2,23 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 5 | use JMS\Serializer\SerializationContext; |
6 | use JMS\Serializer\SerializerBuilder; | ||
7 | use PragmaRX\Recovery\Recovery as BackupCodes; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\JsonResponse; | 9 | use Symfony\Component\HttpFoundation\JsonResponse; |
8 | use Symfony\Component\HttpFoundation\RedirectResponse; | 10 | use Symfony\Component\HttpFoundation\RedirectResponse; |
9 | use Symfony\Component\HttpFoundation\Request; | 11 | use Symfony\Component\HttpFoundation\Request; |
12 | use Symfony\Component\HttpFoundation\Response; | ||
10 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; | 13 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; |
14 | use Symfony\Component\Routing\Annotation\Route; | ||
15 | use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint; | ||
11 | use Wallabag\CoreBundle\Entity\Config; | 16 | use Wallabag\CoreBundle\Entity\Config; |
12 | use Wallabag\CoreBundle\Entity\TaggingRule; | 17 | use Wallabag\CoreBundle\Entity\TaggingRule; |
13 | use Wallabag\CoreBundle\Form\Type\ChangePasswordType; | 18 | use Wallabag\CoreBundle\Form\Type\ChangePasswordType; |
14 | use Wallabag\CoreBundle\Form\Type\ConfigType; | 19 | use Wallabag\CoreBundle\Form\Type\ConfigType; |
15 | use Wallabag\CoreBundle\Form\Type\RssType; | 20 | use Wallabag\CoreBundle\Form\Type\FeedType; |
21 | use Wallabag\CoreBundle\Form\Type\TaggingRuleImportType; | ||
16 | use Wallabag\CoreBundle\Form\Type\TaggingRuleType; | 22 | use Wallabag\CoreBundle\Form\Type\TaggingRuleType; |
17 | use Wallabag\CoreBundle\Form\Type\UserInformationType; | 23 | use Wallabag\CoreBundle\Form\Type\UserInformationType; |
18 | use Wallabag\CoreBundle\Tools\Utils; | 24 | use Wallabag\CoreBundle\Tools\Utils; |
@@ -20,8 +26,6 @@ use Wallabag\CoreBundle\Tools\Utils; | |||
20 | class ConfigController extends Controller | 26 | class ConfigController extends Controller |
21 | { | 27 | { |
22 | /** | 28 | /** |
23 | * @param Request $request | ||
24 | * | ||
25 | * @Route("/config", name="config") | 29 | * @Route("/config", name="config") |
26 | */ | 30 | */ |
27 | public function indexAction(Request $request) | 31 | public function indexAction(Request $request) |
@@ -45,7 +49,7 @@ class ConfigController extends Controller | |||
45 | $activeTheme = $this->get('liip_theme.active_theme'); | 49 | $activeTheme = $this->get('liip_theme.active_theme'); |
46 | $activeTheme->setName($config->getTheme()); | 50 | $activeTheme->setName($config->getTheme()); |
47 | 51 | ||
48 | $this->get('session')->getFlashBag()->add( | 52 | $this->addFlash( |
49 | 'notice', | 53 | 'notice', |
50 | 'flashes.config.notice.config_saved' | 54 | 'flashes.config.notice.config_saved' |
51 | ); | 55 | ); |
@@ -67,7 +71,7 @@ class ConfigController extends Controller | |||
67 | $userManager->updateUser($user, true); | 71 | $userManager->updateUser($user, true); |
68 | } | 72 | } |
69 | 73 | ||
70 | $this->get('session')->getFlashBag()->add('notice', $message); | 74 | $this->addFlash('notice', $message); |
71 | 75 | ||
72 | return $this->redirect($this->generateUrl('config') . '#set4'); | 76 | return $this->redirect($this->generateUrl('config') . '#set4'); |
73 | } | 77 | } |
@@ -82,7 +86,7 @@ class ConfigController extends Controller | |||
82 | if ($userForm->isSubmitted() && $userForm->isValid()) { | 86 | if ($userForm->isSubmitted() && $userForm->isValid()) { |
83 | $userManager->updateUser($user, true); | 87 | $userManager->updateUser($user, true); |
84 | 88 | ||
85 | $this->get('session')->getFlashBag()->add( | 89 | $this->addFlash( |
86 | 'notice', | 90 | 'notice', |
87 | 'flashes.config.notice.user_updated' | 91 | 'flashes.config.notice.user_updated' |
88 | ); | 92 | ); |
@@ -90,17 +94,17 @@ class ConfigController extends Controller | |||
90 | return $this->redirect($this->generateUrl('config') . '#set3'); | 94 | return $this->redirect($this->generateUrl('config') . '#set3'); |
91 | } | 95 | } |
92 | 96 | ||
93 | // handle rss information | 97 | // handle feed information |
94 | $rssForm = $this->createForm(RssType::class, $config, ['action' => $this->generateUrl('config') . '#set2']); | 98 | $feedForm = $this->createForm(FeedType::class, $config, ['action' => $this->generateUrl('config') . '#set2']); |
95 | $rssForm->handleRequest($request); | 99 | $feedForm->handleRequest($request); |
96 | 100 | ||
97 | if ($rssForm->isSubmitted() && $rssForm->isValid()) { | 101 | if ($feedForm->isSubmitted() && $feedForm->isValid()) { |
98 | $em->persist($config); | 102 | $em->persist($config); |
99 | $em->flush(); | 103 | $em->flush(); |
100 | 104 | ||
101 | $this->get('session')->getFlashBag()->add( | 105 | $this->addFlash( |
102 | 'notice', | 106 | 'notice', |
103 | 'flashes.config.notice.rss_updated' | 107 | 'flashes.config.notice.feed_updated' |
104 | ); | 108 | ); |
105 | 109 | ||
106 | return $this->redirect($this->generateUrl('config') . '#set2'); | 110 | return $this->redirect($this->generateUrl('config') . '#set2'); |
@@ -130,7 +134,7 @@ class ConfigController extends Controller | |||
130 | $em->persist($taggingRule); | 134 | $em->persist($taggingRule); |
131 | $em->flush(); | 135 | $em->flush(); |
132 | 136 | ||
133 | $this->get('session')->getFlashBag()->add( | 137 | $this->addFlash( |
134 | 'notice', | 138 | 'notice', |
135 | 'flashes.config.notice.tagging_rules_updated' | 139 | 'flashes.config.notice.tagging_rules_updated' |
136 | ); | 140 | ); |
@@ -138,28 +142,168 @@ class ConfigController extends Controller | |||
138 | return $this->redirect($this->generateUrl('config') . '#set5'); | 142 | return $this->redirect($this->generateUrl('config') . '#set5'); |
139 | } | 143 | } |
140 | 144 | ||
145 | // handle tagging rules import | ||
146 | $taggingRulesImportform = $this->createForm(TaggingRuleImportType::class); | ||
147 | $taggingRulesImportform->handleRequest($request); | ||
148 | |||
149 | if ($taggingRulesImportform->isSubmitted() && $taggingRulesImportform->isValid()) { | ||
150 | $message = 'flashes.config.notice.tagging_rules_not_imported'; | ||
151 | $file = $taggingRulesImportform->get('file')->getData(); | ||
152 | |||
153 | if (null !== $file && $file->isValid() && \in_array($file->getClientMimeType(), ['application/json', 'application/octet-stream'], true)) { | ||
154 | $content = json_decode(file_get_contents($file->getPathname()), true); | ||
155 | |||
156 | if (\is_array($content)) { | ||
157 | foreach ($content as $rule) { | ||
158 | $taggingRule = new TaggingRule(); | ||
159 | $taggingRule->setRule($rule['rule']); | ||
160 | $taggingRule->setTags($rule['tags']); | ||
161 | $taggingRule->setConfig($config); | ||
162 | $em->persist($taggingRule); | ||
163 | } | ||
164 | |||
165 | $em->flush(); | ||
166 | |||
167 | $message = 'flashes.config.notice.tagging_rules_imported'; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | $this->addFlash('notice', $message); | ||
172 | |||
173 | return $this->redirect($this->generateUrl('config') . '#set5'); | ||
174 | } | ||
175 | |||
141 | return $this->render('WallabagCoreBundle:Config:index.html.twig', [ | 176 | return $this->render('WallabagCoreBundle:Config:index.html.twig', [ |
142 | 'form' => [ | 177 | 'form' => [ |
143 | 'config' => $configForm->createView(), | 178 | 'config' => $configForm->createView(), |
144 | 'rss' => $rssForm->createView(), | 179 | 'feed' => $feedForm->createView(), |
145 | 'pwd' => $pwdForm->createView(), | 180 | 'pwd' => $pwdForm->createView(), |
146 | 'user' => $userForm->createView(), | 181 | 'user' => $userForm->createView(), |
147 | 'new_tagging_rule' => $newTaggingRule->createView(), | 182 | 'new_tagging_rule' => $newTaggingRule->createView(), |
183 | 'import_tagging_rule' => $taggingRulesImportform->createView(), | ||
148 | ], | 184 | ], |
149 | 'rss' => [ | 185 | 'feed' => [ |
150 | 'username' => $user->getUsername(), | 186 | 'username' => $user->getUsername(), |
151 | 'token' => $config->getRssToken(), | 187 | 'token' => $config->getFeedToken(), |
152 | ], | 188 | ], |
153 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), | 189 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), |
154 | 'wallabag_url' => $this->getParameter('domain_name'), | 190 | 'wallabag_url' => $this->getParameter('domain_name'), |
155 | 'enabled_users' => $this->get('wallabag_user.user_repository') | 191 | 'enabled_users' => $this->get('wallabag_user.user_repository')->getSumEnabledUsers(), |
156 | ->getSumEnabledUsers(), | 192 | ]); |
193 | } | ||
194 | |||
195 | /** | ||
196 | * Enable 2FA using email. | ||
197 | * | ||
198 | * @Route("/config/otp/email", name="config_otp_email") | ||
199 | */ | ||
200 | public function otpEmailAction() | ||
201 | { | ||
202 | if (!$this->getParameter('twofactor_auth')) { | ||
203 | return $this->createNotFoundException('two_factor not enabled'); | ||
204 | } | ||
205 | |||
206 | $user = $this->getUser(); | ||
207 | |||
208 | $user->setGoogleAuthenticatorSecret(null); | ||
209 | $user->setBackupCodes(null); | ||
210 | $user->setEmailTwoFactor(true); | ||
211 | |||
212 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
213 | |||
214 | $this->addFlash( | ||
215 | 'notice', | ||
216 | 'flashes.config.notice.otp_enabled' | ||
217 | ); | ||
218 | |||
219 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * Enable 2FA using OTP app, user will need to confirm the generated code from the app. | ||
224 | * | ||
225 | * @Route("/config/otp/app", name="config_otp_app") | ||
226 | */ | ||
227 | public function otpAppAction() | ||
228 | { | ||
229 | if (!$this->getParameter('twofactor_auth')) { | ||
230 | return $this->createNotFoundException('two_factor not enabled'); | ||
231 | } | ||
232 | |||
233 | $user = $this->getUser(); | ||
234 | $secret = $this->get('scheb_two_factor.security.google_authenticator')->generateSecret(); | ||
235 | |||
236 | $user->setGoogleAuthenticatorSecret($secret); | ||
237 | $user->setEmailTwoFactor(false); | ||
238 | |||
239 | $backupCodes = (new BackupCodes())->toArray(); | ||
240 | $backupCodesHashed = array_map( | ||
241 | function ($backupCode) { | ||
242 | return password_hash($backupCode, PASSWORD_DEFAULT); | ||
243 | }, | ||
244 | $backupCodes | ||
245 | ); | ||
246 | |||
247 | $user->setBackupCodes($backupCodesHashed); | ||
248 | |||
249 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
250 | |||
251 | return $this->render('WallabagCoreBundle:Config:otp_app.html.twig', [ | ||
252 | 'backupCodes' => $backupCodes, | ||
253 | 'qr_code' => $this->get('scheb_two_factor.security.google_authenticator')->getQRContent($user), | ||
157 | ]); | 254 | ]); |
158 | } | 255 | } |
159 | 256 | ||
160 | /** | 257 | /** |
161 | * @param Request $request | 258 | * Cancelling 2FA using OTP app. |
162 | * | 259 | * |
260 | * @Route("/config/otp/app/cancel", name="config_otp_app_cancel") | ||
261 | */ | ||
262 | public function otpAppCancelAction() | ||
263 | { | ||
264 | if (!$this->getParameter('twofactor_auth')) { | ||
265 | return $this->createNotFoundException('two_factor not enabled'); | ||
266 | } | ||
267 | |||
268 | $user = $this->getUser(); | ||
269 | $user->setGoogleAuthenticatorSecret(null); | ||
270 | $user->setBackupCodes(null); | ||
271 | |||
272 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
273 | |||
274 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
275 | } | ||
276 | |||
277 | /** | ||
278 | * Validate OTP code. | ||
279 | * | ||
280 | * @Route("/config/otp/app/check", name="config_otp_app_check") | ||
281 | */ | ||
282 | public function otpAppCheckAction(Request $request) | ||
283 | { | ||
284 | $isValid = $this->get('scheb_two_factor.security.google_authenticator')->checkCode( | ||
285 | $this->getUser(), | ||
286 | $request->get('_auth_code') | ||
287 | ); | ||
288 | |||
289 | if (true === $isValid) { | ||
290 | $this->addFlash( | ||
291 | 'notice', | ||
292 | 'flashes.config.notice.otp_enabled' | ||
293 | ); | ||
294 | |||
295 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
296 | } | ||
297 | |||
298 | $this->addFlash( | ||
299 | 'two_factor', | ||
300 | 'scheb_two_factor.code_invalid' | ||
301 | ); | ||
302 | |||
303 | return $this->redirect($this->generateUrl('config_otp_app')); | ||
304 | } | ||
305 | |||
306 | /** | ||
163 | * @Route("/generate-token", name="generate_token") | 307 | * @Route("/generate-token", name="generate_token") |
164 | * | 308 | * |
165 | * @return RedirectResponse|JsonResponse | 309 | * @return RedirectResponse|JsonResponse |
@@ -167,28 +311,52 @@ class ConfigController extends Controller | |||
167 | public function generateTokenAction(Request $request) | 311 | public function generateTokenAction(Request $request) |
168 | { | 312 | { |
169 | $config = $this->getConfig(); | 313 | $config = $this->getConfig(); |
170 | $config->setRssToken(Utils::generateToken()); | 314 | $config->setFeedToken(Utils::generateToken()); |
171 | 315 | ||
172 | $em = $this->getDoctrine()->getManager(); | 316 | $em = $this->getDoctrine()->getManager(); |
173 | $em->persist($config); | 317 | $em->persist($config); |
174 | $em->flush(); | 318 | $em->flush(); |
175 | 319 | ||
176 | if ($request->isXmlHttpRequest()) { | 320 | if ($request->isXmlHttpRequest()) { |
177 | return new JsonResponse(['token' => $config->getRssToken()]); | 321 | return new JsonResponse(['token' => $config->getFeedToken()]); |
178 | } | 322 | } |
179 | 323 | ||
180 | $this->get('session')->getFlashBag()->add( | 324 | $this->addFlash( |
181 | 'notice', | 325 | 'notice', |
182 | 'flashes.config.notice.rss_token_updated' | 326 | 'flashes.config.notice.feed_token_updated' |
183 | ); | 327 | ); |
184 | 328 | ||
185 | return $this->redirect($this->generateUrl('config') . '#set2'); | 329 | return $this->redirect($this->generateUrl('config') . '#set2'); |
186 | } | 330 | } |
187 | 331 | ||
188 | /** | 332 | /** |
189 | * Deletes a tagging rule and redirect to the config homepage. | 333 | * @Route("/revoke-token", name="revoke_token") |
190 | * | 334 | * |
191 | * @param TaggingRule $rule | 335 | * @return RedirectResponse|JsonResponse |
336 | */ | ||
337 | public function revokeTokenAction(Request $request) | ||
338 | { | ||
339 | $config = $this->getConfig(); | ||
340 | $config->setFeedToken(null); | ||
341 | |||
342 | $em = $this->getDoctrine()->getManager(); | ||
343 | $em->persist($config); | ||
344 | $em->flush(); | ||
345 | |||
346 | if ($request->isXmlHttpRequest()) { | ||
347 | return new JsonResponse(); | ||
348 | } | ||
349 | |||
350 | $this->addFlash( | ||
351 | 'notice', | ||
352 | 'flashes.config.notice.feed_token_revoked' | ||
353 | ); | ||
354 | |||
355 | return $this->redirect($this->generateUrl('config') . '#set2'); | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * Deletes a tagging rule and redirect to the config homepage. | ||
192 | * | 360 | * |
193 | * @Route("/tagging-rule/delete/{id}", requirements={"id" = "\d+"}, name="delete_tagging_rule") | 361 | * @Route("/tagging-rule/delete/{id}", requirements={"id" = "\d+"}, name="delete_tagging_rule") |
194 | * | 362 | * |
@@ -202,7 +370,7 @@ class ConfigController extends Controller | |||
202 | $em->remove($rule); | 370 | $em->remove($rule); |
203 | $em->flush(); | 371 | $em->flush(); |
204 | 372 | ||
205 | $this->get('session')->getFlashBag()->add( | 373 | $this->addFlash( |
206 | 'notice', | 374 | 'notice', |
207 | 'flashes.config.notice.tagging_rules_deleted' | 375 | 'flashes.config.notice.tagging_rules_deleted' |
208 | ); | 376 | ); |
@@ -213,8 +381,6 @@ class ConfigController extends Controller | |||
213 | /** | 381 | /** |
214 | * Edit a tagging rule. | 382 | * Edit a tagging rule. |
215 | * | 383 | * |
216 | * @param TaggingRule $rule | ||
217 | * | ||
218 | * @Route("/tagging-rule/edit/{id}", requirements={"id" = "\d+"}, name="edit_tagging_rule") | 384 | * @Route("/tagging-rule/edit/{id}", requirements={"id" = "\d+"}, name="edit_tagging_rule") |
219 | * | 385 | * |
220 | * @return RedirectResponse | 386 | * @return RedirectResponse |
@@ -268,7 +434,7 @@ class ConfigController extends Controller | |||
268 | break; | 434 | break; |
269 | } | 435 | } |
270 | 436 | ||
271 | $this->get('session')->getFlashBag()->add( | 437 | $this->addFlash( |
272 | 'notice', | 438 | 'notice', |
273 | 'flashes.config.notice.' . $type . '_reset' | 439 | 'flashes.config.notice.' . $type . '_reset' |
274 | ); | 440 | ); |
@@ -281,8 +447,6 @@ class ConfigController extends Controller | |||
281 | * | 447 | * |
282 | * @Route("/account/delete", name="delete_account") | 448 | * @Route("/account/delete", name="delete_account") |
283 | * | 449 | * |
284 | * @param Request $request | ||
285 | * | ||
286 | * @throws AccessDeniedHttpException | 450 | * @throws AccessDeniedHttpException |
287 | * | 451 | * |
288 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 452 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -313,8 +477,6 @@ class ConfigController extends Controller | |||
313 | * | 477 | * |
314 | * @Route("/config/view-mode", name="switch_view_mode") | 478 | * @Route("/config/view-mode", name="switch_view_mode") |
315 | * | 479 | * |
316 | * @param Request $request | ||
317 | * | ||
318 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 480 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
319 | */ | 481 | */ |
320 | public function changeViewModeAction(Request $request) | 482 | public function changeViewModeAction(Request $request) |
@@ -330,6 +492,52 @@ class ConfigController extends Controller | |||
330 | } | 492 | } |
331 | 493 | ||
332 | /** | 494 | /** |
495 | * Change the locale for the current user. | ||
496 | * | ||
497 | * @param string $language | ||
498 | * | ||
499 | * @Route("/locale/{language}", name="changeLocale") | ||
500 | * | ||
501 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | ||
502 | */ | ||
503 | public function setLocaleAction(Request $request, $language = null) | ||
504 | { | ||
505 | $errors = $this->get('validator')->validate($language, (new LocaleConstraint())); | ||
506 | |||
507 | if (0 === \count($errors)) { | ||
508 | $request->getSession()->set('_locale', $language); | ||
509 | } | ||
510 | |||
511 | return $this->redirect($request->headers->get('referer', $this->generateUrl('homepage'))); | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * Export tagging rules for the logged in user. | ||
516 | * | ||
517 | * @Route("/tagging-rule/export", name="export_tagging_rule") | ||
518 | * | ||
519 | * @return Response | ||
520 | */ | ||
521 | public function exportTaggingRulesAction() | ||
522 | { | ||
523 | $data = SerializerBuilder::create()->build()->serialize( | ||
524 | $this->getUser()->getConfig()->getTaggingRules(), | ||
525 | 'json', | ||
526 | SerializationContext::create()->setGroups(['export_tagging_rule']) | ||
527 | ); | ||
528 | |||
529 | return Response::create( | ||
530 | $data, | ||
531 | 200, | ||
532 | [ | ||
533 | 'Content-type' => 'application/json', | ||
534 | 'Content-Disposition' => 'attachment; filename="tagging_rules_' . $this->getUser()->getUsername() . '.json"', | ||
535 | 'Content-Transfer-Encoding' => 'UTF-8', | ||
536 | ] | ||
537 | ); | ||
538 | } | ||
539 | |||
540 | /** | ||
333 | * Remove all tags for given tags and a given user and cleanup orphan tags. | 541 | * Remove all tags for given tags and a given user and cleanup orphan tags. |
334 | * | 542 | * |
335 | * @param array $tags | 543 | * @param array $tags |
@@ -395,8 +603,6 @@ class ConfigController extends Controller | |||
395 | 603 | ||
396 | /** | 604 | /** |
397 | * Validate that a rule can be edited/deleted by the current user. | 605 | * Validate that a rule can be edited/deleted by the current user. |
398 | * | ||
399 | * @param TaggingRule $rule | ||
400 | */ | 606 | */ |
401 | private function validateRuleAction(TaggingRule $rule) | 607 | private function validateRuleAction(TaggingRule $rule) |
402 | { | 608 | { |
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index b7fdea27..ba5bfbe2 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php | |||
@@ -2,12 +2,13 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Doctrine\ORM\NoResultException; | ||
5 | use Pagerfanta\Adapter\DoctrineORMAdapter; | 6 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; | 8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; |
8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
9 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 9 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
10 | use Symfony\Component\HttpFoundation\Request; | 10 | use Symfony\Component\HttpFoundation\Request; |
11 | use Symfony\Component\Routing\Annotation\Route; | ||
11 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 12 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
12 | use Wallabag\CoreBundle\Entity\Entry; | 13 | use Wallabag\CoreBundle\Entity\Entry; |
13 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; | 14 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; |
@@ -20,8 +21,7 @@ use Wallabag\CoreBundle\Form\Type\SearchEntryType; | |||
20 | class EntryController extends Controller | 21 | class EntryController extends Controller |
21 | { | 22 | { |
22 | /** | 23 | /** |
23 | * @param Request $request | 24 | * @param int $page |
24 | * @param int $page | ||
25 | * | 25 | * |
26 | * @Route("/search/{page}", name="search", defaults={"page" = 1}) | 26 | * @Route("/search/{page}", name="search", defaults={"page" = 1}) |
27 | * | 27 | * |
@@ -52,8 +52,6 @@ class EntryController extends Controller | |||
52 | } | 52 | } |
53 | 53 | ||
54 | /** | 54 | /** |
55 | * @param Request $request | ||
56 | * | ||
57 | * @Route("/new-entry", name="new_entry") | 55 | * @Route("/new-entry", name="new_entry") |
58 | * | 56 | * |
59 | * @return \Symfony\Component\HttpFoundation\Response | 57 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -96,8 +94,6 @@ class EntryController extends Controller | |||
96 | } | 94 | } |
97 | 95 | ||
98 | /** | 96 | /** |
99 | * @param Request $request | ||
100 | * | ||
101 | * @Route("/bookmarklet", name="bookmarklet") | 97 | * @Route("/bookmarklet", name="bookmarklet") |
102 | * | 98 | * |
103 | * @return \Symfony\Component\HttpFoundation\Response | 99 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -134,9 +130,6 @@ class EntryController extends Controller | |||
134 | /** | 130 | /** |
135 | * Edit an entry content. | 131 | * Edit an entry content. |
136 | * | 132 | * |
137 | * @param Request $request | ||
138 | * @param Entry $entry | ||
139 | * | ||
140 | * @Route("/edit/{id}", requirements={"id" = "\d+"}, name="edit") | 133 | * @Route("/edit/{id}", requirements={"id" = "\d+"}, name="edit") |
141 | * | 134 | * |
142 | * @return \Symfony\Component\HttpFoundation\Response | 135 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -170,8 +163,7 @@ class EntryController extends Controller | |||
170 | /** | 163 | /** |
171 | * Shows all entries for current user. | 164 | * Shows all entries for current user. |
172 | * | 165 | * |
173 | * @param Request $request | 166 | * @param int $page |
174 | * @param int $page | ||
175 | * | 167 | * |
176 | * @Route("/all/list/{page}", name="all", defaults={"page" = "1"}) | 168 | * @Route("/all/list/{page}", name="all", defaults={"page" = "1"}) |
177 | * | 169 | * |
@@ -185,8 +177,7 @@ class EntryController extends Controller | |||
185 | /** | 177 | /** |
186 | * Shows unread entries for current user. | 178 | * Shows unread entries for current user. |
187 | * | 179 | * |
188 | * @param Request $request | 180 | * @param int $page |
189 | * @param int $page | ||
190 | * | 181 | * |
191 | * @Route("/unread/list/{page}", name="unread", defaults={"page" = "1"}) | 182 | * @Route("/unread/list/{page}", name="unread", defaults={"page" = "1"}) |
192 | * | 183 | * |
@@ -205,8 +196,7 @@ class EntryController extends Controller | |||
205 | /** | 196 | /** |
206 | * Shows read entries for current user. | 197 | * Shows read entries for current user. |
207 | * | 198 | * |
208 | * @param Request $request | 199 | * @param int $page |
209 | * @param int $page | ||
210 | * | 200 | * |
211 | * @Route("/archive/list/{page}", name="archive", defaults={"page" = "1"}) | 201 | * @Route("/archive/list/{page}", name="archive", defaults={"page" = "1"}) |
212 | * | 202 | * |
@@ -220,8 +210,7 @@ class EntryController extends Controller | |||
220 | /** | 210 | /** |
221 | * Shows starred entries for current user. | 211 | * Shows starred entries for current user. |
222 | * | 212 | * |
223 | * @param Request $request | 213 | * @param int $page |
224 | * @param int $page | ||
225 | * | 214 | * |
226 | * @Route("/starred/list/{page}", name="starred", defaults={"page" = "1"}) | 215 | * @Route("/starred/list/{page}", name="starred", defaults={"page" = "1"}) |
227 | * | 216 | * |
@@ -233,9 +222,46 @@ class EntryController extends Controller | |||
233 | } | 222 | } |
234 | 223 | ||
235 | /** | 224 | /** |
236 | * Shows entry content. | 225 | * Shows untagged articles for current user. |
226 | * | ||
227 | * @param int $page | ||
228 | * | ||
229 | * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"}) | ||
237 | * | 230 | * |
238 | * @param Entry $entry | 231 | * @return \Symfony\Component\HttpFoundation\Response |
232 | */ | ||
233 | public function showUntaggedEntriesAction(Request $request, $page) | ||
234 | { | ||
235 | return $this->showEntries('untagged', $request, $page); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * Shows random entry depending on the given type. | ||
240 | * | ||
241 | * @param string $type | ||
242 | * | ||
243 | * @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|all"}) | ||
244 | * | ||
245 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | ||
246 | */ | ||
247 | public function redirectRandomEntryAction($type = 'all') | ||
248 | { | ||
249 | try { | ||
250 | $entry = $this->get('wallabag_core.entry_repository') | ||
251 | ->getRandomEntry($this->getUser()->getId(), $type); | ||
252 | } catch (NoResultException $e) { | ||
253 | $bag = $this->get('session')->getFlashBag(); | ||
254 | $bag->clear(); | ||
255 | $bag->add('notice', 'flashes.entry.notice.no_random_entry'); | ||
256 | |||
257 | return $this->redirect($this->generateUrl($type)); | ||
258 | } | ||
259 | |||
260 | return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()])); | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * Shows entry content. | ||
239 | * | 265 | * |
240 | * @Route("/view/{id}", requirements={"id" = "\d+"}, name="view") | 266 | * @Route("/view/{id}", requirements={"id" = "\d+"}, name="view") |
241 | * | 267 | * |
@@ -255,8 +281,6 @@ class EntryController extends Controller | |||
255 | * Reload an entry. | 281 | * Reload an entry. |
256 | * Refetch content from the website and make it readable again. | 282 | * Refetch content from the website and make it readable again. |
257 | * | 283 | * |
258 | * @param Entry $entry | ||
259 | * | ||
260 | * @Route("/reload/{id}", requirements={"id" = "\d+"}, name="reload_entry") | 284 | * @Route("/reload/{id}", requirements={"id" = "\d+"}, name="reload_entry") |
261 | * | 285 | * |
262 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 286 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -289,9 +313,6 @@ class EntryController extends Controller | |||
289 | /** | 313 | /** |
290 | * Changes read status for an entry. | 314 | * Changes read status for an entry. |
291 | * | 315 | * |
292 | * @param Request $request | ||
293 | * @param Entry $entry | ||
294 | * | ||
295 | * @Route("/archive/{id}", requirements={"id" = "\d+"}, name="archive_entry") | 316 | * @Route("/archive/{id}", requirements={"id" = "\d+"}, name="archive_entry") |
296 | * | 317 | * |
297 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 318 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -321,9 +342,6 @@ class EntryController extends Controller | |||
321 | /** | 342 | /** |
322 | * Changes starred status for an entry. | 343 | * Changes starred status for an entry. |
323 | * | 344 | * |
324 | * @param Request $request | ||
325 | * @param Entry $entry | ||
326 | * | ||
327 | * @Route("/star/{id}", requirements={"id" = "\d+"}, name="star_entry") | 345 | * @Route("/star/{id}", requirements={"id" = "\d+"}, name="star_entry") |
328 | * | 346 | * |
329 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 347 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -354,8 +372,6 @@ class EntryController extends Controller | |||
354 | /** | 372 | /** |
355 | * Deletes entry and redirect to the homepage or the last viewed page. | 373 | * Deletes entry and redirect to the homepage or the last viewed page. |
356 | * | 374 | * |
357 | * @param Entry $entry | ||
358 | * | ||
359 | * @Route("/delete/{id}", requirements={"id" = "\d+"}, name="delete_entry") | 375 | * @Route("/delete/{id}", requirements={"id" = "\d+"}, name="delete_entry") |
360 | * | 376 | * |
361 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 377 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -396,8 +412,6 @@ class EntryController extends Controller | |||
396 | /** | 412 | /** |
397 | * Get public URL for entry (and generate it if necessary). | 413 | * Get public URL for entry (and generate it if necessary). |
398 | * | 414 | * |
399 | * @param Entry $entry | ||
400 | * | ||
401 | * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share") | 415 | * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share") |
402 | * | 416 | * |
403 | * @return \Symfony\Component\HttpFoundation\Response | 417 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -422,8 +436,6 @@ class EntryController extends Controller | |||
422 | /** | 436 | /** |
423 | * Disable public sharing for an entry. | 437 | * Disable public sharing for an entry. |
424 | * | 438 | * |
425 | * @param Entry $entry | ||
426 | * | ||
427 | * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share") | 439 | * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share") |
428 | * | 440 | * |
429 | * @return \Symfony\Component\HttpFoundation\Response | 441 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -446,8 +458,6 @@ class EntryController extends Controller | |||
446 | /** | 458 | /** |
447 | * Ability to view a content publicly. | 459 | * Ability to view a content publicly. |
448 | * | 460 | * |
449 | * @param Entry $entry | ||
450 | * | ||
451 | * @Route("/share/{uid}", requirements={"uid" = ".+"}, name="share_entry") | 461 | * @Route("/share/{uid}", requirements={"uid" = ".+"}, name="share_entry") |
452 | * @Cache(maxage="25200", smaxage="25200", public=true) | 462 | * @Cache(maxage="25200", smaxage="25200", public=true) |
453 | * | 463 | * |
@@ -466,60 +476,11 @@ class EntryController extends Controller | |||
466 | } | 476 | } |
467 | 477 | ||
468 | /** | 478 | /** |
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 | 479 | * Global method to retrieve entries depending on the given type |
518 | * It returns the response to be send. | 480 | * It returns the response to be send. |
519 | * | 481 | * |
520 | * @param string $type Entries type: unread, starred or archive | 482 | * @param string $type Entries type: unread, starred or archive |
521 | * @param Request $request | 483 | * @param int $page |
522 | * @param int $page | ||
523 | * | 484 | * |
524 | * @return \Symfony\Component\HttpFoundation\Response | 485 | * @return \Symfony\Component\HttpFoundation\Response |
525 | */ | 486 | */ |
@@ -532,11 +493,9 @@ class EntryController extends Controller | |||
532 | switch ($type) { | 493 | switch ($type) { |
533 | case 'search': | 494 | case 'search': |
534 | $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute); | 495 | $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute); |
535 | |||
536 | break; | 496 | break; |
537 | case 'untagged': | 497 | case 'untagged': |
538 | $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); | 498 | $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); |
539 | |||
540 | break; | 499 | break; |
541 | case 'starred': | 500 | case 'starred': |
542 | $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); | 501 | $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); |
@@ -576,6 +535,9 @@ class EntryController extends Controller | |||
576 | } | 535 | } |
577 | } | 536 | } |
578 | 537 | ||
538 | $nbEntriesUntagged = $this->get('wallabag_core.entry_repository') | ||
539 | ->countUntaggedEntriesByUser($this->getUser()->getId()); | ||
540 | |||
579 | return $this->render( | 541 | return $this->render( |
580 | 'WallabagCoreBundle:Entry:entries.html.twig', [ | 542 | 'WallabagCoreBundle:Entry:entries.html.twig', [ |
581 | 'form' => $form->createView(), | 543 | 'form' => $form->createView(), |
@@ -583,14 +545,45 @@ class EntryController extends Controller | |||
583 | 'currentPage' => $page, | 545 | 'currentPage' => $page, |
584 | 'searchTerm' => $searchTerm, | 546 | 'searchTerm' => $searchTerm, |
585 | 'isFiltered' => $form->isSubmitted(), | 547 | 'isFiltered' => $form->isSubmitted(), |
548 | 'nbEntriesUntagged' => $nbEntriesUntagged, | ||
586 | ] | 549 | ] |
587 | ); | 550 | ); |
588 | } | 551 | } |
589 | 552 | ||
590 | /** | 553 | /** |
591 | * Check if the logged user can manage the given entry. | 554 | * Fetch content and update entry. |
555 | * In case it fails, $entry->getContent will return an error message. | ||
592 | * | 556 | * |
593 | * @param Entry $entry | 557 | * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded |
558 | */ | ||
559 | private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') | ||
560 | { | ||
561 | $message = 'flashes.entry.notice.' . $prefixMessage; | ||
562 | |||
563 | try { | ||
564 | $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); | ||
565 | } catch (\Exception $e) { | ||
566 | $this->get('logger')->error('Error while saving an entry', [ | ||
567 | 'exception' => $e, | ||
568 | 'entry' => $entry, | ||
569 | ]); | ||
570 | |||
571 | $message = 'flashes.entry.notice.' . $prefixMessage . '_failed'; | ||
572 | } | ||
573 | |||
574 | if (empty($entry->getDomainName())) { | ||
575 | $this->get('wallabag_core.content_proxy')->setEntryDomainName($entry); | ||
576 | } | ||
577 | |||
578 | if (empty($entry->getTitle())) { | ||
579 | $this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry); | ||
580 | } | ||
581 | |||
582 | $this->get('session')->getFlashBag()->add('notice', $message); | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * Check if the logged user can manage the given entry. | ||
594 | */ | 587 | */ |
595 | private function checkUserAction(Entry $entry) | 588 | private function checkUserAction(Entry $entry) |
596 | { | 589 | { |
@@ -602,8 +595,6 @@ class EntryController extends Controller | |||
602 | /** | 595 | /** |
603 | * Check for existing entry, if it exists, redirect to it with a message. | 596 | * Check for existing entry, if it exists, redirect to it with a message. |
604 | * | 597 | * |
605 | * @param Entry $entry | ||
606 | * | ||
607 | * @return Entry|bool | 598 | * @return Entry|bool |
608 | */ | 599 | */ |
609 | private function checkIfEntryAlreadyExists(Entry $entry) | 600 | private function checkIfEntryAlreadyExists(Entry $entry) |
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php index 7ca89239..282fd733 100644 --- a/src/Wallabag/CoreBundle/Controller/ExportController.php +++ b/src/Wallabag/CoreBundle/Controller/ExportController.php | |||
@@ -2,10 +2,10 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | 7 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
8 | use Symfony\Component\Routing\Annotation\Route; | ||
9 | use Wallabag\CoreBundle\Entity\Entry; | 9 | use Wallabag\CoreBundle\Entity\Entry; |
10 | 10 | ||
11 | /** | 11 | /** |
@@ -17,7 +17,6 @@ class ExportController extends Controller | |||
17 | /** | 17 | /** |
18 | * Gets one entry content. | 18 | * Gets one entry content. |
19 | * | 19 | * |
20 | * @param Entry $entry | ||
21 | * @param string $format | 20 | * @param string $format |
22 | * | 21 | * |
23 | * @Route("/export/{id}.{format}", name="export_entry", requirements={ | 22 | * @Route("/export/{id}.{format}", name="export_entry", requirements={ |
@@ -58,6 +57,7 @@ class ExportController extends Controller | |||
58 | $method = ucfirst($category); | 57 | $method = ucfirst($category); |
59 | $methodBuilder = 'getBuilderFor' . $method . 'ByUser'; | 58 | $methodBuilder = 'getBuilderFor' . $method . 'ByUser'; |
60 | $repository = $this->get('wallabag_core.entry_repository'); | 59 | $repository = $this->get('wallabag_core.entry_repository'); |
60 | $title = $method; | ||
61 | 61 | ||
62 | if ('tag_entries' === $category) { | 62 | if ('tag_entries' === $category) { |
63 | $tag = $this->get('wallabag_core.tag_repository')->findOneBySlug($request->query->get('tag')); | 63 | $tag = $this->get('wallabag_core.tag_repository')->findOneBySlug($request->query->get('tag')); |
@@ -66,6 +66,8 @@ class ExportController extends Controller | |||
66 | $this->getUser()->getId(), | 66 | $this->getUser()->getId(), |
67 | $tag->getId() | 67 | $tag->getId() |
68 | ); | 68 | ); |
69 | |||
70 | $title = 'Tag ' . $tag->getLabel(); | ||
69 | } else { | 71 | } else { |
70 | $entries = $repository | 72 | $entries = $repository |
71 | ->$methodBuilder($this->getUser()->getId()) | 73 | ->$methodBuilder($this->getUser()->getId()) |
@@ -76,7 +78,7 @@ class ExportController extends Controller | |||
76 | try { | 78 | try { |
77 | return $this->get('wallabag_core.helper.entries_export') | 79 | return $this->get('wallabag_core.helper.entries_export') |
78 | ->setEntries($entries) | 80 | ->setEntries($entries) |
79 | ->updateTitle($method) | 81 | ->updateTitle($title) |
80 | ->updateAuthor($method) | 82 | ->updateAuthor($method) |
81 | ->exportAs($format); | 83 | ->exportAs($format); |
82 | } catch (\InvalidArgumentException $e) { | 84 | } catch (\InvalidArgumentException $e) { |
diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/FeedController.php index 848bb814..95c3427b 100644 --- a/src/Wallabag/CoreBundle/Controller/RssController.php +++ b/src/Wallabag/CoreBundle/Controller/FeedController.php | |||
@@ -7,86 +7,94 @@ use Pagerfanta\Adapter\DoctrineORMAdapter; | |||
7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
8 | use Pagerfanta\Pagerfanta; | 8 | use Pagerfanta\Pagerfanta; |
9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
11 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 10 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
12 | use Symfony\Component\HttpFoundation\Request; | ||
13 | use Symfony\Component\HttpFoundation\Response; | 11 | use Symfony\Component\HttpFoundation\Response; |
12 | use Symfony\Component\Routing\Annotation\Route; | ||
14 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 13 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
15 | use Wallabag\CoreBundle\Entity\Tag; | 14 | use Wallabag\CoreBundle\Entity\Tag; |
16 | use Wallabag\UserBundle\Entity\User; | 15 | use Wallabag\UserBundle\Entity\User; |
17 | 16 | ||
18 | class RssController extends Controller | 17 | class FeedController extends Controller |
19 | { | 18 | { |
20 | /** | 19 | /** |
21 | * Shows unread entries for current user. | 20 | * Shows unread entries for current user. |
22 | * | 21 | * |
23 | * @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"}) | 22 | * @Route("/feed/{username}/{token}/unread/{page}", name="unread_feed", defaults={"page"=1, "_format"="xml"}) |
24 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 23 | * |
24 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
25 | * | ||
26 | * @param $page | ||
25 | * | 27 | * |
26 | * @return \Symfony\Component\HttpFoundation\Response | 28 | * @return \Symfony\Component\HttpFoundation\Response |
27 | */ | 29 | */ |
28 | public function showUnreadRSSAction(Request $request, User $user) | 30 | public function showUnreadFeedAction(User $user, $page) |
29 | { | 31 | { |
30 | return $this->showEntries('unread', $user, $request->query->get('page', 1)); | 32 | return $this->showEntries('unread', $user, $page); |
31 | } | 33 | } |
32 | 34 | ||
33 | /** | 35 | /** |
34 | * Shows read entries for current user. | 36 | * Shows read entries for current user. |
35 | * | 37 | * |
36 | * @Route("/{username}/{token}/archive.xml", name="archive_rss", defaults={"_format"="xml"}) | 38 | * @Route("/feed/{username}/{token}/archive/{page}", name="archive_feed", defaults={"page"=1, "_format"="xml"}) |
37 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 39 | * |
40 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
41 | * | ||
42 | * @param $page | ||
38 | * | 43 | * |
39 | * @return \Symfony\Component\HttpFoundation\Response | 44 | * @return \Symfony\Component\HttpFoundation\Response |
40 | */ | 45 | */ |
41 | public function showArchiveRSSAction(Request $request, User $user) | 46 | public function showArchiveFeedAction(User $user, $page) |
42 | { | 47 | { |
43 | return $this->showEntries('archive', $user, $request->query->get('page', 1)); | 48 | return $this->showEntries('archive', $user, $page); |
44 | } | 49 | } |
45 | 50 | ||
46 | /** | 51 | /** |
47 | * Shows starred entries for current user. | 52 | * Shows starred entries for current user. |
48 | * | 53 | * |
49 | * @Route("/{username}/{token}/starred.xml", name="starred_rss", defaults={"_format"="xml"}) | 54 | * @Route("/feed/{username}/{token}/starred/{page}", name="starred_feed", defaults={"page"=1, "_format"="xml"}) |
50 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 55 | * |
56 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
57 | * | ||
58 | * @param $page | ||
51 | * | 59 | * |
52 | * @return \Symfony\Component\HttpFoundation\Response | 60 | * @return \Symfony\Component\HttpFoundation\Response |
53 | */ | 61 | */ |
54 | public function showStarredRSSAction(Request $request, User $user) | 62 | public function showStarredFeedAction(User $user, $page) |
55 | { | 63 | { |
56 | return $this->showEntries('starred', $user, $request->query->get('page', 1)); | 64 | return $this->showEntries('starred', $user, $page); |
57 | } | 65 | } |
58 | 66 | ||
59 | /** | 67 | /** |
60 | * Shows all entries for current user. | 68 | * Shows all entries for current user. |
61 | * | 69 | * |
62 | * @Route("/{username}/{token}/all.xml", name="all_rss", defaults={"_format"="xml"}) | 70 | * @Route("/feed/{username}/{token}/all/{page}", name="all_feed", defaults={"page"=1, "_format"="xml"}) |
63 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 71 | * |
72 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
64 | * | 73 | * |
65 | * @return \Symfony\Component\HttpFoundation\Response | 74 | * @return \Symfony\Component\HttpFoundation\Response |
66 | */ | 75 | */ |
67 | public function showAllRSSAction(Request $request, User $user) | 76 | public function showAllFeedAction(User $user, $page) |
68 | { | 77 | { |
69 | return $this->showEntries('all', $user, $request->query->get('page', 1)); | 78 | return $this->showEntries('all', $user, $page); |
70 | } | 79 | } |
71 | 80 | ||
72 | /** | 81 | /** |
73 | * Shows entries associated to a tag for current user. | 82 | * Shows entries associated to a tag for current user. |
74 | * | 83 | * |
75 | * @Route("/{username}/{token}/tags/{slug}.xml", name="tag_rss", defaults={"_format"="xml"}) | 84 | * @Route("/feed/{username}/{token}/tags/{slug}/{page}", name="tag_feed", defaults={"page"=1, "_format"="xml"}) |
76 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 85 | * |
86 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
77 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) | 87 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) |
78 | * | 88 | * |
79 | * @return \Symfony\Component\HttpFoundation\Response | 89 | * @return \Symfony\Component\HttpFoundation\Response |
80 | */ | 90 | */ |
81 | public function showTagsAction(Request $request, User $user, Tag $tag) | 91 | public function showTagsFeedAction(User $user, Tag $tag, $page) |
82 | { | 92 | { |
83 | $page = $request->query->get('page', 1); | ||
84 | |||
85 | $url = $this->generateUrl( | 93 | $url = $this->generateUrl( |
86 | 'tag_rss', | 94 | 'tag_feed', |
87 | [ | 95 | [ |
88 | 'username' => $user->getUsername(), | 96 | 'username' => $user->getUsername(), |
89 | 'token' => $user->getConfig()->getRssToken(), | 97 | 'token' => $user->getConfig()->getFeedToken(), |
90 | 'slug' => $tag->getSlug(), | 98 | 'slug' => $tag->getSlug(), |
91 | ], | 99 | ], |
92 | UrlGeneratorInterface::ABSOLUTE_URL | 100 | UrlGeneratorInterface::ABSOLUTE_URL |
@@ -119,12 +127,15 @@ class RssController extends Controller | |||
119 | return $this->render( | 127 | return $this->render( |
120 | '@WallabagCore/themes/common/Entry/entries.xml.twig', | 128 | '@WallabagCore/themes/common/Entry/entries.xml.twig', |
121 | [ | 129 | [ |
122 | 'url_html' => $this->generateUrl('tag_entries', ['slug' => $tag->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL), | 130 | 'type' => 'tag', |
123 | 'type' => 'tag (' . $tag->getLabel() . ')', | ||
124 | 'url' => $url, | 131 | 'url' => $url, |
125 | 'entries' => $entries, | 132 | 'entries' => $entries, |
133 | 'user' => $user->getUsername(), | ||
134 | 'domainName' => $this->getParameter('domain_name'), | ||
135 | 'version' => $this->getParameter('wallabag_core.version'), | ||
136 | 'tag' => $tag->getSlug(), | ||
126 | ], | 137 | ], |
127 | new Response('', 200, ['Content-Type' => 'application/rss+xml']) | 138 | new Response('', 200, ['Content-Type' => 'application/atom+xml']) |
128 | ); | 139 | ); |
129 | } | 140 | } |
130 | 141 | ||
@@ -133,7 +144,6 @@ class RssController extends Controller | |||
133 | * It returns the response to be send. | 144 | * It returns the response to be send. |
134 | * | 145 | * |
135 | * @param string $type Entries type: unread, starred or archive | 146 | * @param string $type Entries type: unread, starred or archive |
136 | * @param User $user | ||
137 | * @param int $page | 147 | * @param int $page |
138 | * | 148 | * |
139 | * @return \Symfony\Component\HttpFoundation\Response | 149 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -162,14 +172,14 @@ class RssController extends Controller | |||
162 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); | 172 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); |
163 | $entries = new Pagerfanta($pagerAdapter); | 173 | $entries = new Pagerfanta($pagerAdapter); |
164 | 174 | ||
165 | $perPage = $user->getConfig()->getRssLimit() ?: $this->getParameter('wallabag_core.rss_limit'); | 175 | $perPage = $user->getConfig()->getFeedLimit() ?: $this->getParameter('wallabag_core.feed_limit'); |
166 | $entries->setMaxPerPage($perPage); | 176 | $entries->setMaxPerPage($perPage); |
167 | 177 | ||
168 | $url = $this->generateUrl( | 178 | $url = $this->generateUrl( |
169 | $type . '_rss', | 179 | $type . '_feed', |
170 | [ | 180 | [ |
171 | 'username' => $user->getUsername(), | 181 | 'username' => $user->getUsername(), |
172 | 'token' => $user->getConfig()->getRssToken(), | 182 | 'token' => $user->getConfig()->getFeedToken(), |
173 | ], | 183 | ], |
174 | UrlGeneratorInterface::ABSOLUTE_URL | 184 | UrlGeneratorInterface::ABSOLUTE_URL |
175 | ); | 185 | ); |
@@ -178,19 +188,19 @@ class RssController extends Controller | |||
178 | $entries->setCurrentPage((int) $page); | 188 | $entries->setCurrentPage((int) $page); |
179 | } catch (OutOfRangeCurrentPageException $e) { | 189 | } catch (OutOfRangeCurrentPageException $e) { |
180 | if ($page > 1) { | 190 | if ($page > 1) { |
181 | return $this->redirect($url . '?page=' . $entries->getNbPages(), 302); | 191 | return $this->redirect($url . '/' . $entries->getNbPages()); |
182 | } | 192 | } |
183 | } | 193 | } |
184 | 194 | ||
185 | return $this->render( | 195 | return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [ |
186 | '@WallabagCore/themes/common/Entry/entries.xml.twig', | 196 | 'type' => $type, |
187 | [ | 197 | 'url' => $url, |
188 | 'url_html' => $this->generateUrl($type, [], UrlGeneratorInterface::ABSOLUTE_URL), | 198 | 'entries' => $entries, |
189 | 'type' => $type, | 199 | 'user' => $user->getUsername(), |
190 | 'url' => $url, | 200 | 'domainName' => $this->getParameter('domain_name'), |
191 | 'entries' => $entries, | 201 | 'version' => $this->getParameter('wallabag_core.version'), |
192 | ], | 202 | ], |
193 | new Response('', 200, ['Content-Type' => 'application/rss+xml']) | 203 | new Response('', 200, ['Content-Type' => 'application/atom+xml']) |
194 | ); | 204 | ); |
195 | } | 205 | } |
196 | } | 206 | } |
diff --git a/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php b/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php index 548de744..4320c5ff 100644 --- a/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php +++ b/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php | |||
@@ -2,10 +2,9 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | ||
6 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
7 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
8 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
7 | use Symfony\Component\Routing\Annotation\Route; | ||
9 | use Wallabag\CoreBundle\Entity\SiteCredential; | 8 | use Wallabag\CoreBundle\Entity\SiteCredential; |
10 | use Wallabag\UserBundle\Entity\User; | 9 | use 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,10 +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 | * | ||
42 | * @param Request $request | ||
43 | * | 38 | * |
44 | * @return \Symfony\Component\HttpFoundation\Response | 39 | * @return \Symfony\Component\HttpFoundation\Response |
45 | */ | 40 | */ |
@@ -77,11 +72,7 @@ class SiteCredentialController extends Controller | |||
77 | /** | 72 | /** |
78 | * Displays a form to edit an existing site credential entity. | 73 | * Displays a form to edit an existing site credential entity. |
79 | * | 74 | * |
80 | * @Route("/{id}/edit", name="site_credentials_edit") | 75 | * @Route("/{id}/edit", name="site_credentials_edit", methods={"GET", "POST"}) |
81 | * @Method({"GET", "POST"}) | ||
82 | * | ||
83 | * @param Request $request | ||
84 | * @param SiteCredential $siteCredential | ||
85 | * | 76 | * |
86 | * @return \Symfony\Component\HttpFoundation\Response | 77 | * @return \Symfony\Component\HttpFoundation\Response |
87 | */ | 78 | */ |
@@ -121,11 +112,7 @@ class SiteCredentialController extends Controller | |||
121 | /** | 112 | /** |
122 | * Deletes a site credential entity. | 113 | * Deletes a site credential entity. |
123 | * | 114 | * |
124 | * @Route("/{id}", name="site_credentials_delete") | 115 | * @Route("/{id}", name="site_credentials_delete", methods={"DELETE"}) |
125 | * @Method("DELETE") | ||
126 | * | ||
127 | * @param Request $request | ||
128 | * @param SiteCredential $siteCredential | ||
129 | * | 116 | * |
130 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 117 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
131 | */ | 118 | */ |
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 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class StaticController extends Controller | 8 | class StaticController extends Controller |
9 | { | 9 | { |
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php index b6d28e59..a6ad131f 100644 --- a/src/Wallabag/CoreBundle/Controller/TagController.php +++ b/src/Wallabag/CoreBundle/Controller/TagController.php | |||
@@ -5,19 +5,17 @@ namespace Wallabag\CoreBundle\Controller; | |||
5 | use Pagerfanta\Adapter\ArrayAdapter; | 5 | use Pagerfanta\Adapter\ArrayAdapter; |
6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
9 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
10 | use Symfony\Component\HttpFoundation\Request; | 9 | use Symfony\Component\HttpFoundation\Request; |
10 | use Symfony\Component\Routing\Annotation\Route; | ||
11 | use Wallabag\CoreBundle\Entity\Entry; | 11 | use Wallabag\CoreBundle\Entity\Entry; |
12 | use Wallabag\CoreBundle\Entity\Tag; | 12 | use Wallabag\CoreBundle\Entity\Tag; |
13 | use Wallabag\CoreBundle\Form\Type\NewTagType; | 13 | use Wallabag\CoreBundle\Form\Type\NewTagType; |
14 | use Wallabag\CoreBundle\Form\Type\RenameTagType; | ||
14 | 15 | ||
15 | class TagController extends Controller | 16 | class TagController extends Controller |
16 | { | 17 | { |
17 | /** | 18 | /** |
18 | * @param Request $request | ||
19 | * @param Entry $entry | ||
20 | * | ||
21 | * @Route("/new-tag/{entry}", requirements={"entry" = "\d+"}, name="new_tag") | 19 | * @Route("/new-tag/{entry}", requirements={"entry" = "\d+"}, name="new_tag") |
22 | * | 20 | * |
23 | * @return \Symfony\Component\HttpFoundation\Response | 21 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -86,14 +84,22 @@ class TagController extends Controller | |||
86 | { | 84 | { |
87 | $tags = $this->get('wallabag_core.tag_repository') | 85 | $tags = $this->get('wallabag_core.tag_repository') |
88 | ->findAllFlatTagsWithNbEntries($this->getUser()->getId()); | 86 | ->findAllFlatTagsWithNbEntries($this->getUser()->getId()); |
87 | $nbEntriesUntagged = $this->get('wallabag_core.entry_repository') | ||
88 | ->countUntaggedEntriesByUser($this->getUser()->getId()); | ||
89 | |||
90 | $renameForms = []; | ||
91 | foreach ($tags as $tag) { | ||
92 | $renameForms[$tag['id']] = $this->createForm(RenameTagType::class, new Tag())->createView(); | ||
93 | } | ||
89 | 94 | ||
90 | return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [ | 95 | return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [ |
91 | 'tags' => $tags, | 96 | 'tags' => $tags, |
97 | 'renameForms' => $renameForms, | ||
98 | 'nbEntriesUntagged' => $nbEntriesUntagged, | ||
92 | ]); | 99 | ]); |
93 | } | 100 | } |
94 | 101 | ||
95 | /** | 102 | /** |
96 | * @param Tag $tag | ||
97 | * @param int $page | 103 | * @param int $page |
98 | * | 104 | * |
99 | * @Route("/tag/list/{slug}/{page}", name="tag_entries", defaults={"page" = "1"}) | 105 | * @Route("/tag/list/{slug}/{page}", name="tag_entries", defaults={"page" = "1"}) |
@@ -130,4 +136,45 @@ class TagController extends Controller | |||
130 | 'tag' => $tag, | 136 | 'tag' => $tag, |
131 | ]); | 137 | ]); |
132 | } | 138 | } |
139 | |||
140 | /** | ||
141 | * Rename a given tag with a new label | ||
142 | * Create a new tag with the new name and drop the old one. | ||
143 | * | ||
144 | * @Route("/tag/rename/{slug}", name="tag_rename") | ||
145 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) | ||
146 | * | ||
147 | * @return \Symfony\Component\HttpFoundation\Response | ||
148 | */ | ||
149 | public function renameTagAction(Tag $tag, Request $request) | ||
150 | { | ||
151 | $form = $this->createForm(RenameTagType::class, new Tag()); | ||
152 | $form->handleRequest($request); | ||
153 | |||
154 | if ($form->isSubmitted() && $form->isValid()) { | ||
155 | $entries = $this->get('wallabag_core.entry_repository')->findAllByTagId( | ||
156 | $this->getUser()->getId(), | ||
157 | $tag->getId() | ||
158 | ); | ||
159 | foreach ($entries as $entry) { | ||
160 | $this->get('wallabag_core.tags_assigner')->assignTagsToEntry( | ||
161 | $entry, | ||
162 | $form->get('label')->getData() | ||
163 | ); | ||
164 | $entry->removeTag($tag); | ||
165 | } | ||
166 | |||
167 | $em = $this->getDoctrine()->getManager(); | ||
168 | $em->flush(); | ||
169 | } | ||
170 | |||
171 | $this->get('session')->getFlashBag()->add( | ||
172 | 'notice', | ||
173 | 'flashes.tag.notice.tag_renamed' | ||
174 | ); | ||
175 | |||
176 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'), '', true); | ||
177 | |||
178 | return $this->redirect($redirectUrl); | ||
179 | } | ||
133 | } | 180 | } |
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php b/src/Wallabag/CoreBundle/DataFixtures/ConfigFixtures.php index 3d4d5def..5e914965 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 | ||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | 3 | namespace Wallabag\CoreBundle\DataFixtures; |
4 | 4 | ||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | 5 | use Doctrine\Bundle\FixturesBundle\Fixture; |
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | 6 | use Doctrine\Common\DataFixtures\DependentFixtureInterface; |
7 | use Doctrine\Common\Persistence\ObjectManager; | 7 | use Doctrine\Common\Persistence\ObjectManager; |
8 | use Wallabag\CoreBundle\Entity\Config; | 8 | use Wallabag\CoreBundle\Entity\Config; |
9 | use Wallabag\UserBundle\DataFixtures\UserFixtures; | ||
9 | 10 | ||
10 | class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface | 11 | class ConfigFixtures extends Fixture implements DependentFixtureInterface |
11 | { | 12 | { |
12 | /** | 13 | /** |
13 | * {@inheritdoc} | 14 | * {@inheritdoc} |
@@ -18,7 +19,7 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface | |||
18 | 19 | ||
19 | $adminConfig->setTheme('material'); | 20 | $adminConfig->setTheme('material'); |
20 | $adminConfig->setItemsPerPage(30); | 21 | $adminConfig->setItemsPerPage(30); |
21 | $adminConfig->setReadingSpeed(1); | 22 | $adminConfig->setReadingSpeed(200); |
22 | $adminConfig->setLanguage('en'); | 23 | $adminConfig->setLanguage('en'); |
23 | $adminConfig->setPocketConsumerKey('xxxxx'); | 24 | $adminConfig->setPocketConsumerKey('xxxxx'); |
24 | $adminConfig->setActionMarkAsRead(0); | 25 | $adminConfig->setActionMarkAsRead(0); |
@@ -31,7 +32,7 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface | |||
31 | $bobConfig = new Config($this->getReference('bob-user')); | 32 | $bobConfig = new Config($this->getReference('bob-user')); |
32 | $bobConfig->setTheme('default'); | 33 | $bobConfig->setTheme('default'); |
33 | $bobConfig->setItemsPerPage(10); | 34 | $bobConfig->setItemsPerPage(10); |
34 | $bobConfig->setReadingSpeed(1); | 35 | $bobConfig->setReadingSpeed(200); |
35 | $bobConfig->setLanguage('fr'); | 36 | $bobConfig->setLanguage('fr'); |
36 | $bobConfig->setPocketConsumerKey(null); | 37 | $bobConfig->setPocketConsumerKey(null); |
37 | $bobConfig->setActionMarkAsRead(1); | 38 | $bobConfig->setActionMarkAsRead(1); |
@@ -44,7 +45,7 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface | |||
44 | $emptyConfig = new Config($this->getReference('empty-user')); | 45 | $emptyConfig = new Config($this->getReference('empty-user')); |
45 | $emptyConfig->setTheme('material'); | 46 | $emptyConfig->setTheme('material'); |
46 | $emptyConfig->setItemsPerPage(10); | 47 | $emptyConfig->setItemsPerPage(10); |
47 | $emptyConfig->setReadingSpeed(1); | 48 | $emptyConfig->setReadingSpeed(200); |
48 | $emptyConfig->setLanguage('en'); | 49 | $emptyConfig->setLanguage('en'); |
49 | $emptyConfig->setPocketConsumerKey(null); | 50 | $emptyConfig->setPocketConsumerKey(null); |
50 | $emptyConfig->setActionMarkAsRead(0); | 51 | $emptyConfig->setActionMarkAsRead(0); |
@@ -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/EntryFixtures.php b/src/Wallabag/CoreBundle/DataFixtures/EntryFixtures.php new file mode 100644 index 00000000..024fcfdc --- /dev/null +++ b/src/Wallabag/CoreBundle/DataFixtures/EntryFixtures.php | |||
@@ -0,0 +1,138 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DataFixtures; | ||
4 | |||
5 | use Doctrine\Bundle\FixturesBundle\Fixture; | ||
6 | use Doctrine\Common\DataFixtures\DependentFixtureInterface; | ||
7 | use Doctrine\Common\Persistence\ObjectManager; | ||
8 | use Wallabag\CoreBundle\Entity\Entry; | ||
9 | use Wallabag\UserBundle\DataFixtures\UserFixtures; | ||
10 | |||
11 | class EntryFixtures extends Fixture implements DependentFixtureInterface | ||
12 | { | ||
13 | /** | ||
14 | * {@inheritdoc} | ||
15 | */ | ||
16 | public function load(ObjectManager $manager) | ||
17 | { | ||
18 | $entries = [ | ||
19 | 'entry1' => [ | ||
20 | 'user' => 'admin-user', | ||
21 | 'url' => 'http://0.0.0.0/entry1', | ||
22 | 'reading_time' => 11, | ||
23 | 'domain' => 'domain.io', | ||
24 | 'mime' => 'text/html', | ||
25 | 'title' => 'test title entry1', | ||
26 | 'content' => 'This is my content /o/', | ||
27 | 'language' => 'en', | ||
28 | 'tags' => ['foo-tag', 'baz-tag'], | ||
29 | ], | ||
30 | 'entry2' => [ | ||
31 | 'user' => 'admin-user', | ||
32 | 'url' => 'http://0.0.0.0/entry2', | ||
33 | 'reading_time' => 1, | ||
34 | 'domain' => 'domain.io', | ||
35 | 'mime' => 'text/html', | ||
36 | 'title' => 'test title entry2', | ||
37 | 'content' => 'This is my content /o/', | ||
38 | 'origin' => 'ftp://oneftp.tld', | ||
39 | 'language' => 'fr', | ||
40 | ], | ||
41 | 'entry3' => [ | ||
42 | 'user' => 'bob-user', | ||
43 | 'url' => 'http://0.0.0.0/entry3', | ||
44 | 'reading_time' => 1, | ||
45 | 'domain' => 'domain.io', | ||
46 | 'mime' => 'text/html', | ||
47 | 'title' => 'test title entry3', | ||
48 | 'content' => 'This is my content /o/', | ||
49 | 'language' => 'en', | ||
50 | 'tags' => ['foo-tag', 'bar-tag', 'bob-tag'], | ||
51 | ], | ||
52 | 'entry4' => [ | ||
53 | 'user' => 'admin-user', | ||
54 | 'url' => 'http://0.0.0.0/entry4', | ||
55 | 'reading_time' => 12, | ||
56 | 'domain' => 'domain.io', | ||
57 | 'mime' => 'text/html', | ||
58 | 'title' => 'test title entry4', | ||
59 | 'content' => 'This is my content /o/', | ||
60 | 'language' => 'en', | ||
61 | 'tags' => ['foo-tag', 'bar-tag'], | ||
62 | ], | ||
63 | 'entry5' => [ | ||
64 | 'user' => 'admin-user', | ||
65 | 'url' => 'http://0.0.0.0/entry5', | ||
66 | 'reading_time' => 12, | ||
67 | 'domain' => 'domain.io', | ||
68 | 'mime' => 'text/html', | ||
69 | 'title' => 'test title entry5', | ||
70 | 'content' => 'This is my content /o/', | ||
71 | 'language' => 'fr', | ||
72 | 'starred' => true, | ||
73 | 'preview' => 'http://0.0.0.0/image.jpg', | ||
74 | ], | ||
75 | 'entry6' => [ | ||
76 | 'user' => 'admin-user', | ||
77 | 'url' => 'http://0.0.0.0/entry6', | ||
78 | 'reading_time' => 12, | ||
79 | 'domain' => 'domain.io', | ||
80 | 'mime' => 'text/html', | ||
81 | 'title' => 'test title entry6', | ||
82 | 'content' => 'This is my content /o/', | ||
83 | 'language' => 'de', | ||
84 | 'archived' => true, | ||
85 | 'tags' => ['bar-tag'], | ||
86 | ], | ||
87 | ]; | ||
88 | |||
89 | foreach ($entries as $reference => $item) { | ||
90 | $entry = new Entry($this->getReference($item['user'])); | ||
91 | $entry->setUrl($item['url']); | ||
92 | $entry->setReadingTime($item['reading_time']); | ||
93 | $entry->setDomainName($item['domain']); | ||
94 | $entry->setMimetype($item['mime']); | ||
95 | $entry->setTitle($item['title']); | ||
96 | $entry->setContent($item['content']); | ||
97 | $entry->setLanguage($item['language']); | ||
98 | |||
99 | if (isset($item['tags'])) { | ||
100 | foreach ($item['tags'] as $tag) { | ||
101 | $entry->addTag($this->getReference($tag)); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | if (isset($item['origin'])) { | ||
106 | $entry->setOriginUrl($item['origin']); | ||
107 | } | ||
108 | |||
109 | if (isset($item['starred'])) { | ||
110 | $entry->setStarred($item['starred']); | ||
111 | } | ||
112 | |||
113 | if (isset($item['archived'])) { | ||
114 | $entry->setArchived($item['archived']); | ||
115 | } | ||
116 | |||
117 | if (isset($item['preview'])) { | ||
118 | $entry->setPreviewPicture($item['preview']); | ||
119 | } | ||
120 | |||
121 | $manager->persist($entry); | ||
122 | $this->addReference($reference, $entry); | ||
123 | } | ||
124 | |||
125 | $manager->flush(); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * {@inheritdoc} | ||
130 | */ | ||
131 | public function getDependencies() | ||
132 | { | ||
133 | return [ | ||
134 | UserFixtures::class, | ||
135 | TagFixtures::class, | ||
136 | ]; | ||
137 | } | ||
138 | } | ||
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php b/src/Wallabag/CoreBundle/DataFixtures/InternalSettingFixtures.php index 3fe88e7f..b052d1d5 100644 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php +++ b/src/Wallabag/CoreBundle/DataFixtures/InternalSettingFixtures.php | |||
@@ -1,15 +1,14 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | 3 | namespace Wallabag\CoreBundle\DataFixtures; |
4 | 4 | ||
5 | use Craue\ConfigBundle\Entity\Setting; | 5 | use Doctrine\Bundle\FixturesBundle\Fixture; |
6 | use Doctrine\Common\DataFixtures\AbstractFixture; | ||
7 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | ||
8 | use Doctrine\Common\Persistence\ObjectManager; | 6 | use Doctrine\Common\Persistence\ObjectManager; |
9 | use Symfony\Component\DependencyInjection\ContainerAwareInterface; | 7 | use Symfony\Component\DependencyInjection\ContainerAwareInterface; |
10 | use Symfony\Component\DependencyInjection\ContainerInterface; | 8 | use Symfony\Component\DependencyInjection\ContainerInterface; |
9 | use Wallabag\CoreBundle\Entity\InternalSetting; | ||
11 | 10 | ||
12 | class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface | 11 | class InternalSettingFixtures extends Fixture implements ContainerAwareInterface |
13 | { | 12 | { |
14 | /** | 13 | /** |
15 | * @var ContainerInterface | 14 | * @var ContainerInterface |
@@ -27,7 +26,7 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface | |||
27 | public function load(ObjectManager $manager) | 26 | public function load(ObjectManager $manager) |
28 | { | 27 | { |
29 | foreach ($this->container->getParameter('wallabag_core.default_internal_settings') as $setting) { | 28 | foreach ($this->container->getParameter('wallabag_core.default_internal_settings') as $setting) { |
30 | $newSetting = new Setting(); | 29 | $newSetting = new InternalSetting(); |
31 | $newSetting->setName($setting['name']); | 30 | $newSetting->setName($setting['name']); |
32 | $newSetting->setValue($setting['value']); | 31 | $newSetting->setValue($setting['value']); |
33 | $newSetting->setSection($setting['section']); | 32 | $newSetting->setSection($setting['section']); |
@@ -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/LoadEntryData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php deleted file mode 100644 index 0e1510a2..00000000 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php +++ /dev/null | |||
@@ -1,119 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | ||
4 | |||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | ||
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | ||
7 | use Doctrine\Common\Persistence\ObjectManager; | ||
8 | use Wallabag\CoreBundle\Entity\Entry; | ||
9 | |||
10 | class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface | ||
11 | { | ||
12 | /** | ||
13 | * {@inheritdoc} | ||
14 | */ | ||
15 | public function load(ObjectManager $manager) | ||
16 | { | ||
17 | $entry1 = new Entry($this->getReference('admin-user')); | ||
18 | $entry1->setUrl('http://0.0.0.0/entry1'); | ||
19 | $entry1->setReadingTime(11); | ||
20 | $entry1->setDomainName('domain.io'); | ||
21 | $entry1->setMimetype('text/html'); | ||
22 | $entry1->setTitle('test title entry1'); | ||
23 | $entry1->setContent('This is my content /o/'); | ||
24 | $entry1->setLanguage('en'); | ||
25 | |||
26 | $entry1->addTag($this->getReference('foo-tag')); | ||
27 | $entry1->addTag($this->getReference('baz-tag')); | ||
28 | |||
29 | $manager->persist($entry1); | ||
30 | |||
31 | $this->addReference('entry1', $entry1); | ||
32 | |||
33 | $entry2 = new Entry($this->getReference('admin-user')); | ||
34 | $entry2->setUrl('http://0.0.0.0/entry2'); | ||
35 | $entry2->setReadingTime(1); | ||
36 | $entry2->setDomainName('domain.io'); | ||
37 | $entry2->setMimetype('text/html'); | ||
38 | $entry2->setTitle('test title entry2'); | ||
39 | $entry2->setContent('This is my content /o/'); | ||
40 | $entry2->setOriginUrl('ftp://oneftp.tld'); | ||
41 | $entry2->setLanguage('fr'); | ||
42 | |||
43 | $manager->persist($entry2); | ||
44 | |||
45 | $this->addReference('entry2', $entry2); | ||
46 | |||
47 | $entry3 = new Entry($this->getReference('bob-user')); | ||
48 | $entry3->setUrl('http://0.0.0.0/entry3'); | ||
49 | $entry3->setReadingTime(1); | ||
50 | $entry3->setDomainName('domain.io'); | ||
51 | $entry3->setMimetype('text/html'); | ||
52 | $entry3->setTitle('test title entry3'); | ||
53 | $entry3->setContent('This is my content /o/'); | ||
54 | $entry3->setLanguage('en'); | ||
55 | |||
56 | $entry3->addTag($this->getReference('foo-tag')); | ||
57 | $entry3->addTag($this->getReference('bar-tag')); | ||
58 | |||
59 | $manager->persist($entry3); | ||
60 | |||
61 | $this->addReference('entry3', $entry3); | ||
62 | |||
63 | $entry4 = new Entry($this->getReference('admin-user')); | ||
64 | $entry4->setUrl('http://0.0.0.0/entry4'); | ||
65 | $entry4->setReadingTime(12); | ||
66 | $entry4->setDomainName('domain.io'); | ||
67 | $entry4->setMimetype('text/html'); | ||
68 | $entry4->setTitle('test title entry4'); | ||
69 | $entry4->setContent('This is my content /o/'); | ||
70 | $entry4->setLanguage('en'); | ||
71 | |||
72 | $entry4->addTag($this->getReference('foo-tag')); | ||
73 | $entry4->addTag($this->getReference('bar-tag')); | ||
74 | |||
75 | $manager->persist($entry4); | ||
76 | |||
77 | $this->addReference('entry4', $entry4); | ||
78 | |||
79 | $entry5 = new Entry($this->getReference('admin-user')); | ||
80 | $entry5->setUrl('http://0.0.0.0/entry5'); | ||
81 | $entry5->setReadingTime(12); | ||
82 | $entry5->setDomainName('domain.io'); | ||
83 | $entry5->setMimetype('text/html'); | ||
84 | $entry5->setTitle('test title entry5'); | ||
85 | $entry5->setContent('This is my content /o/'); | ||
86 | $entry5->setStarred(true); | ||
87 | $entry5->setLanguage('fr'); | ||
88 | $entry5->setPreviewPicture('http://0.0.0.0/image.jpg'); | ||
89 | |||
90 | $manager->persist($entry5); | ||
91 | |||
92 | $this->addReference('entry5', $entry5); | ||
93 | |||
94 | $entry6 = new Entry($this->getReference('admin-user')); | ||
95 | $entry6->setUrl('http://0.0.0.0/entry6'); | ||
96 | $entry6->setReadingTime(12); | ||
97 | $entry6->setDomainName('domain.io'); | ||
98 | $entry6->setMimetype('text/html'); | ||
99 | $entry6->setTitle('test title entry6'); | ||
100 | $entry6->setContent('This is my content /o/'); | ||
101 | $entry6->setArchived(true); | ||
102 | $entry6->setLanguage('de'); | ||
103 | $entry6->addTag($this->getReference('bar-tag')); | ||
104 | |||
105 | $manager->persist($entry6); | ||
106 | |||
107 | $this->addReference('entry6', $entry6); | ||
108 | |||
109 | $manager->flush(); | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * {@inheritdoc} | ||
114 | */ | ||
115 | public function getOrder() | ||
116 | { | ||
117 | return 30; | ||
118 | } | ||
119 | } | ||
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSiteCredentialData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSiteCredentialData.php deleted file mode 100644 index 866f55a4..00000000 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSiteCredentialData.php +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | ||
4 | |||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | ||
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | ||
7 | use Doctrine\Common\Persistence\ObjectManager; | ||
8 | use Wallabag\CoreBundle\Entity\SiteCredential; | ||
9 | |||
10 | class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureInterface | ||
11 | { | ||
12 | /** | ||
13 | * {@inheritdoc} | ||
14 | */ | ||
15 | public function load(ObjectManager $manager) | ||
16 | { | ||
17 | $credential = new SiteCredential($this->getReference('admin-user')); | ||
18 | $credential->setHost('example.com'); | ||
19 | $credential->setUsername('foo'); | ||
20 | $credential->setPassword('bar'); | ||
21 | |||
22 | $manager->persist($credential); | ||
23 | |||
24 | $manager->flush(); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * {@inheritdoc} | ||
29 | */ | ||
30 | public function getOrder() | ||
31 | { | ||
32 | return 50; | ||
33 | } | ||
34 | } | ||
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php deleted file mode 100644 index 0ecfd18b..00000000 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | ||
4 | |||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | ||
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | ||
7 | use Doctrine\Common\Persistence\ObjectManager; | ||
8 | use Wallabag\CoreBundle\Entity\Tag; | ||
9 | |||
10 | class LoadTagData extends AbstractFixture implements OrderedFixtureInterface | ||
11 | { | ||
12 | /** | ||
13 | * {@inheritdoc} | ||
14 | */ | ||
15 | public function load(ObjectManager $manager) | ||
16 | { | ||
17 | $tag1 = new Tag(); | ||
18 | $tag1->setLabel('foo bar'); | ||
19 | |||
20 | $manager->persist($tag1); | ||
21 | |||
22 | $this->addReference('foo-bar-tag', $tag1); | ||
23 | |||
24 | $tag2 = new Tag(); | ||
25 | $tag2->setLabel('bar'); | ||
26 | |||
27 | $manager->persist($tag2); | ||
28 | |||
29 | $this->addReference('bar-tag', $tag2); | ||
30 | |||
31 | $tag3 = new Tag(); | ||
32 | $tag3->setLabel('baz'); | ||
33 | |||
34 | $manager->persist($tag3); | ||
35 | |||
36 | $this->addReference('baz-tag', $tag3); | ||
37 | |||
38 | $tag4 = new Tag(); | ||
39 | $tag4->setLabel('foo'); | ||
40 | |||
41 | $manager->persist($tag4); | ||
42 | |||
43 | $this->addReference('foo-tag', $tag4); | ||
44 | |||
45 | $manager->flush(); | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * {@inheritdoc} | ||
50 | */ | ||
51 | public function getOrder() | ||
52 | { | ||
53 | return 25; | ||
54 | } | ||
55 | } | ||
diff --git a/src/Wallabag/CoreBundle/DataFixtures/SiteCredentialFixtures.php b/src/Wallabag/CoreBundle/DataFixtures/SiteCredentialFixtures.php new file mode 100644 index 00000000..9a7d116f --- /dev/null +++ b/src/Wallabag/CoreBundle/DataFixtures/SiteCredentialFixtures.php | |||
@@ -0,0 +1,56 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DataFixtures; | ||
4 | |||
5 | use Doctrine\Bundle\FixturesBundle\Fixture; | ||
6 | use Doctrine\Common\DataFixtures\DependentFixtureInterface; | ||
7 | use Doctrine\Common\Persistence\ObjectManager; | ||
8 | use Symfony\Component\DependencyInjection\ContainerAwareInterface; | ||
9 | use Symfony\Component\DependencyInjection\ContainerInterface; | ||
10 | use Wallabag\CoreBundle\Entity\SiteCredential; | ||
11 | use Wallabag\UserBundle\DataFixtures\UserFixtures; | ||
12 | |||
13 | class SiteCredentialFixtures extends Fixture implements DependentFixtureInterface, ContainerAwareInterface | ||
14 | { | ||
15 | /** | ||
16 | * @var ContainerInterface | ||
17 | */ | ||
18 | private $container; | ||
19 | |||
20 | public function setContainer(ContainerInterface $container = null) | ||
21 | { | ||
22 | $this->container = $container; | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * {@inheritdoc} | ||
27 | */ | ||
28 | public function load(ObjectManager $manager) | ||
29 | { | ||
30 | $credential = new SiteCredential($this->getReference('admin-user')); | ||
31 | $credential->setHost('.super.com'); | ||
32 | $credential->setUsername($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('.super')); | ||
33 | $credential->setPassword($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('bar')); | ||
34 | |||
35 | $manager->persist($credential); | ||
36 | |||
37 | $credential = new SiteCredential($this->getReference('admin-user')); | ||
38 | $credential->setHost('paywall.example.com'); | ||
39 | $credential->setUsername($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('paywall.example')); | ||
40 | $credential->setPassword($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('bar')); | ||
41 | |||
42 | $manager->persist($credential); | ||
43 | |||
44 | $manager->flush(); | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * {@inheritdoc} | ||
49 | */ | ||
50 | public function getDependencies() | ||
51 | { | ||
52 | return [ | ||
53 | UserFixtures::class, | ||
54 | ]; | ||
55 | } | ||
56 | } | ||
diff --git a/src/Wallabag/CoreBundle/DataFixtures/TagFixtures.php b/src/Wallabag/CoreBundle/DataFixtures/TagFixtures.php new file mode 100644 index 00000000..58a0d799 --- /dev/null +++ b/src/Wallabag/CoreBundle/DataFixtures/TagFixtures.php | |||
@@ -0,0 +1,35 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DataFixtures; | ||
4 | |||
5 | use Doctrine\Bundle\FixturesBundle\Fixture; | ||
6 | use Doctrine\Common\Persistence\ObjectManager; | ||
7 | use Wallabag\CoreBundle\Entity\Tag; | ||
8 | |||
9 | class TagFixtures extends Fixture | ||
10 | { | ||
11 | /** | ||
12 | * {@inheritdoc} | ||
13 | */ | ||
14 | public function load(ObjectManager $manager) | ||
15 | { | ||
16 | $tags = [ | ||
17 | 'foo-bar-tag' => 'foo bar', //tag used for EntryControllerTest | ||
18 | 'bar-tag' => 'bar', | ||
19 | 'baz-tag' => 'baz', // tag used for ExportControllerTest | ||
20 | 'foo-tag' => 'foo', | ||
21 | 'bob-tag' => 'bob', // tag used for TagRestControllerTest | ||
22 | ]; | ||
23 | |||
24 | foreach ($tags as $reference => $label) { | ||
25 | $tag = new Tag(); | ||
26 | $tag->setLabel($label); | ||
27 | |||
28 | $manager->persist($tag); | ||
29 | |||
30 | $this->addReference($reference, $tag); | ||
31 | } | ||
32 | |||
33 | $manager->flush(); | ||
34 | } | ||
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 | ||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | 3 | namespace Wallabag\CoreBundle\DataFixtures; |
4 | 4 | ||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | 5 | use Doctrine\Bundle\FixturesBundle\Fixture; |
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | 6 | use Doctrine\Common\DataFixtures\DependentFixtureInterface; |
7 | use Doctrine\Common\Persistence\ObjectManager; | 7 | use Doctrine\Common\Persistence\ObjectManager; |
8 | use Wallabag\CoreBundle\Entity\TaggingRule; | 8 | use Wallabag\CoreBundle\Entity\TaggingRule; |
9 | 9 | ||
10 | class LoadTaggingRuleData extends AbstractFixture implements OrderedFixtureInterface | 10 | class 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/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php index a9791f6b..7ae73371 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php | |||
@@ -30,7 +30,7 @@ class Configuration implements ConfigurationInterface | |||
30 | ->defaultValue(50) | 30 | ->defaultValue(50) |
31 | ->end() | 31 | ->end() |
32 | ->integerNode('reading_speed') | 32 | ->integerNode('reading_speed') |
33 | ->defaultValue(1) | 33 | ->defaultValue(200) |
34 | ->end() | 34 | ->end() |
35 | ->scalarNode('version') | 35 | ->scalarNode('version') |
36 | ->end() | 36 | ->end() |
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php index a3ef2b53..e9a1e9e0 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php | |||
@@ -18,7 +18,7 @@ class WallabagCoreExtension extends Extension | |||
18 | $container->setParameter('wallabag_core.items_on_page', $config['items_on_page']); | 18 | $container->setParameter('wallabag_core.items_on_page', $config['items_on_page']); |
19 | $container->setParameter('wallabag_core.theme', $config['theme']); | 19 | $container->setParameter('wallabag_core.theme', $config['theme']); |
20 | $container->setParameter('wallabag_core.language', $config['language']); | 20 | $container->setParameter('wallabag_core.language', $config['language']); |
21 | $container->setParameter('wallabag_core.rss_limit', $config['rss_limit']); | 21 | $container->setParameter('wallabag_core.feed_limit', $config['rss_limit']); |
22 | $container->setParameter('wallabag_core.reading_speed', $config['reading_speed']); | 22 | $container->setParameter('wallabag_core.reading_speed', $config['reading_speed']); |
23 | $container->setParameter('wallabag_core.version', $config['version']); | 23 | $container->setParameter('wallabag_core.version', $config['version']); |
24 | $container->setParameter('wallabag_core.paypal_url', $config['paypal_url']); | 24 | $container->setParameter('wallabag_core.paypal_url', $config['paypal_url']); |
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 | |||
3 | namespace Wallabag\CoreBundle\Doctrine\DBAL\Driver; | ||
4 | |||
5 | use Doctrine\DBAL\Connection; | ||
6 | use Doctrine\DBAL\Driver\PDOPgSql\Driver; | ||
7 | use 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 | */ | ||
16 | class 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 | |||
3 | namespace Wallabag\CoreBundle\Doctrine\DBAL\Schema; | ||
4 | |||
5 | use Doctrine\DBAL\Schema\PostgreSqlSchemaManager; | ||
6 | use 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 | */ | ||
14 | class 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 | ||
3 | namespace Wallabag\CoreBundle\Doctrine; | 3 | namespace Wallabag\CoreBundle\Doctrine; |
4 | 4 | ||
5 | use Doctrine\DBAL\Migrations\AbstractMigration; | ||
6 | use Doctrine\DBAL\Schema\Schema; | 5 | use Doctrine\DBAL\Schema\Schema; |
6 | use Doctrine\Migrations\AbstractMigration; | ||
7 | use Symfony\Component\DependencyInjection\ContainerAwareInterface; | 7 | use Symfony\Component\DependencyInjection\ContainerAwareInterface; |
8 | use Symfony\Component\DependencyInjection\ContainerInterface; | 8 | use Symfony\Component\DependencyInjection\ContainerInterface; |
9 | 9 | ||
diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php index b902ae2c..fe7942ee 100644 --- a/src/Wallabag/CoreBundle/Entity/Config.php +++ b/src/Wallabag/CoreBundle/Entity/Config.php | |||
@@ -11,8 +11,12 @@ use Wallabag\UserBundle\Entity\User; | |||
11 | * Config. | 11 | * Config. |
12 | * | 12 | * |
13 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\ConfigRepository") | 13 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\ConfigRepository") |
14 | * @ORM\Table(name="`config`") | 14 | * @ORM\Table( |
15 | * @ORM\Entity | 15 | * name="`config`", |
16 | * indexes={ | ||
17 | * @ORM\Index(name="config_feed_token", columns={"feed_token"}, options={"lengths"={255}}), | ||
18 | * } | ||
19 | * ) | ||
16 | */ | 20 | */ |
17 | class Config | 21 | class Config |
18 | { | 22 | { |
@@ -60,21 +64,21 @@ class Config | |||
60 | /** | 64 | /** |
61 | * @var string | 65 | * @var string |
62 | * | 66 | * |
63 | * @ORM\Column(name="rss_token", type="string", nullable=true) | 67 | * @ORM\Column(name="feed_token", type="string", nullable=true) |
64 | */ | 68 | */ |
65 | private $rssToken; | 69 | private $feedToken; |
66 | 70 | ||
67 | /** | 71 | /** |
68 | * @var int | 72 | * @var int |
69 | * | 73 | * |
70 | * @ORM\Column(name="rss_limit", type="integer", nullable=true) | 74 | * @ORM\Column(name="feed_limit", type="integer", nullable=true) |
71 | * @Assert\Range( | 75 | * @Assert\Range( |
72 | * min = 1, | 76 | * min = 1, |
73 | * max = 100000, | 77 | * max = 100000, |
74 | * maxMessage = "validator.rss_limit_too_high" | 78 | * maxMessage = "validator.feed_limit_too_high" |
75 | * ) | 79 | * ) |
76 | */ | 80 | */ |
77 | private $rssLimit; | 81 | private $feedLimit; |
78 | 82 | ||
79 | /** | 83 | /** |
80 | * @var float | 84 | * @var float |
@@ -231,51 +235,51 @@ class Config | |||
231 | } | 235 | } |
232 | 236 | ||
233 | /** | 237 | /** |
234 | * Set rssToken. | 238 | * Set feed Token. |
235 | * | 239 | * |
236 | * @param string $rssToken | 240 | * @param string $feedToken |
237 | * | 241 | * |
238 | * @return Config | 242 | * @return Config |
239 | */ | 243 | */ |
240 | public function setRssToken($rssToken) | 244 | public function setFeedToken($feedToken) |
241 | { | 245 | { |
242 | $this->rssToken = $rssToken; | 246 | $this->feedToken = $feedToken; |
243 | 247 | ||
244 | return $this; | 248 | return $this; |
245 | } | 249 | } |
246 | 250 | ||
247 | /** | 251 | /** |
248 | * Get rssToken. | 252 | * Get feedToken. |
249 | * | 253 | * |
250 | * @return string | 254 | * @return string |
251 | */ | 255 | */ |
252 | public function getRssToken() | 256 | public function getFeedToken() |
253 | { | 257 | { |
254 | return $this->rssToken; | 258 | return $this->feedToken; |
255 | } | 259 | } |
256 | 260 | ||
257 | /** | 261 | /** |
258 | * Set rssLimit. | 262 | * Set Feed Limit. |
259 | * | 263 | * |
260 | * @param int $rssLimit | 264 | * @param int $feedLimit |
261 | * | 265 | * |
262 | * @return Config | 266 | * @return Config |
263 | */ | 267 | */ |
264 | public function setRssLimit($rssLimit) | 268 | public function setFeedLimit($feedLimit) |
265 | { | 269 | { |
266 | $this->rssLimit = $rssLimit; | 270 | $this->feedLimit = $feedLimit; |
267 | 271 | ||
268 | return $this; | 272 | return $this; |
269 | } | 273 | } |
270 | 274 | ||
271 | /** | 275 | /** |
272 | * Get rssLimit. | 276 | * Get Feed Limit. |
273 | * | 277 | * |
274 | * @return int | 278 | * @return int |
275 | */ | 279 | */ |
276 | public function getRssLimit() | 280 | public function getFeedLimit() |
277 | { | 281 | { |
278 | return $this->rssLimit; | 282 | return $this->feedLimit; |
279 | } | 283 | } |
280 | 284 | ||
281 | /** | 285 | /** |
@@ -367,8 +371,6 @@ class Config | |||
367 | } | 371 | } |
368 | 372 | ||
369 | /** | 373 | /** |
370 | * @param TaggingRule $rule | ||
371 | * | ||
372 | * @return Config | 374 | * @return Config |
373 | */ | 375 | */ |
374 | public function addTaggingRule(TaggingRule $rule) | 376 | public function addTaggingRule(TaggingRule $rule) |
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php index 2b1f2e05..19045798 100644 --- a/src/Wallabag/CoreBundle/Entity/Entry.php +++ b/src/Wallabag/CoreBundle/Entity/Entry.php | |||
@@ -13,6 +13,7 @@ use JMS\Serializer\Annotation\XmlRoot; | |||
13 | use Symfony\Component\Validator\Constraints as Assert; | 13 | use Symfony\Component\Validator\Constraints as Assert; |
14 | use Wallabag\AnnotationBundle\Entity\Annotation; | 14 | use Wallabag\AnnotationBundle\Entity\Annotation; |
15 | use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | 15 | use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; |
16 | use Wallabag\CoreBundle\Helper\UrlHasher; | ||
16 | use Wallabag\UserBundle\Entity\User; | 17 | use Wallabag\UserBundle\Entity\User; |
17 | 18 | ||
18 | /** | 19 | /** |
@@ -25,7 +26,13 @@ use Wallabag\UserBundle\Entity\User; | |||
25 | * options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"}, | 26 | * options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"}, |
26 | * indexes={ | 27 | * indexes={ |
27 | * @ORM\Index(name="created_at", columns={"created_at"}), | 28 | * @ORM\Index(name="created_at", columns={"created_at"}), |
28 | * @ORM\Index(name="uid", columns={"uid"}) | 29 | * @ORM\Index(name="uid", columns={"uid"}), |
30 | * @ORM\Index(name="hashed_url_user_id", columns={"user_id", "hashed_url"}, options={"lengths"={null, 40}}), | ||
31 | * @ORM\Index(name="hashed_given_url_user_id", columns={"user_id", "hashed_given_url"}, options={"lengths"={null, 40}}), | ||
32 | * @ORM\Index(name="user_language", columns={"language", "user_id"}), | ||
33 | * @ORM\Index(name="user_archived", columns={"user_id", "is_archived", "archived_at"}), | ||
34 | * @ORM\Index(name="user_created", columns={"user_id", "created_at"}), | ||
35 | * @ORM\Index(name="user_starred", columns={"user_id", "is_starred", "starred_at"}) | ||
29 | * } | 36 | * } |
30 | * ) | 37 | * ) |
31 | * @ORM\HasLifecycleCallbacks() | 38 | * @ORM\HasLifecycleCallbacks() |
@@ -66,6 +73,8 @@ class Entry | |||
66 | private $title; | 73 | private $title; |
67 | 74 | ||
68 | /** | 75 | /** |
76 | * Define the url fetched by wallabag (the final url after potential redirections). | ||
77 | * | ||
69 | * @var string | 78 | * @var string |
70 | * | 79 | * |
71 | * @Assert\NotBlank() | 80 | * @Assert\NotBlank() |
@@ -76,6 +85,42 @@ class Entry | |||
76 | private $url; | 85 | private $url; |
77 | 86 | ||
78 | /** | 87 | /** |
88 | * @var string | ||
89 | * | ||
90 | * @ORM\Column(name="hashed_url", type="string", length=40, nullable=true) | ||
91 | */ | ||
92 | private $hashedUrl; | ||
93 | |||
94 | /** | ||
95 | * From where user retrieved/found the url (an other article, a twitter, or the given_url if non are provided). | ||
96 | * | ||
97 | * @var string | ||
98 | * | ||
99 | * @ORM\Column(name="origin_url", type="text", nullable=true) | ||
100 | * | ||
101 | * @Groups({"entries_for_user", "export_all"}) | ||
102 | */ | ||
103 | private $originUrl; | ||
104 | |||
105 | /** | ||
106 | * Define the url entered by the user (without redirections). | ||
107 | * | ||
108 | * @var string | ||
109 | * | ||
110 | * @ORM\Column(name="given_url", type="text", nullable=true) | ||
111 | * | ||
112 | * @Groups({"entries_for_user", "export_all"}) | ||
113 | */ | ||
114 | private $givenUrl; | ||
115 | |||
116 | /** | ||
117 | * @var string | ||
118 | * | ||
119 | * @ORM\Column(name="hashed_given_url", type="string", length=40, nullable=true) | ||
120 | */ | ||
121 | private $hashedGivenUrl; | ||
122 | |||
123 | /** | ||
79 | * @var bool | 124 | * @var bool |
80 | * | 125 | * |
81 | * @Exclude | 126 | * @Exclude |
@@ -87,6 +132,15 @@ class Entry | |||
87 | private $isArchived = false; | 132 | private $isArchived = false; |
88 | 133 | ||
89 | /** | 134 | /** |
135 | * @var \DateTime | ||
136 | * | ||
137 | * @ORM\Column(name="archived_at", type="datetime", nullable=true) | ||
138 | * | ||
139 | * @Groups({"entries_for_user", "export_all"}) | ||
140 | */ | ||
141 | private $archivedAt = null; | ||
142 | |||
143 | /** | ||
90 | * @var bool | 144 | * @var bool |
91 | * | 145 | * |
92 | * @Exclude | 146 | * @Exclude |
@@ -171,7 +225,7 @@ class Entry | |||
171 | /** | 225 | /** |
172 | * @var string | 226 | * @var string |
173 | * | 227 | * |
174 | * @ORM\Column(name="language", type="text", nullable=true) | 228 | * @ORM\Column(name="language", type="string", length=20, nullable=true) |
175 | * | 229 | * |
176 | * @Groups({"entries_for_user", "export_all"}) | 230 | * @Groups({"entries_for_user", "export_all"}) |
177 | */ | 231 | */ |
@@ -245,15 +299,6 @@ class Entry | |||
245 | */ | 299 | */ |
246 | private $tags; | 300 | private $tags; |
247 | 301 | ||
248 | /** | ||
249 | * @var string | ||
250 | * | ||
251 | * @ORM\Column(name="origin_url", type="text", nullable=true) | ||
252 | * | ||
253 | * @Groups({"entries_for_user", "export_all"}) | ||
254 | */ | ||
255 | private $originUrl; | ||
256 | |||
257 | /* | 302 | /* |
258 | * @param User $user | 303 | * @param User $user |
259 | */ | 304 | */ |
@@ -307,6 +352,7 @@ class Entry | |||
307 | public function setUrl($url) | 352 | public function setUrl($url) |
308 | { | 353 | { |
309 | $this->url = $url; | 354 | $this->url = $url; |
355 | $this->hashedUrl = UrlHasher::hashUrl($url); | ||
310 | 356 | ||
311 | return $this; | 357 | return $this; |
312 | } | 358 | } |
@@ -336,6 +382,44 @@ class Entry | |||
336 | } | 382 | } |
337 | 383 | ||
338 | /** | 384 | /** |
385 | * update isArchived and archive_at fields. | ||
386 | * | ||
387 | * @param bool $isArchived | ||
388 | * | ||
389 | * @return Entry | ||
390 | */ | ||
391 | public function updateArchived($isArchived = false) | ||
392 | { | ||
393 | $this->setArchived($isArchived); | ||
394 | $this->setArchivedAt(null); | ||
395 | if ($this->isArchived()) { | ||
396 | $this->setArchivedAt(new \DateTime()); | ||
397 | } | ||
398 | |||
399 | return $this; | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * @return \DateTime|null | ||
404 | */ | ||
405 | public function getArchivedAt() | ||
406 | { | ||
407 | return $this->archivedAt; | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * @param \DateTime|null $archivedAt | ||
412 | * | ||
413 | * @return Entry | ||
414 | */ | ||
415 | public function setArchivedAt($archivedAt = null) | ||
416 | { | ||
417 | $this->archivedAt = $archivedAt; | ||
418 | |||
419 | return $this; | ||
420 | } | ||
421 | |||
422 | /** | ||
339 | * Get isArchived. | 423 | * Get isArchived. |
340 | * | 424 | * |
341 | * @return bool | 425 | * @return bool |
@@ -357,7 +441,7 @@ class Entry | |||
357 | 441 | ||
358 | public function toggleArchive() | 442 | public function toggleArchive() |
359 | { | 443 | { |
360 | $this->isArchived = $this->isArchived() ^ 1; | 444 | $this->updateArchived($this->isArchived() ^ 1); |
361 | 445 | ||
362 | return $this; | 446 | return $this; |
363 | } | 447 | } |
@@ -466,8 +550,6 @@ class Entry | |||
466 | * Set created_at. | 550 | * Set created_at. |
467 | * Only used when importing data from an other service. | 551 | * Only used when importing data from an other service. |
468 | * | 552 | * |
469 | * @param \DateTime $createdAt | ||
470 | * | ||
471 | * @return Entry | 553 | * @return Entry |
472 | */ | 554 | */ |
473 | public function setCreatedAt(\DateTime $createdAt) | 555 | public function setCreatedAt(\DateTime $createdAt) |
@@ -539,9 +621,6 @@ class Entry | |||
539 | return $this->annotations; | 621 | return $this->annotations; |
540 | } | 622 | } |
541 | 623 | ||
542 | /** | ||
543 | * @param Annotation $annotation | ||
544 | */ | ||
545 | public function setAnnotation(Annotation $annotation) | 624 | public function setAnnotation(Annotation $annotation) |
546 | { | 625 | { |
547 | $this->annotations[] = $annotation; | 626 | $this->annotations[] = $annotation; |
@@ -618,9 +697,6 @@ class Entry | |||
618 | return $data; | 697 | return $data; |
619 | } | 698 | } |
620 | 699 | ||
621 | /** | ||
622 | * @param Tag $tag | ||
623 | */ | ||
624 | public function addTag(Tag $tag) | 700 | public function addTag(Tag $tag) |
625 | { | 701 | { |
626 | if ($this->tags->contains($tag)) { | 702 | if ($this->tags->contains($tag)) { |
@@ -641,8 +717,6 @@ class Entry | |||
641 | 717 | ||
642 | /** | 718 | /** |
643 | * Remove the given tag from the entry (if the tag is associated). | 719 | * Remove the given tag from the entry (if the tag is associated). |
644 | * | ||
645 | * @param Tag $tag | ||
646 | */ | 720 | */ |
647 | public function removeTag(Tag $tag) | 721 | public function removeTag(Tag $tag) |
648 | { | 722 | { |
@@ -714,7 +788,20 @@ class Entry | |||
714 | } | 788 | } |
715 | 789 | ||
716 | /** | 790 | /** |
717 | * @return string | 791 | * Format the entry language to a valid html lang attribute. |
792 | */ | ||
793 | public function getHTMLLanguage() | ||
794 | { | ||
795 | $parsedLocale = \Locale::parseLocale($this->getLanguage()); | ||
796 | $lang = ''; | ||
797 | $lang .= $parsedLocale['language'] ?? ''; | ||
798 | $lang .= isset($parsedLocale['region']) ? '-' . $parsedLocale['region'] : ''; | ||
799 | |||
800 | return $lang; | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * @return string|null | ||
718 | */ | 805 | */ |
719 | public function getUid() | 806 | public function getUid() |
720 | { | 807 | { |
@@ -790,8 +877,6 @@ class Entry | |||
790 | } | 877 | } |
791 | 878 | ||
792 | /** | 879 | /** |
793 | * @param \Datetime $publishedAt | ||
794 | * | ||
795 | * @return Entry | 880 | * @return Entry |
796 | */ | 881 | */ |
797 | public function setPublishedAt(\Datetime $publishedAt) | 882 | public function setPublishedAt(\Datetime $publishedAt) |
@@ -864,4 +949,49 @@ class Entry | |||
864 | { | 949 | { |
865 | return $this->originUrl; | 950 | return $this->originUrl; |
866 | } | 951 | } |
952 | |||
953 | /** | ||
954 | * Set given url. | ||
955 | * | ||
956 | * @param string $givenUrl | ||
957 | * | ||
958 | * @return Entry | ||
959 | */ | ||
960 | public function setGivenUrl($givenUrl) | ||
961 | { | ||
962 | $this->givenUrl = $givenUrl; | ||
963 | $this->hashedGivenUrl = UrlHasher::hashUrl($givenUrl); | ||
964 | |||
965 | return $this; | ||
966 | } | ||
967 | |||
968 | /** | ||
969 | * Get given url. | ||
970 | * | ||
971 | * @return string | ||
972 | */ | ||
973 | public function getGivenUrl() | ||
974 | { | ||
975 | return $this->givenUrl; | ||
976 | } | ||
977 | |||
978 | /** | ||
979 | * @return string | ||
980 | */ | ||
981 | public function getHashedUrl() | ||
982 | { | ||
983 | return $this->hashedUrl; | ||
984 | } | ||
985 | |||
986 | /** | ||
987 | * @param mixed $hashedUrl | ||
988 | * | ||
989 | * @return Entry | ||
990 | */ | ||
991 | public function setHashedUrl($hashedUrl) | ||
992 | { | ||
993 | $this->hashedUrl = $hashedUrl; | ||
994 | |||
995 | return $this; | ||
996 | } | ||
867 | } | 997 | } |
diff --git a/src/Wallabag/CoreBundle/Entity/InternalSetting.php b/src/Wallabag/CoreBundle/Entity/InternalSetting.php new file mode 100644 index 00000000..df8bd3be --- /dev/null +++ b/src/Wallabag/CoreBundle/Entity/InternalSetting.php | |||
@@ -0,0 +1,36 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Entity; | ||
4 | |||
5 | use Craue\ConfigBundle\Entity\BaseSetting; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * InternalSetting. | ||
10 | * | ||
11 | * Re-define setting so we can override length attribute to fix utf8mb4 issue. | ||
12 | * | ||
13 | * @ORM\Entity(repositoryClass="Craue\ConfigBundle\Repository\SettingRepository") | ||
14 | * @ORM\Table(name="`internal_setting`") | ||
15 | * @ORM\AttributeOverrides({ | ||
16 | * @ORM\AttributeOverride(name="name", | ||
17 | * column=@ORM\Column( | ||
18 | * length = 191 | ||
19 | * ) | ||
20 | * ), | ||
21 | * @ORM\AttributeOverride(name="section", | ||
22 | * column=@ORM\Column( | ||
23 | * length = 191 | ||
24 | * ) | ||
25 | * ) | ||
26 | * }) | ||
27 | */ | ||
28 | class InternalSetting extends BaseSetting | ||
29 | { | ||
30 | /** | ||
31 | * @var string|null | ||
32 | * | ||
33 | * @ORM\Column(name="value", type="string", nullable=true, length=191) | ||
34 | */ | ||
35 | protected $value; | ||
36 | } | ||
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/Tag.php b/src/Wallabag/CoreBundle/Entity/Tag.php index a6dc8c50..9fb2f94f 100644 --- a/src/Wallabag/CoreBundle/Entity/Tag.php +++ b/src/Wallabag/CoreBundle/Entity/Tag.php | |||
@@ -13,7 +13,13 @@ use JMS\Serializer\Annotation\XmlRoot; | |||
13 | * Tag. | 13 | * Tag. |
14 | * | 14 | * |
15 | * @XmlRoot("tag") | 15 | * @XmlRoot("tag") |
16 | * @ORM\Table(name="`tag`") | 16 | * @ORM\Table( |
17 | * name="`tag`", | ||
18 | * options={"collate"="utf8mb4_bin", "charset"="utf8mb4"}, | ||
19 | * indexes={ | ||
20 | * @ORM\Index(name="tag_label", columns={"label"}, options={"lengths"={255}}), | ||
21 | * } | ||
22 | * ) | ||
17 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TagRepository") | 23 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TagRepository") |
18 | * @ExclusionPolicy("all") | 24 | * @ExclusionPolicy("all") |
19 | */ | 25 | */ |
@@ -98,9 +104,6 @@ class Tag | |||
98 | return $this->slug; | 104 | return $this->slug; |
99 | } | 105 | } |
100 | 106 | ||
101 | /** | ||
102 | * @param Entry $entry | ||
103 | */ | ||
104 | public function addEntry(Entry $entry) | 107 | public function addEntry(Entry $entry) |
105 | { | 108 | { |
106 | if ($this->entries->contains($entry)) { | 109 | if ($this->entries->contains($entry)) { |
@@ -111,9 +114,6 @@ class Tag | |||
111 | $entry->addTag($this); | 114 | $entry->addTag($this); |
112 | } | 115 | } |
113 | 116 | ||
114 | /** | ||
115 | * @param Entry $entry | ||
116 | */ | ||
117 | public function removeEntry(Entry $entry) | 117 | public function removeEntry(Entry $entry) |
118 | { | 118 | { |
119 | if (!$this->entries->contains($entry)) { | 119 | if (!$this->entries->contains($entry)) { |
diff --git a/src/Wallabag/CoreBundle/Entity/TaggingRule.php b/src/Wallabag/CoreBundle/Entity/TaggingRule.php index 84e11e26..f7166087 100644 --- a/src/Wallabag/CoreBundle/Entity/TaggingRule.php +++ b/src/Wallabag/CoreBundle/Entity/TaggingRule.php | |||
@@ -3,12 +3,16 @@ | |||
3 | namespace Wallabag\CoreBundle\Entity; | 3 | namespace Wallabag\CoreBundle\Entity; |
4 | 4 | ||
5 | use Doctrine\ORM\Mapping as ORM; | 5 | use Doctrine\ORM\Mapping as ORM; |
6 | use KPhoen\RulerZBundle\Validator\Constraints as RulerZAssert; | 6 | use JMS\Serializer\Annotation\Exclude; |
7 | use JMS\Serializer\Annotation\Groups; | ||
8 | use JMS\Serializer\Annotation\XmlRoot; | ||
9 | use Symfony\Bridge\RulerZ\Validator\Constraints as RulerZAssert; | ||
7 | use Symfony\Component\Validator\Constraints as Assert; | 10 | use Symfony\Component\Validator\Constraints as Assert; |
8 | 11 | ||
9 | /** | 12 | /** |
10 | * Tagging rule. | 13 | * Tagging rule. |
11 | * | 14 | * |
15 | * @XmlRoot("tagging_rule") | ||
12 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TaggingRuleRepository") | 16 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TaggingRuleRepository") |
13 | * @ORM\Table(name="`tagging_rule`") | 17 | * @ORM\Table(name="`tagging_rule`") |
14 | * @ORM\Entity | 18 | * @ORM\Entity |
@@ -34,6 +38,8 @@ class TaggingRule | |||
34 | * allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches", "notmatches"} | 38 | * allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches", "notmatches"} |
35 | * ) | 39 | * ) |
36 | * @ORM\Column(name="rule", type="string", nullable=false) | 40 | * @ORM\Column(name="rule", type="string", nullable=false) |
41 | * | ||
42 | * @Groups({"export_tagging_rule"}) | ||
37 | */ | 43 | */ |
38 | private $rule; | 44 | private $rule; |
39 | 45 | ||
@@ -42,10 +48,14 @@ class TaggingRule | |||
42 | * | 48 | * |
43 | * @Assert\NotBlank() | 49 | * @Assert\NotBlank() |
44 | * @ORM\Column(name="tags", type="simple_array", nullable=false) | 50 | * @ORM\Column(name="tags", type="simple_array", nullable=false) |
51 | * | ||
52 | * @Groups({"export_tagging_rule"}) | ||
45 | */ | 53 | */ |
46 | private $tags = []; | 54 | private $tags = []; |
47 | 55 | ||
48 | /** | 56 | /** |
57 | * @Exclude | ||
58 | * | ||
49 | * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", inversedBy="taggingRules") | 59 | * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", inversedBy="taggingRules") |
50 | */ | 60 | */ |
51 | private $config; | 61 | private $config; |
@@ -111,8 +121,6 @@ class TaggingRule | |||
111 | /** | 121 | /** |
112 | * Set config. | 122 | * Set config. |
113 | * | 123 | * |
114 | * @param Config $config | ||
115 | * | ||
116 | * @return TaggingRule | 124 | * @return TaggingRule |
117 | */ | 125 | */ |
118 | public function setConfig(Config $config) | 126 | public function setConfig(Config $config) |
diff --git a/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php b/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php index 367cdfb0..1b5d61ad 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; | |||
6 | use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; | 6 | use 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 | */ |
@@ -23,14 +25,11 @@ class UserLocaleListener | |||
23 | $this->session = $session; | 25 | $this->session = $session; |
24 | } | 26 | } |
25 | 27 | ||
26 | /** | ||
27 | * @param InteractiveLoginEvent $event | ||
28 | */ | ||
29 | public function onInteractiveLogin(InteractiveLoginEvent $event) | 28 | public function onInteractiveLogin(InteractiveLoginEvent $event) |
30 | { | 29 | { |
31 | $user = $event->getAuthenticationToken()->getUser(); | 30 | $user = $event->getAuthenticationToken()->getUser(); |
32 | 31 | ||
33 | if (null !== $user->getConfig()->getLanguage()) { | 32 | if (null !== $user->getConfig()->getLanguage() && null === $this->session->get('_locale')) { |
34 | $this->session->set('_locale', $user->getConfig()->getLanguage()); | 33 | $this->session->set('_locale', $user->getConfig()->getLanguage()); |
35 | } | 34 | } |
36 | } | 35 | } |
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/CustomDoctrineORMSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/CustomDoctrineORMSubscriber.php index cabb3eca..b8f6e1d6 100644 --- a/src/Wallabag/CoreBundle/Event/Subscriber/CustomDoctrineORMSubscriber.php +++ b/src/Wallabag/CoreBundle/Event/Subscriber/CustomDoctrineORMSubscriber.php | |||
@@ -12,9 +12,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
12 | */ | 12 | */ |
13 | class CustomDoctrineORMSubscriber extends DoctrineORMSubscriber implements EventSubscriberInterface | 13 | class CustomDoctrineORMSubscriber extends DoctrineORMSubscriber implements EventSubscriberInterface |
14 | { | 14 | { |
15 | /** | ||
16 | * @param GetFilterConditionEvent $event | ||
17 | */ | ||
18 | public function filterDateRange(GetFilterConditionEvent $event) | 15 | public function filterDateRange(GetFilterConditionEvent $event) |
19 | { | 16 | { |
20 | $expr = $event->getFilterQuery()->getExpressionBuilder(); | 17 | $expr = $event->getFilterQuery()->getExpressionBuilder(); |
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php index 1dd0a1a4..ef8d7d3b 100644 --- a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php +++ b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php | |||
@@ -35,8 +35,6 @@ class DownloadImagesSubscriber implements EventSubscriberInterface | |||
35 | 35 | ||
36 | /** | 36 | /** |
37 | * Download images and updated the data into the entry. | 37 | * Download images and updated the data into the entry. |
38 | * | ||
39 | * @param EntrySavedEvent $event | ||
40 | */ | 38 | */ |
41 | public function onEntrySaved(EntrySavedEvent $event) | 39 | public function onEntrySaved(EntrySavedEvent $event) |
42 | { | 40 | { |
@@ -69,8 +67,6 @@ class DownloadImagesSubscriber implements EventSubscriberInterface | |||
69 | 67 | ||
70 | /** | 68 | /** |
71 | * Remove images related to the entry. | 69 | * Remove images related to the entry. |
72 | * | ||
73 | * @param EntryDeletedEvent $event | ||
74 | */ | 70 | */ |
75 | public function onEntryDeleted(EntryDeletedEvent $event) | 71 | public function onEntryDeleted(EntryDeletedEvent $event) |
76 | { | 72 | { |
@@ -88,8 +84,6 @@ class DownloadImagesSubscriber implements EventSubscriberInterface | |||
88 | * | 84 | * |
89 | * @todo If we want to add async download, it should be done in that method | 85 | * @todo If we want to add async download, it should be done in that method |
90 | * | 86 | * |
91 | * @param Entry $entry | ||
92 | * | ||
93 | * @return string|false False in case of async | 87 | * @return string|false False in case of async |
94 | */ | 88 | */ |
95 | private function downloadImages(Entry $entry) | 89 | private function downloadImages(Entry $entry) |
@@ -106,8 +100,6 @@ class DownloadImagesSubscriber implements EventSubscriberInterface | |||
106 | * | 100 | * |
107 | * @todo If we want to add async download, it should be done in that method | 101 | * @todo If we want to add async download, it should be done in that method |
108 | * | 102 | * |
109 | * @param Entry $entry | ||
110 | * | ||
111 | * @return string|false False in case of async | 103 | * @return string|false False in case of async |
112 | */ | 104 | */ |
113 | private function downloadPreviewImage(Entry $entry) | 105 | private function downloadPreviewImage(Entry $entry) |
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php index 9c1d8a1d..dcadeedf 100644 --- a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php +++ b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php | |||
@@ -18,9 +18,6 @@ class SQLiteCascadeDeleteSubscriber implements EventSubscriber | |||
18 | { | 18 | { |
19 | private $doctrine; | 19 | private $doctrine; |
20 | 20 | ||
21 | /** | ||
22 | * @param \Doctrine\Bundle\DoctrineBundle\Registry $doctrine | ||
23 | */ | ||
24 | public function __construct(Registry $doctrine) | 21 | public function __construct(Registry $doctrine) |
25 | { | 22 | { |
26 | $this->doctrine = $doctrine; | 23 | $this->doctrine = $doctrine; |
@@ -39,8 +36,6 @@ class SQLiteCascadeDeleteSubscriber implements EventSubscriber | |||
39 | /** | 36 | /** |
40 | * We removed everything related to the upcoming removed entry because SQLite can't handle it on it own. | 37 | * We removed everything related to the upcoming removed entry because SQLite can't handle it on it own. |
41 | * We do it in the preRemove, because we can't retrieve tags in the postRemove (because the entry id is gone). | 38 | * We do it in the preRemove, because we can't retrieve tags in the postRemove (because the entry id is gone). |
42 | * | ||
43 | * @param LifecycleEventArgs $args | ||
44 | */ | 39 | */ |
45 | public function preRemove(LifecycleEventArgs $args) | 40 | public function preRemove(LifecycleEventArgs $args) |
46 | { | 41 | { |
diff --git a/src/Wallabag/CoreBundle/Form/Type/ConfigType.php b/src/Wallabag/CoreBundle/Form/Type/ConfigType.php index 1714ce74..6901fa08 100644 --- a/src/Wallabag/CoreBundle/Form/Type/ConfigType.php +++ b/src/Wallabag/CoreBundle/Form/Type/ConfigType.php | |||
@@ -4,6 +4,7 @@ namespace Wallabag\CoreBundle\Form\Type; | |||
4 | 4 | ||
5 | use Symfony\Component\Form\AbstractType; | 5 | use Symfony\Component\Form\AbstractType; |
6 | use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | 6 | use Symfony\Component\Form\Extension\Core\Type\ChoiceType; |
7 | use Symfony\Component\Form\Extension\Core\Type\IntegerType; | ||
7 | use Symfony\Component\Form\Extension\Core\Type\SubmitType; | 8 | use Symfony\Component\Form\Extension\Core\Type\SubmitType; |
8 | use Symfony\Component\Form\FormBuilderInterface; | 9 | use Symfony\Component\Form\FormBuilderInterface; |
9 | use Symfony\Component\OptionsResolver\OptionsResolver; | 10 | use Symfony\Component\OptionsResolver\OptionsResolver; |
@@ -37,19 +38,13 @@ class ConfigType extends AbstractType | |||
37 | 'choices' => array_flip($this->themes), | 38 | 'choices' => array_flip($this->themes), |
38 | 'label' => 'config.form_settings.theme_label', | 39 | 'label' => 'config.form_settings.theme_label', |
39 | ]) | 40 | ]) |
40 | ->add('items_per_page', null, [ | 41 | ->add('items_per_page', IntegerType::class, [ |
41 | 'label' => 'config.form_settings.items_per_page_label', | 42 | 'label' => 'config.form_settings.items_per_page_label', |
42 | 'property_path' => 'itemsPerPage', | 43 | 'property_path' => 'itemsPerPage', |
43 | ]) | 44 | ]) |
44 | ->add('reading_speed', ChoiceType::class, [ | 45 | ->add('reading_speed', IntegerType::class, [ |
45 | 'label' => 'config.form_settings.reading_speed.label', | 46 | 'label' => 'config.form_settings.reading_speed.label', |
46 | 'property_path' => 'readingSpeed', | 47 | 'property_path' => 'readingSpeed', |
47 | 'choices' => [ | ||
48 | 'config.form_settings.reading_speed.100_word' => '0.5', | ||
49 | 'config.form_settings.reading_speed.200_word' => '1', | ||
50 | 'config.form_settings.reading_speed.300_word' => '1.5', | ||
51 | 'config.form_settings.reading_speed.400_word' => '2', | ||
52 | ], | ||
53 | ]) | 48 | ]) |
54 | ->add('action_mark_as_read', ChoiceType::class, [ | 49 | ->add('action_mark_as_read', ChoiceType::class, [ |
55 | 'label' => 'config.form_settings.action_mark_as_read.label', | 50 | 'label' => 'config.form_settings.action_mark_as_read.label', |
diff --git a/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php b/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php index 08355928..2fc4c204 100644 --- a/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php +++ b/src/Wallabag/CoreBundle/Form/Type/EditEntryType.php | |||
@@ -22,11 +22,13 @@ class EditEntryType extends AbstractType | |||
22 | 'disabled' => true, | 22 | 'disabled' => true, |
23 | 'required' => false, | 23 | 'required' => false, |
24 | 'label' => 'entry.edit.url_label', | 24 | 'label' => 'entry.edit.url_label', |
25 | 'default_protocol' => null, | ||
25 | ]) | 26 | ]) |
26 | ->add('origin_url', UrlType::class, [ | 27 | ->add('origin_url', UrlType::class, [ |
27 | 'required' => false, | 28 | 'required' => false, |
28 | 'property_path' => 'originUrl', | 29 | 'property_path' => 'originUrl', |
29 | 'label' => 'entry.edit.origin_url_label', | 30 | 'label' => 'entry.edit.origin_url_label', |
31 | 'default_protocol' => null, | ||
30 | ]) | 32 | ]) |
31 | ->add('save', SubmitType::class, [ | 33 | ->add('save', SubmitType::class, [ |
32 | 'label' => 'entry.edit.save_label', | 34 | 'label' => 'entry.edit.save_label', |
diff --git a/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php b/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php index 702c7f7a..17070c59 100644 --- a/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php +++ b/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php | |||
@@ -23,9 +23,6 @@ class EntryFilterType extends AbstractType | |||
23 | 23 | ||
24 | /** | 24 | /** |
25 | * Repository & user are used to get a list of language entries for this user. | 25 | * Repository & user are used to get a list of language entries for this user. |
26 | * | ||
27 | * @param EntityRepository $entryRepository | ||
28 | * @param TokenStorageInterface $tokenStorage | ||
29 | */ | 26 | */ |
30 | public function __construct(EntityRepository $entryRepository, TokenStorageInterface $tokenStorage) | 27 | public function __construct(EntityRepository $entryRepository, TokenStorageInterface $tokenStorage) |
31 | { | 28 | { |
@@ -54,8 +51,8 @@ class EntryFilterType extends AbstractType | |||
54 | $lower = $values['value']['left_number'][0]; | 51 | $lower = $values['value']['left_number'][0]; |
55 | $upper = $values['value']['right_number'][0]; | 52 | $upper = $values['value']['right_number'][0]; |
56 | 53 | ||
57 | $min = (int) ($lower * $this->user->getConfig()->getReadingSpeed()); | 54 | $min = (int) ($lower * $this->user->getConfig()->getReadingSpeed() / 200); |
58 | $max = (int) ($upper * $this->user->getConfig()->getReadingSpeed()); | 55 | $max = (int) ($upper * $this->user->getConfig()->getReadingSpeed() / 200); |
59 | 56 | ||
60 | if (null === $lower && null === $upper) { | 57 | if (null === $lower && null === $upper) { |
61 | // no value? no filter | 58 | // no value? no filter |
@@ -108,7 +105,7 @@ class EntryFilterType extends AbstractType | |||
108 | ->add('httpStatus', TextFilterType::class, [ | 105 | ->add('httpStatus', TextFilterType::class, [ |
109 | 'apply_filter' => function (QueryInterface $filterQuery, $field, $values) { | 106 | 'apply_filter' => function (QueryInterface $filterQuery, $field, $values) { |
110 | $value = $values['value']; | 107 | $value = $values['value']; |
111 | if (false === array_key_exists($value, Response::$statusTexts)) { | 108 | if (false === \array_key_exists($value, Response::$statusTexts)) { |
112 | return; | 109 | return; |
113 | } | 110 | } |
114 | 111 | ||
diff --git a/src/Wallabag/CoreBundle/Form/Type/RssType.php b/src/Wallabag/CoreBundle/Form/Type/FeedType.php index 49b31c1e..9b34daf4 100644 --- a/src/Wallabag/CoreBundle/Form/Type/RssType.php +++ b/src/Wallabag/CoreBundle/Form/Type/FeedType.php | |||
@@ -7,14 +7,14 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |||
7 | use Symfony\Component\Form\FormBuilderInterface; | 7 | use Symfony\Component\Form\FormBuilderInterface; |
8 | use Symfony\Component\OptionsResolver\OptionsResolver; | 8 | use Symfony\Component\OptionsResolver\OptionsResolver; |
9 | 9 | ||
10 | class RssType extends AbstractType | 10 | class FeedType extends AbstractType |
11 | { | 11 | { |
12 | public function buildForm(FormBuilderInterface $builder, array $options) | 12 | public function buildForm(FormBuilderInterface $builder, array $options) |
13 | { | 13 | { |
14 | $builder | 14 | $builder |
15 | ->add('rss_limit', null, [ | 15 | ->add('feed_limit', null, [ |
16 | 'label' => 'config.form_rss.rss_limit', | 16 | 'label' => 'config.form_feed.feed_limit', |
17 | 'property_path' => 'rssLimit', | 17 | 'property_path' => 'feedLimit', |
18 | ]) | 18 | ]) |
19 | ->add('save', SubmitType::class, [ | 19 | ->add('save', SubmitType::class, [ |
20 | 'label' => 'config.form.save', | 20 | 'label' => 'config.form.save', |
@@ -31,6 +31,6 @@ class RssType extends AbstractType | |||
31 | 31 | ||
32 | public function getBlockPrefix() | 32 | public function getBlockPrefix() |
33 | { | 33 | { |
34 | return 'rss_config'; | 34 | return 'feed_config'; |
35 | } | 35 | } |
36 | } | 36 | } |
diff --git a/src/Wallabag/CoreBundle/Form/Type/NewEntryType.php b/src/Wallabag/CoreBundle/Form/Type/NewEntryType.php index 7d74fee3..7af1e589 100644 --- a/src/Wallabag/CoreBundle/Form/Type/NewEntryType.php +++ b/src/Wallabag/CoreBundle/Form/Type/NewEntryType.php | |||
@@ -15,6 +15,7 @@ class NewEntryType extends AbstractType | |||
15 | ->add('url', UrlType::class, [ | 15 | ->add('url', UrlType::class, [ |
16 | 'required' => true, | 16 | 'required' => true, |
17 | 'label' => 'entry.new.form_new.url_label', | 17 | 'label' => 'entry.new.form_new.url_label', |
18 | 'default_protocol' => null, | ||
18 | ]) | 19 | ]) |
19 | ; | 20 | ; |
20 | } | 21 | } |
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 | |||
3 | namespace Wallabag\CoreBundle\Form\Type; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\Extension\Core\Type\TextType; | ||
7 | use Symfony\Component\Form\FormBuilderInterface; | ||
8 | use Symfony\Component\OptionsResolver\OptionsResolver; | ||
9 | |||
10 | class 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/TaggingRuleImportType.php b/src/Wallabag/CoreBundle/Form/Type/TaggingRuleImportType.php new file mode 100644 index 00000000..c6a8c0b8 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/TaggingRuleImportType.php | |||
@@ -0,0 +1,29 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Form\Type; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\Extension\Core\Type\FileType; | ||
7 | use Symfony\Component\Form\Extension\Core\Type\SubmitType; | ||
8 | use Symfony\Component\Form\FormBuilderInterface; | ||
9 | |||
10 | class TaggingRuleImportType extends AbstractType | ||
11 | { | ||
12 | public function buildForm(FormBuilderInterface $builder, array $options) | ||
13 | { | ||
14 | $builder | ||
15 | ->add('file', FileType::class, [ | ||
16 | 'label' => 'config.form_rules.file_label', | ||
17 | 'required' => true, | ||
18 | ]) | ||
19 | ->add('import', SubmitType::class, [ | ||
20 | 'label' => 'config.form_rules.import_submit', | ||
21 | ]) | ||
22 | ; | ||
23 | } | ||
24 | |||
25 | public function getBlockPrefix() | ||
26 | { | ||
27 | return 'upload_tagging_rule_file'; | ||
28 | } | ||
29 | } | ||
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/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php index 90e00c62..b0be2176 100644 --- a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php +++ b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php | |||
@@ -34,11 +34,6 @@ class GrabySiteConfigBuilder implements SiteConfigBuilder | |||
34 | 34 | ||
35 | /** | 35 | /** |
36 | * GrabySiteConfigBuilder constructor. | 36 | * GrabySiteConfigBuilder constructor. |
37 | * | ||
38 | * @param ConfigBuilder $grabyConfigBuilder | ||
39 | * @param TokenStorage $token | ||
40 | * @param SiteCredentialRepository $credentialRepository | ||
41 | * @param LoggerInterface $logger | ||
42 | */ | 37 | */ |
43 | public function __construct(ConfigBuilder $grabyConfigBuilder, TokenStorage $token, SiteCredentialRepository $credentialRepository, LoggerInterface $logger) | 38 | public function __construct(ConfigBuilder $grabyConfigBuilder, TokenStorage $token, SiteCredentialRepository $credentialRepository, LoggerInterface $logger) |
44 | { | 39 | { |
@@ -62,11 +57,24 @@ class GrabySiteConfigBuilder implements SiteConfigBuilder | |||
62 | $host = substr($host, 4); | 57 | $host = substr($host, 4); |
63 | } | 58 | } |
64 | 59 | ||
65 | $credentials = null; | 60 | if (!$this->currentUser) { |
66 | if ($this->currentUser) { | 61 | $this->logger->debug('Auth: no current user defined.'); |
67 | $credentials = $this->credentialRepository->findOneByHostAndUser($host, $this->currentUser->getId()); | 62 | |
63 | return false; | ||
68 | } | 64 | } |
69 | 65 | ||
66 | $hosts = [$host]; | ||
67 | // will try to see for a host without the first subdomain (fr.example.org & .example.org) | ||
68 | $split = explode('.', $host); | ||
69 | |||
70 | if (\count($split) > 1) { | ||
71 | // remove first subdomain | ||
72 | array_shift($split); | ||
73 | $hosts[] = '.' . implode('.', $split); | ||
74 | } | ||
75 | |||
76 | $credentials = $this->credentialRepository->findOneByHostsAndUser($hosts, $this->currentUser->getId()); | ||
77 | |||
70 | if (null === $credentials) { | 78 | if (null === $credentials) { |
71 | $this->logger->debug('Auth: no credentials available for host.', ['host' => $host]); | 79 | $this->logger->debug('Auth: no credentials available for host.', ['host' => $host]); |
72 | 80 | ||
diff --git a/src/Wallabag/CoreBundle/Helper/ContentProxy.php b/src/Wallabag/CoreBundle/Helper/ContentProxy.php index d38811a2..9c6fa8db 100644 --- a/src/Wallabag/CoreBundle/Helper/ContentProxy.php +++ b/src/Wallabag/CoreBundle/Helper/ContentProxy.php | |||
@@ -12,8 +12,8 @@ use Wallabag\CoreBundle\Entity\Entry; | |||
12 | use Wallabag\CoreBundle\Tools\Utils; | 12 | use Wallabag\CoreBundle\Tools\Utils; |
13 | 13 | ||
14 | /** | 14 | /** |
15 | * This kind of proxy class take care of getting the content from an url | 15 | * This kind of proxy class takes care of getting the content from an url |
16 | * and update the entry with what it found. | 16 | * and updates the entry with what it found. |
17 | */ | 17 | */ |
18 | class ContentProxy | 18 | class ContentProxy |
19 | { | 19 | { |
@@ -47,13 +47,18 @@ class ContentProxy | |||
47 | */ | 47 | */ |
48 | public function updateEntry(Entry $entry, $url, array $content = [], $disableContentUpdate = false) | 48 | public function updateEntry(Entry $entry, $url, array $content = [], $disableContentUpdate = false) |
49 | { | 49 | { |
50 | $this->graby->toggleImgNoReferrer(true); | ||
50 | if (!empty($content['html'])) { | 51 | if (!empty($content['html'])) { |
51 | $content['html'] = $this->graby->cleanupHtml($content['html'], $url); | 52 | $content['html'] = $this->graby->cleanupHtml($content['html'], $url); |
52 | } | 53 | } |
53 | 54 | ||
54 | if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) { | 55 | if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) { |
55 | $fetchedContent = $this->graby->fetchContent($url); | 56 | $fetchedContent = $this->graby->fetchContent($url); |
56 | $fetchedContent['title'] = $this->sanitizeContentTitle($fetchedContent['title'], $fetchedContent['content_type']); | 57 | |
58 | $fetchedContent['title'] = $this->sanitizeContentTitle( | ||
59 | $fetchedContent['title'], | ||
60 | isset($fetchedContent['headers']['content-type']) ? $fetchedContent['headers']['content-type'] : '' | ||
61 | ); | ||
57 | 62 | ||
58 | // when content is imported, we have information in $content | 63 | // when content is imported, we have information in $content |
59 | // in case fetching content goes bad, we'll keep the imported information instead of overriding them | 64 | // in case fetching content goes bad, we'll keep the imported information instead of overriding them |
@@ -73,13 +78,14 @@ class ContentProxy | |||
73 | $entry->setUrl($url); | 78 | $entry->setUrl($url); |
74 | } | 79 | } |
75 | 80 | ||
81 | $entry->setGivenUrl($url); | ||
82 | |||
76 | $this->stockEntry($entry, $content); | 83 | $this->stockEntry($entry, $content); |
77 | } | 84 | } |
78 | 85 | ||
79 | /** | 86 | /** |
80 | * Use a Symfony validator to ensure the language is well formatted. | 87 | * Use a Symfony validator to ensure the language is well formatted. |
81 | * | 88 | * |
82 | * @param Entry $entry | ||
83 | * @param string $value Language to validate and save | 89 | * @param string $value Language to validate and save |
84 | */ | 90 | */ |
85 | public function updateLanguage(Entry $entry, $value) | 91 | public function updateLanguage(Entry $entry, $value) |
@@ -105,7 +111,6 @@ class ContentProxy | |||
105 | /** | 111 | /** |
106 | * Use a Symfony validator to ensure the preview picture is a real url. | 112 | * Use a Symfony validator to ensure the preview picture is a real url. |
107 | * | 113 | * |
108 | * @param Entry $entry | ||
109 | * @param string $value URL to validate and save | 114 | * @param string $value URL to validate and save |
110 | */ | 115 | */ |
111 | public function updatePreviewPicture(Entry $entry, $value) | 116 | public function updatePreviewPicture(Entry $entry, $value) |
@@ -127,7 +132,6 @@ class ContentProxy | |||
127 | /** | 132 | /** |
128 | * Update date. | 133 | * Update date. |
129 | * | 134 | * |
130 | * @param Entry $entry | ||
131 | * @param string $value Date to validate and save | 135 | * @param string $value Date to validate and save |
132 | */ | 136 | */ |
133 | public function updatePublishedAt(Entry $entry, $value) | 137 | public function updatePublishedAt(Entry $entry, $value) |
@@ -154,8 +158,6 @@ class ContentProxy | |||
154 | 158 | ||
155 | /** | 159 | /** |
156 | * Helper to extract and save host from entry url. | 160 | * Helper to extract and save host from entry url. |
157 | * | ||
158 | * @param Entry $entry | ||
159 | */ | 161 | */ |
160 | public function setEntryDomainName(Entry $entry) | 162 | public function setEntryDomainName(Entry $entry) |
161 | { | 163 | { |
@@ -169,8 +171,6 @@ class ContentProxy | |||
169 | * Helper to set a default title using: | 171 | * Helper to set a default title using: |
170 | * - url basename, if applicable | 172 | * - url basename, if applicable |
171 | * - hostname. | 173 | * - hostname. |
172 | * | ||
173 | * @param Entry $entry | ||
174 | */ | 174 | */ |
175 | public function setDefaultEntryTitle(Entry $entry) | 175 | public function setDefaultEntryTitle(Entry $entry) |
176 | { | 176 | { |
@@ -187,8 +187,8 @@ class ContentProxy | |||
187 | /** | 187 | /** |
188 | * Try to sanitize the title of the fetched content from wrong character encodings and invalid UTF-8 character. | 188 | * Try to sanitize the title of the fetched content from wrong character encodings and invalid UTF-8 character. |
189 | * | 189 | * |
190 | * @param $title | 190 | * @param string $title |
191 | * @param $contentType | 191 | * @param string $contentType |
192 | * | 192 | * |
193 | * @return string | 193 | * @return string |
194 | */ | 194 | */ |
@@ -252,22 +252,19 @@ class ContentProxy | |||
252 | 252 | ||
253 | if (!empty($content['title'])) { | 253 | if (!empty($content['title'])) { |
254 | $entry->setTitle($content['title']); | 254 | $entry->setTitle($content['title']); |
255 | } elseif (!empty($content['open_graph']['og_title'])) { | ||
256 | $entry->setTitle($content['open_graph']['og_title']); | ||
257 | } | 255 | } |
258 | 256 | ||
259 | $html = $content['html']; | 257 | if (empty($content['html'])) { |
260 | if (false === $html) { | 258 | $content['html'] = $this->fetchingErrorMessage; |
261 | $html = $this->fetchingErrorMessage; | ||
262 | 259 | ||
263 | if (!empty($content['open_graph']['og_description'])) { | 260 | if (!empty($content['description'])) { |
264 | $html .= '<p><i>But we found a short description: </i></p>'; | 261 | $content['html'] .= '<p><i>But we found a short description: </i></p>'; |
265 | $html .= $content['open_graph']['og_description']; | 262 | $content['html'] .= $content['description']; |
266 | } | 263 | } |
267 | } | 264 | } |
268 | 265 | ||
269 | $entry->setContent($html); | 266 | $entry->setContent($content['html']); |
270 | $entry->setReadingTime(Utils::getReadingTime($html)); | 267 | $entry->setReadingTime(Utils::getReadingTime($content['html'])); |
271 | 268 | ||
272 | if (!empty($content['status'])) { | 269 | if (!empty($content['status'])) { |
273 | $entry->setHttpStatus($content['status']); | 270 | $entry->setHttpStatus($content['status']); |
@@ -277,8 +274,8 @@ class ContentProxy | |||
277 | $entry->setPublishedBy($content['authors']); | 274 | $entry->setPublishedBy($content['authors']); |
278 | } | 275 | } |
279 | 276 | ||
280 | if (!empty($content['all_headers']) && $this->storeArticleHeaders) { | 277 | if (!empty($content['headers'])) { |
281 | $entry->setHeaders($content['all_headers']); | 278 | $entry->setHeaders($content['headers']); |
282 | } | 279 | } |
283 | 280 | ||
284 | if (!empty($content['date'])) { | 281 | if (!empty($content['date'])) { |
@@ -289,17 +286,30 @@ class ContentProxy | |||
289 | $this->updateLanguage($entry, $content['language']); | 286 | $this->updateLanguage($entry, $content['language']); |
290 | } | 287 | } |
291 | 288 | ||
292 | if (!empty($content['open_graph']['og_image'])) { | 289 | $previewPictureUrl = ''; |
293 | $this->updatePreviewPicture($entry, $content['open_graph']['og_image']); | 290 | if (!empty($content['image'])) { |
291 | $previewPictureUrl = $content['image']; | ||
294 | } | 292 | } |
295 | 293 | ||
296 | // if content is an image, define it as a preview too | 294 | // if content is an image, define it as a preview too |
297 | if (!empty($content['content_type']) && \in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) { | 295 | if (!empty($content['headers']['content-type']) && \in_array($this->mimeGuesser->guess($content['headers']['content-type']), ['jpeg', 'jpg', 'gif', 'png'], true)) { |
298 | $this->updatePreviewPicture($entry, $content['url']); | 296 | $previewPictureUrl = $content['url']; |
297 | } elseif (empty($previewPictureUrl)) { | ||
298 | $this->logger->debug('Extracting images from content to provide a default preview picture'); | ||
299 | $imagesUrls = DownloadImages::extractImagesUrlsFromHtml($content['html']); | ||
300 | $this->logger->debug(\count($imagesUrls) . ' pictures found'); | ||
301 | |||
302 | if (!empty($imagesUrls)) { | ||
303 | $previewPictureUrl = $imagesUrls[0]; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (!empty($content['headers']['content-type'])) { | ||
308 | $entry->setMimetype($content['headers']['content-type']); | ||
299 | } | 309 | } |
300 | 310 | ||
301 | if (!empty($content['content_type'])) { | 311 | if (!empty($previewPictureUrl)) { |
302 | $entry->setMimetype($content['content_type']); | 312 | $this->updatePreviewPicture($entry, $previewPictureUrl); |
303 | } | 313 | } |
304 | 314 | ||
305 | try { | 315 | try { |
@@ -316,7 +326,6 @@ class ContentProxy | |||
316 | * Update the origin_url field when a redirection occurs | 326 | * Update the origin_url field when a redirection occurs |
317 | * This field is set if it is empty and new url does not match ignore list. | 327 | * This field is set if it is empty and new url does not match ignore list. |
318 | * | 328 | * |
319 | * @param Entry $entry | ||
320 | * @param string $url | 329 | * @param string $url |
321 | */ | 330 | */ |
322 | private function updateOriginUrl(Entry $entry, $url) | 331 | private function updateOriginUrl(Entry $entry, $url) |
@@ -424,8 +433,6 @@ class ContentProxy | |||
424 | /** | 433 | /** |
425 | * Validate that the given content has at least a title, an html and a url. | 434 | * Validate that the given content has at least a title, an html and a url. |
426 | * | 435 | * |
427 | * @param array $content | ||
428 | * | ||
429 | * @return bool true if valid otherwise false | 436 | * @return bool true if valid otherwise false |
430 | */ | 437 | */ |
431 | private function validateContent(array $content) | 438 | private function validateContent(array $content) |
diff --git a/src/Wallabag/CoreBundle/Helper/DownloadImages.php b/src/Wallabag/CoreBundle/Helper/DownloadImages.php index cc3dcfce..1d98fd1a 100644 --- a/src/Wallabag/CoreBundle/Helper/DownloadImages.php +++ b/src/Wallabag/CoreBundle/Helper/DownloadImages.php | |||
@@ -2,8 +2,15 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Helper; | 3 | namespace Wallabag\CoreBundle\Helper; |
4 | 4 | ||
5 | use GuzzleHttp\Client; | 5 | use GuzzleHttp\Psr7\Uri; |
6 | use GuzzleHttp\Message\Response; | 6 | use GuzzleHttp\Psr7\UriResolver; |
7 | use Http\Client\Common\HttpMethodsClient; | ||
8 | use Http\Client\Common\Plugin\ErrorPlugin; | ||
9 | use Http\Client\Common\PluginClient; | ||
10 | use Http\Client\HttpClient; | ||
11 | use Http\Discovery\MessageFactoryDiscovery; | ||
12 | use Http\Message\MessageFactory; | ||
13 | use Psr\Http\Message\ResponseInterface; | ||
7 | use Psr\Log\LoggerInterface; | 14 | use Psr\Log\LoggerInterface; |
8 | use Symfony\Component\DomCrawler\Crawler; | 15 | use Symfony\Component\DomCrawler\Crawler; |
9 | use Symfony\Component\Finder\Finder; | 16 | use Symfony\Component\Finder\Finder; |
@@ -19,9 +26,9 @@ class DownloadImages | |||
19 | private $mimeGuesser; | 26 | private $mimeGuesser; |
20 | private $wallabagUrl; | 27 | private $wallabagUrl; |
21 | 28 | ||
22 | public function __construct(Client $client, $baseFolder, $wallabagUrl, LoggerInterface $logger) | 29 | public function __construct(HttpClient $client, $baseFolder, $wallabagUrl, LoggerInterface $logger, MessageFactory $messageFactory = null) |
23 | { | 30 | { |
24 | $this->client = $client; | 31 | $this->client = new HttpMethodsClient(new PluginClient($client, [new ErrorPlugin()]), $messageFactory ?: MessageFactoryDiscovery::find()); |
25 | $this->baseFolder = $baseFolder; | 32 | $this->baseFolder = $baseFolder; |
26 | $this->wallabagUrl = rtrim($wallabagUrl, '/'); | 33 | $this->wallabagUrl = rtrim($wallabagUrl, '/'); |
27 | $this->logger = $logger; | 34 | $this->logger = $logger; |
@@ -31,6 +38,23 @@ class DownloadImages | |||
31 | } | 38 | } |
32 | 39 | ||
33 | /** | 40 | /** |
41 | * Process the html and extract images URLs from it. | ||
42 | * | ||
43 | * @param string $html | ||
44 | * | ||
45 | * @return string[] | ||
46 | */ | ||
47 | public static function extractImagesUrlsFromHtml($html) | ||
48 | { | ||
49 | $crawler = new Crawler($html); | ||
50 | $imagesCrawler = $crawler->filterXpath('//img'); | ||
51 | $imagesUrls = $imagesCrawler->extract(['src']); | ||
52 | $imagesSrcsetUrls = self::getSrcsetUrls($imagesCrawler); | ||
53 | |||
54 | return array_unique(array_merge($imagesUrls, $imagesSrcsetUrls)); | ||
55 | } | ||
56 | |||
57 | /** | ||
34 | * Process the html and extract image from it, save them to local and return the updated html. | 58 | * Process the html and extract image from it, save them to local and return the updated html. |
35 | * | 59 | * |
36 | * @param int $entryId ID of the entry | 60 | * @param int $entryId ID of the entry |
@@ -41,13 +65,7 @@ class DownloadImages | |||
41 | */ | 65 | */ |
42 | public function processHtml($entryId, $html, $url) | 66 | public function processHtml($entryId, $html, $url) |
43 | { | 67 | { |
44 | $crawler = new Crawler($html); | 68 | $imagesUrls = self::extractImagesUrlsFromHtml($html); |
45 | $imagesCrawler = $crawler | ||
46 | ->filterXpath('//img'); | ||
47 | $imagesUrls = $imagesCrawler | ||
48 | ->extract(['src']); | ||
49 | $imagesSrcsetUrls = $this->getSrcsetUrls($imagesCrawler); | ||
50 | $imagesUrls = array_unique(array_merge($imagesUrls, $imagesSrcsetUrls)); | ||
51 | 69 | ||
52 | $relativePath = $this->getRelativePath($entryId); | 70 | $relativePath = $this->getRelativePath($entryId); |
53 | 71 | ||
@@ -122,7 +140,7 @@ class DownloadImages | |||
122 | $localPath = $folderPath . '/' . $hashImage . '.' . $ext; | 140 | $localPath = $folderPath . '/' . $hashImage . '.' . $ext; |
123 | 141 | ||
124 | try { | 142 | try { |
125 | $im = imagecreatefromstring($res->getBody()); | 143 | $im = imagecreatefromstring((string) $res->getBody()); |
126 | } catch (\Exception $e) { | 144 | } catch (\Exception $e) { |
127 | $im = false; | 145 | $im = false; |
128 | } | 146 | } |
@@ -135,7 +153,21 @@ class DownloadImages | |||
135 | 153 | ||
136 | switch ($ext) { | 154 | switch ($ext) { |
137 | case 'gif': | 155 | case 'gif': |
138 | imagegif($im, $localPath); | 156 | // use Imagick if available to keep GIF animation |
157 | if (class_exists('\\Imagick')) { | ||
158 | try { | ||
159 | $imagick = new \Imagick(); | ||
160 | $imagick->readImageBlob($res->getBody()); | ||
161 | $imagick->setImageFormat('gif'); | ||
162 | $imagick->writeImages($localPath, true); | ||
163 | } catch (\Exception $e) { | ||
164 | // if Imagick fail, fallback to the default solution | ||
165 | imagegif($im, $localPath); | ||
166 | } | ||
167 | } else { | ||
168 | imagegif($im, $localPath); | ||
169 | } | ||
170 | |||
139 | $this->logger->debug('DownloadImages: Re-creating gif'); | 171 | $this->logger->debug('DownloadImages: Re-creating gif'); |
140 | break; | 172 | break; |
141 | case 'jpeg': | 173 | case 'jpeg': |
@@ -181,29 +213,30 @@ class DownloadImages | |||
181 | /** | 213 | /** |
182 | * Get images urls from the srcset image attribute. | 214 | * Get images urls from the srcset image attribute. |
183 | * | 215 | * |
184 | * @param Crawler $imagesCrawler | ||
185 | * | ||
186 | * @return array An array of urls | 216 | * @return array An array of urls |
187 | */ | 217 | */ |
188 | private function getSrcsetUrls(Crawler $imagesCrawler) | 218 | private static function getSrcsetUrls(Crawler $imagesCrawler) |
189 | { | 219 | { |
190 | $urls = []; | 220 | $urls = []; |
191 | $iterator = $imagesCrawler | 221 | $iterator = $imagesCrawler->getIterator(); |
192 | ->getIterator(); | 222 | |
193 | while ($iterator->valid()) { | 223 | while ($iterator->valid()) { |
194 | $srcsetAttribute = $iterator->current()->getAttribute('srcset'); | 224 | $srcsetAttribute = $iterator->current()->getAttribute('srcset'); |
225 | |||
195 | if ('' !== $srcsetAttribute) { | 226 | if ('' !== $srcsetAttribute) { |
196 | // Couldn't start with " OR ' OR a white space | 227 | // Couldn't start with " OR ' OR a white space |
197 | // Could be one or more white space | 228 | // Could be one or more white space |
198 | // Must be one or more digits followed by w OR x | 229 | // Must be one or more digits followed by w OR x |
199 | $pattern = "/(?:[^\"'\s]+\s*(?:\d+[wx])+)/"; | 230 | $pattern = "/(?:[^\"'\s]+\s*(?:\d+[wx])+)/"; |
200 | preg_match_all($pattern, $srcsetAttribute, $matches); | 231 | preg_match_all($pattern, $srcsetAttribute, $matches); |
232 | |||
201 | $srcset = \call_user_func_array('array_merge', $matches); | 233 | $srcset = \call_user_func_array('array_merge', $matches); |
202 | $srcsetUrls = array_map(function ($src) { | 234 | $srcsetUrls = array_map(function ($src) { |
203 | return trim(explode(' ', $src, 2)[0]); | 235 | return trim(explode(' ', $src, 2)[0]); |
204 | }, $srcset); | 236 | }, $srcset); |
205 | $urls = array_merge($srcsetUrls, $urls); | 237 | $urls = array_merge($srcsetUrls, $urls); |
206 | } | 238 | } |
239 | |||
207 | $iterator->next(); | 240 | $iterator->next(); |
208 | } | 241 | } |
209 | 242 | ||
@@ -260,33 +293,29 @@ class DownloadImages | |||
260 | return $url; | 293 | return $url; |
261 | } | 294 | } |
262 | 295 | ||
263 | $base = new \SimplePie_IRI($base); | 296 | $base = new Uri($base); |
264 | 297 | ||
265 | // remove '//' in URL path (causes URLs not to resolve properly) | 298 | // in case the url has no scheme & host |
266 | if (isset($base->ipath)) { | 299 | if ('' === $base->getAuthority() || '' === $base->getScheme()) { |
267 | $base->ipath = preg_replace('!//+!', '/', $base->ipath); | 300 | $this->logger->error('DownloadImages: Can not make an absolute link', ['base' => $base, 'url' => $url]); |
268 | } | ||
269 | 301 | ||
270 | if ($absolute = \SimplePie_IRI::absolutize($base, $url)) { | 302 | return false; |
271 | return $absolute->get_uri(); | ||
272 | } | 303 | } |
273 | 304 | ||
274 | $this->logger->error('DownloadImages: Can not make an absolute link', ['base' => $base, 'url' => $url]); | 305 | return (string) UriResolver::resolve($base, new Uri($url)); |
275 | |||
276 | return false; | ||
277 | } | 306 | } |
278 | 307 | ||
279 | /** | 308 | /** |
280 | * Retrieve and validate the extension from the response of the url of the image. | 309 | * Retrieve and validate the extension from the response of the url of the image. |
281 | * | 310 | * |
282 | * @param Response $res Guzzle Response | 311 | * @param ResponseInterface $res Http Response |
283 | * @param string $imagePath Path from the src image from the content (used for log only) | 312 | * @param string $imagePath Path from the src image from the content (used for log only) |
284 | * | 313 | * |
285 | * @return string|false Extension name or false if validation failed | 314 | * @return string|false Extension name or false if validation failed |
286 | */ | 315 | */ |
287 | private function getExtensionFromResponse(Response $res, $imagePath) | 316 | private function getExtensionFromResponse(ResponseInterface $res, $imagePath) |
288 | { | 317 | { |
289 | $ext = $this->mimeGuesser->guess($res->getHeader('content-type')); | 318 | $ext = $this->mimeGuesser->guess(current($res->getHeader('content-type'))); |
290 | $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); | 319 | $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); |
291 | 320 | ||
292 | // ok header doesn't have the extension, try a different way | 321 | // ok header doesn't have the extension, try a different way |
diff --git a/src/Wallabag/CoreBundle/Helper/EntriesExport.php b/src/Wallabag/CoreBundle/Helper/EntriesExport.php index cbf1037b..f981ee50 100644 --- a/src/Wallabag/CoreBundle/Helper/EntriesExport.php +++ b/src/Wallabag/CoreBundle/Helper/EntriesExport.php | |||
@@ -85,7 +85,7 @@ class EntriesExport | |||
85 | public function updateAuthor($method) | 85 | public function updateAuthor($method) |
86 | { | 86 | { |
87 | if ('entry' !== $method) { | 87 | if ('entry' !== $method) { |
88 | $this->author = $method . ' authors'; | 88 | $this->author = 'Various authors'; |
89 | 89 | ||
90 | return $this; | 90 | return $this; |
91 | } | 91 | } |
@@ -150,8 +150,6 @@ class EntriesExport | |||
150 | */ | 150 | */ |
151 | 151 | ||
152 | $book->setTitle($this->title); | 152 | $book->setTitle($this->title); |
153 | // Could also be the ISBN number, prefered for published books, or a UUID. | ||
154 | $book->setIdentifier($this->title, EPub::IDENTIFIER_URI); | ||
155 | // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc. | 153 | // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc. |
156 | $book->setLanguage($this->language); | 154 | $book->setLanguage($this->language); |
157 | $book->setDescription('Some articles saved on my wallabag'); | 155 | $book->setDescription('Some articles saved on my wallabag'); |
@@ -167,12 +165,9 @@ class EntriesExport | |||
167 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'PHP'); | 165 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'PHP'); |
168 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'wallabag'); | 166 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'wallabag'); |
169 | 167 | ||
170 | /* | 168 | $entryIds = []; |
171 | * Front page | 169 | $entryCount = \count($this->entries); |
172 | */ | 170 | $i = 0; |
173 | if (file_exists($this->logoPath)) { | ||
174 | $book->setCoverImage('Cover.png', file_get_contents($this->logoPath), 'image/png'); | ||
175 | } | ||
176 | 171 | ||
177 | /* | 172 | /* |
178 | * Adding actual entries | 173 | * Adding actual entries |
@@ -180,21 +175,48 @@ class EntriesExport | |||
180 | 175 | ||
181 | // set tags as subjects | 176 | // set tags as subjects |
182 | foreach ($this->entries as $entry) { | 177 | foreach ($this->entries as $entry) { |
178 | ++$i; | ||
179 | |||
180 | /* | ||
181 | * Front page | ||
182 | * Set if there's only one entry in the given set | ||
183 | */ | ||
184 | if (1 === $entryCount && null !== $entry->getPreviewPicture()) { | ||
185 | $book->setCoverImage($entry->getPreviewPicture()); | ||
186 | } | ||
187 | |||
183 | foreach ($entry->getTags() as $tag) { | 188 | foreach ($entry->getTags() as $tag) { |
184 | $book->setSubject($tag->getLabel()); | 189 | $book->setSubject($tag->getLabel()); |
185 | } | 190 | } |
191 | $filename = sha1(sprintf('%s:%s', $entry->getUrl(), $entry->getTitle())); | ||
186 | 192 | ||
187 | // the reader in Kobo Devices doesn't likes special caracters | 193 | $publishedBy = $entry->getPublishedBy(); |
188 | // in filenames, we limit to A-z/0-9 | 194 | $authors = $this->translator->trans('export.unknown'); |
189 | $filename = preg_replace('/[^A-Za-z0-9\-]/', '', $entry->getTitle()); | 195 | if (!empty($publishedBy)) { |
196 | $authors = implode(',', $publishedBy); | ||
197 | } | ||
190 | 198 | ||
191 | $titlepage = $content_start . '<h1>' . $entry->getTitle() . '</h1>' . $this->getExportInformation('PHPePub') . $bookEnd; | 199 | $titlepage = $content_start . |
192 | $book->addChapter('Title', 'Title.html', $titlepage, true, EPub::EXTERNAL_REF_ADD); | 200 | '<h1>' . $entry->getTitle() . '</h1>' . |
201 | '<dl>' . | ||
202 | '<dt>' . $this->translator->trans('entry.view.published_by') . '</dt><dd>' . $authors . '</dd>' . | ||
203 | '<dt>' . $this->translator->trans('entry.metadata.reading_time') . '</dt><dd>' . $this->translator->trans('entry.metadata.reading_time_minutes_short', ['%readingTime%' => $entry->getReadingTime()]) . '</dd>' . | ||
204 | '<dt>' . $this->translator->trans('entry.metadata.added_on') . '</dt><dd>' . $entry->getCreatedAt()->format('Y-m-d') . '</dd>' . | ||
205 | '<dt>' . $this->translator->trans('entry.metadata.address') . '</dt><dd><a href="' . $entry->getUrl() . '">' . $entry->getUrl() . '</a></dd>' . | ||
206 | '</dl>' . | ||
207 | $bookEnd; | ||
208 | $book->addChapter("Entry {$i} of {$entryCount}", "{$filename}_cover.html", $titlepage, true, EPub::EXTERNAL_REF_ADD); | ||
193 | $chapter = $content_start . $entry->getContent() . $bookEnd; | 209 | $chapter = $content_start . $entry->getContent() . $bookEnd; |
194 | $book->addChapter($entry->getTitle(), htmlspecialchars($filename) . '.html', $chapter, true, EPub::EXTERNAL_REF_ADD); | 210 | |
211 | $entryIds[] = $entry->getId(); | ||
212 | $book->addChapter($entry->getTitle(), "{$filename}.html", $chapter, true, EPub::EXTERNAL_REF_ADD); | ||
195 | } | 213 | } |
196 | 214 | ||
197 | $book->buildTOC(); | 215 | $book->addChapter('Notices', 'Cover2.html', $content_start . $this->getExportInformation('PHPePub') . $bookEnd); |
216 | |||
217 | // Could also be the ISBN number, prefered for published books, or a UUID. | ||
218 | $hash = sha1(sprintf('%s:%s', $this->wallabagUrl, implode(',', $entryIds))); | ||
219 | $book->setIdentifier(sprintf('urn:wallabag:%s', $hash), EPub::IDENTIFIER_URI); | ||
198 | 220 | ||
199 | return Response::create( | 221 | return Response::create( |
200 | $book->getBook(), | 222 | $book->getBook(), |
@@ -202,7 +224,7 @@ class EntriesExport | |||
202 | [ | 224 | [ |
203 | 'Content-Description' => 'File Transfer', | 225 | 'Content-Description' => 'File Transfer', |
204 | 'Content-type' => 'application/epub+zip', | 226 | 'Content-type' => 'application/epub+zip', |
205 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.epub"', | 227 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.epub"', |
206 | 'Content-Transfer-Encoding' => 'binary', | 228 | 'Content-Transfer-Encoding' => 'binary', |
207 | ] | 229 | ] |
208 | ); | 230 | ); |
@@ -244,9 +266,6 @@ class EntriesExport | |||
244 | } | 266 | } |
245 | $mobi->setContentProvider($content); | 267 | $mobi->setContentProvider($content); |
246 | 268 | ||
247 | // the browser inside Kindle Devices doesn't likes special caracters either, we limit to A-z/0-9 | ||
248 | $this->title = preg_replace('/[^A-Za-z0-9\-]/', '', $this->title); | ||
249 | |||
250 | return Response::create( | 269 | return Response::create( |
251 | $mobi->toString(), | 270 | $mobi->toString(), |
252 | 200, | 271 | 200, |
@@ -254,7 +273,7 @@ class EntriesExport | |||
254 | 'Accept-Ranges' => 'bytes', | 273 | 'Accept-Ranges' => 'bytes', |
255 | 'Content-Description' => 'File Transfer', | 274 | 'Content-Description' => 'File Transfer', |
256 | 'Content-type' => 'application/x-mobipocket-ebook', | 275 | 'Content-type' => 'application/x-mobipocket-ebook', |
257 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.mobi"', | 276 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.mobi"', |
258 | 'Content-Transfer-Encoding' => 'binary', | 277 | 'Content-Transfer-Encoding' => 'binary', |
259 | ] | 278 | ] |
260 | ); | 279 | ); |
@@ -279,14 +298,6 @@ class EntriesExport | |||
279 | $pdf->SetKeywords('wallabag'); | 298 | $pdf->SetKeywords('wallabag'); |
280 | 299 | ||
281 | /* | 300 | /* |
282 | * Front page | ||
283 | */ | ||
284 | $pdf->AddPage(); | ||
285 | $intro = '<h1>' . $this->title . '</h1>' . $this->getExportInformation('tcpdf'); | ||
286 | |||
287 | $pdf->writeHTMLCell(0, 0, '', '', $intro, 0, 1, 0, true, '', true); | ||
288 | |||
289 | /* | ||
290 | * Adding actual entries | 301 | * Adding actual entries |
291 | */ | 302 | */ |
292 | foreach ($this->entries as $entry) { | 303 | foreach ($this->entries as $entry) { |
@@ -294,6 +305,22 @@ class EntriesExport | |||
294 | $pdf->SetKeywords($tag->getLabel()); | 305 | $pdf->SetKeywords($tag->getLabel()); |
295 | } | 306 | } |
296 | 307 | ||
308 | $publishedBy = $entry->getPublishedBy(); | ||
309 | $authors = $this->translator->trans('export.unknown'); | ||
310 | if (!empty($publishedBy)) { | ||
311 | $authors = implode(',', $publishedBy); | ||
312 | } | ||
313 | |||
314 | $pdf->addPage(); | ||
315 | $html = '<h1>' . $entry->getTitle() . '</h1>' . | ||
316 | '<dl>' . | ||
317 | '<dt>' . $this->translator->trans('entry.view.published_by') . '</dt><dd>' . $authors . '</dd>' . | ||
318 | '<dt>' . $this->translator->trans('entry.metadata.reading_time') . '</dt><dd>' . $this->translator->trans('entry.metadata.reading_time_minutes_short', ['%readingTime%' => $entry->getReadingTime()]) . '</dd>' . | ||
319 | '<dt>' . $this->translator->trans('entry.metadata.added_on') . '</dt><dd>' . $entry->getCreatedAt()->format('Y-m-d') . '</dd>' . | ||
320 | '<dt>' . $this->translator->trans('entry.metadata.address') . '</dt><dd><a href="' . $entry->getUrl() . '">' . $entry->getUrl() . '</a></dd>' . | ||
321 | '</dl>'; | ||
322 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); | ||
323 | |||
297 | $pdf->AddPage(); | 324 | $pdf->AddPage(); |
298 | $html = '<h1>' . $entry->getTitle() . '</h1>'; | 325 | $html = '<h1>' . $entry->getTitle() . '</h1>'; |
299 | $html .= $entry->getContent(); | 326 | $html .= $entry->getContent(); |
@@ -301,6 +328,14 @@ class EntriesExport | |||
301 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); | 328 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); |
302 | } | 329 | } |
303 | 330 | ||
331 | /* | ||
332 | * Last page | ||
333 | */ | ||
334 | $pdf->AddPage(); | ||
335 | $html = $this->getExportInformation('tcpdf'); | ||
336 | |||
337 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); | ||
338 | |||
304 | // set image scale factor | 339 | // set image scale factor |
305 | $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); | 340 | $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); |
306 | 341 | ||
@@ -310,7 +345,7 @@ class EntriesExport | |||
310 | [ | 345 | [ |
311 | 'Content-Description' => 'File Transfer', | 346 | 'Content-Description' => 'File Transfer', |
312 | 'Content-type' => 'application/pdf', | 347 | 'Content-type' => 'application/pdf', |
313 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.pdf"', | 348 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.pdf"', |
314 | 'Content-Transfer-Encoding' => 'binary', | 349 | 'Content-Transfer-Encoding' => 'binary', |
315 | ] | 350 | ] |
316 | ); | 351 | ); |
@@ -356,7 +391,7 @@ class EntriesExport | |||
356 | 200, | 391 | 200, |
357 | [ | 392 | [ |
358 | 'Content-type' => 'application/csv', | 393 | 'Content-type' => 'application/csv', |
359 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.csv"', | 394 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.csv"', |
360 | 'Content-Transfer-Encoding' => 'UTF-8', | 395 | 'Content-Transfer-Encoding' => 'UTF-8', |
361 | ] | 396 | ] |
362 | ); | 397 | ); |
@@ -374,7 +409,7 @@ class EntriesExport | |||
374 | 200, | 409 | 200, |
375 | [ | 410 | [ |
376 | 'Content-type' => 'application/json', | 411 | 'Content-type' => 'application/json', |
377 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.json"', | 412 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.json"', |
378 | 'Content-Transfer-Encoding' => 'UTF-8', | 413 | 'Content-Transfer-Encoding' => 'UTF-8', |
379 | ] | 414 | ] |
380 | ); | 415 | ); |
@@ -392,7 +427,7 @@ class EntriesExport | |||
392 | 200, | 427 | 200, |
393 | [ | 428 | [ |
394 | 'Content-type' => 'application/xml', | 429 | 'Content-type' => 'application/xml', |
395 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.xml"', | 430 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.xml"', |
396 | 'Content-Transfer-Encoding' => 'UTF-8', | 431 | 'Content-Transfer-Encoding' => 'UTF-8', |
397 | ] | 432 | ] |
398 | ); | 433 | ); |
@@ -418,7 +453,7 @@ class EntriesExport | |||
418 | 200, | 453 | 200, |
419 | [ | 454 | [ |
420 | 'Content-type' => 'text/plain', | 455 | 'Content-type' => 'text/plain', |
421 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.txt"', | 456 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.txt"', |
422 | 'Content-Transfer-Encoding' => 'UTF-8', | 457 | 'Content-Transfer-Encoding' => 'UTF-8', |
423 | ] | 458 | ] |
424 | ); | 459 | ); |
@@ -461,4 +496,15 @@ class EntriesExport | |||
461 | 496 | ||
462 | return str_replace('%IMAGE%', '', $info); | 497 | return str_replace('%IMAGE%', '', $info); |
463 | } | 498 | } |
499 | |||
500 | /** | ||
501 | * Return a sanitized version of the title by applying translit iconv | ||
502 | * and removing non alphanumeric characters, - and space. | ||
503 | * | ||
504 | * @return string Sanitized filename | ||
505 | */ | ||
506 | private function getSanitizedFilename() | ||
507 | { | ||
508 | return preg_replace('/[^A-Za-z0-9\- \']/', '', iconv('utf-8', 'us-ascii//TRANSLIT', $this->title)); | ||
509 | } | ||
464 | } | 510 | } |
diff --git a/src/Wallabag/CoreBundle/Helper/FileCookieJar.php b/src/Wallabag/CoreBundle/Helper/FileCookieJar.php new file mode 100644 index 00000000..9a63e949 --- /dev/null +++ b/src/Wallabag/CoreBundle/Helper/FileCookieJar.php | |||
@@ -0,0 +1,91 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Helper; | ||
4 | |||
5 | use GuzzleHttp\Cookie\FileCookieJar as BaseFileCookieJar; | ||
6 | use GuzzleHttp\Cookie\SetCookie; | ||
7 | use GuzzleHttp\Utils; | ||
8 | use Psr\Log\LoggerInterface; | ||
9 | |||
10 | /** | ||
11 | * Overidden Cookie behavior to: | ||
12 | * - fix multiple concurrent writes (see https://github.com/guzzle/guzzle/pull/1884) | ||
13 | * - ignore error when the cookie file is malformatted (resulting in clearing it). | ||
14 | */ | ||
15 | class FileCookieJar extends BaseFileCookieJar | ||
16 | { | ||
17 | private $logger; | ||
18 | |||
19 | /** | ||
20 | * @param LoggerInterface $logger Only used to log info when something goes wrong | ||
21 | * @param string $cookieFile File to store the cookie data | ||
22 | */ | ||
23 | public function __construct(LoggerInterface $logger, $cookieFile) | ||
24 | { | ||
25 | parent::__construct($cookieFile); | ||
26 | |||
27 | $this->logger = $logger; | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * Saves the cookies to a file. | ||
32 | * | ||
33 | * @param string $filename File to save | ||
34 | * | ||
35 | * @throws \RuntimeException if the file cannot be found or created | ||
36 | */ | ||
37 | public function save($filename) | ||
38 | { | ||
39 | $json = []; | ||
40 | foreach ($this as $cookie) { | ||
41 | if ($cookie->getExpires() && !$cookie->getDiscard()) { | ||
42 | $json[] = $cookie->toArray(); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | if (false === file_put_contents($filename, json_encode($json), LOCK_EX)) { | ||
47 | // @codeCoverageIgnoreStart | ||
48 | throw new \RuntimeException("Unable to save file {$filename}"); | ||
49 | // @codeCoverageIgnoreEnd | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * Load cookies from a JSON formatted file. | ||
55 | * | ||
56 | * Old cookies are kept unless overwritten by newly loaded ones. | ||
57 | * | ||
58 | * @param string $filename cookie file to load | ||
59 | * | ||
60 | * @throws \RuntimeException if the file cannot be loaded | ||
61 | */ | ||
62 | public function load($filename) | ||
63 | { | ||
64 | $json = file_get_contents($filename); | ||
65 | if (false === $json) { | ||
66 | // @codeCoverageIgnoreStart | ||
67 | throw new \RuntimeException("Unable to load file {$filename}"); | ||
68 | // @codeCoverageIgnoreEnd | ||
69 | } | ||
70 | |||
71 | try { | ||
72 | $data = Utils::jsonDecode($json, true); | ||
73 | } catch (\InvalidArgumentException $e) { | ||
74 | $this->logger->error('JSON inside the cookie is broken', [ | ||
75 | 'json' => $json, | ||
76 | 'error_msg' => $e->getMessage(), | ||
77 | ]); | ||
78 | |||
79 | // cookie file is invalid, just ignore the exception and it'll reset the whole cookie file | ||
80 | $data = ''; | ||
81 | } | ||
82 | |||
83 | if (\is_array($data)) { | ||
84 | foreach (Utils::jsonDecode($json, true) as $cookie) { | ||
85 | $this->setCookie(new SetCookie($cookie)); | ||
86 | } | ||
87 | } elseif (\strlen($data)) { | ||
88 | throw new \RuntimeException("Invalid cookie file: {$filename}"); | ||
89 | } | ||
90 | } | ||
91 | } | ||
diff --git a/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php index 4602a684..ea864acb 100644 --- a/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php +++ b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php | |||
@@ -2,16 +2,18 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Helper; | 3 | namespace Wallabag\CoreBundle\Helper; |
4 | 4 | ||
5 | use Graby\Ring\Client\SafeCurlHandler; | 5 | use GuzzleHttp\Client as GuzzleClient; |
6 | use GuzzleHttp\Client; | ||
7 | use GuzzleHttp\Cookie\CookieJar; | 6 | use GuzzleHttp\Cookie\CookieJar; |
8 | use GuzzleHttp\Event\SubscriberInterface; | 7 | use GuzzleHttp\Event\SubscriberInterface; |
8 | use Http\Adapter\Guzzle5\Client as GuzzleAdapter; | ||
9 | use Http\Client\HttpClient; | ||
10 | use Http\HttplugBundle\ClientFactory\ClientFactory; | ||
9 | use Psr\Log\LoggerInterface; | 11 | use Psr\Log\LoggerInterface; |
10 | 12 | ||
11 | /** | 13 | /** |
12 | * Builds and configures the Guzzle HTTP client. | 14 | * Builds and configures the HTTP client. |
13 | */ | 15 | */ |
14 | class HttpClientFactory | 16 | class HttpClientFactory implements ClientFactory |
15 | { | 17 | { |
16 | /** @var [\GuzzleHttp\Event\SubscriberInterface] */ | 18 | /** @var [\GuzzleHttp\Event\SubscriberInterface] */ |
17 | private $subscribers = []; | 19 | private $subscribers = []; |
@@ -25,9 +27,7 @@ class HttpClientFactory | |||
25 | /** | 27 | /** |
26 | * HttpClientFactory constructor. | 28 | * HttpClientFactory constructor. |
27 | * | 29 | * |
28 | * @param \GuzzleHttp\Cookie\CookieJar $cookieJar | 30 | * @param string $restrictedAccess This param is a kind of boolean. Values: 0 or 1 |
29 | * @param string $restrictedAccess This param is a kind of boolean. Values: 0 or 1 | ||
30 | * @param LoggerInterface $logger | ||
31 | */ | 31 | */ |
32 | public function __construct(CookieJar $cookieJar, $restrictedAccess, LoggerInterface $logger) | 32 | public function __construct(CookieJar $cookieJar, $restrictedAccess, LoggerInterface $logger) |
33 | { | 33 | { |
@@ -37,35 +37,38 @@ class HttpClientFactory | |||
37 | } | 37 | } |
38 | 38 | ||
39 | /** | 39 | /** |
40 | * @return \GuzzleHttp\Client|null | 40 | * Adds a subscriber to the HTTP client. |
41 | */ | ||
42 | public function addSubscriber(SubscriberInterface $subscriber) | ||
43 | { | ||
44 | $this->subscribers[] = $subscriber; | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * Input an array of configuration to be able to create a HttpClient. | ||
49 | * | ||
50 | * @return HttpClient | ||
41 | */ | 51 | */ |
42 | public function buildHttpClient() | 52 | public function createClient(array $config = []) |
43 | { | 53 | { |
44 | $this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]); | 54 | $this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]); |
45 | 55 | ||
46 | if (0 === (int) $this->restrictedAccess) { | 56 | if (0 === (int) $this->restrictedAccess) { |
47 | return; | 57 | return new GuzzleAdapter(new GuzzleClient($config)); |
48 | } | 58 | } |
49 | 59 | ||
50 | // we clear the cookie to avoid websites who use cookies for analytics | 60 | // we clear the cookie to avoid websites who use cookies for analytics |
51 | $this->cookieJar->clear(); | 61 | $this->cookieJar->clear(); |
52 | // need to set the (shared) cookie jar | 62 | if (!isset($config['defaults']['cookies'])) { |
53 | $client = new Client(['handler' => new SafeCurlHandler(), 'defaults' => ['cookies' => $this->cookieJar]]); | 63 | // need to set the (shared) cookie jar |
64 | $config['defaults']['cookies'] = $this->cookieJar; | ||
65 | } | ||
54 | 66 | ||
67 | $guzzle = new GuzzleClient($config); | ||
55 | foreach ($this->subscribers as $subscriber) { | 68 | foreach ($this->subscribers as $subscriber) { |
56 | $client->getEmitter()->attach($subscriber); | 69 | $guzzle->getEmitter()->attach($subscriber); |
57 | } | 70 | } |
58 | 71 | ||
59 | return $client; | 72 | return new GuzzleAdapter($guzzle); |
60 | } | ||
61 | |||
62 | /** | ||
63 | * Adds a subscriber to the HTTP client. | ||
64 | * | ||
65 | * @param SubscriberInterface $subscriber | ||
66 | */ | ||
67 | public function addSubscriber(SubscriberInterface $subscriber) | ||
68 | { | ||
69 | $this->subscribers[] = $subscriber; | ||
70 | } | 73 | } |
71 | } | 74 | } |
diff --git a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php index 1c2c5093..3d56a6d8 100644 --- a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php +++ b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php | |||
@@ -20,10 +20,9 @@ class PreparePagerForEntries | |||
20 | } | 20 | } |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * @param AdapterInterface $adapter | 23 | * @param User $user If user isn't logged in, we can force it (like for feed) |
24 | * @param User $user If user isn't logged in, we can force it (like for rss) | ||
25 | * | 24 | * |
26 | * @return null|Pagerfanta | 25 | * @return Pagerfanta|null |
27 | */ | 26 | */ |
28 | public function prepare(AdapterInterface $adapter, User $user = null) | 27 | public function prepare(AdapterInterface $adapter, User $user = null) |
29 | { | 28 | { |
diff --git a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php index 63f65067..d48e2469 100644 --- a/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php +++ b/src/Wallabag/CoreBundle/Helper/RuleBasedTagger.php | |||
@@ -6,6 +6,7 @@ use Psr\Log\LoggerInterface; | |||
6 | use RulerZ\RulerZ; | 6 | use RulerZ\RulerZ; |
7 | use Wallabag\CoreBundle\Entity\Entry; | 7 | use Wallabag\CoreBundle\Entity\Entry; |
8 | use Wallabag\CoreBundle\Entity\Tag; | 8 | use Wallabag\CoreBundle\Entity\Tag; |
9 | use Wallabag\CoreBundle\Entity\TaggingRule; | ||
9 | use Wallabag\CoreBundle\Repository\EntryRepository; | 10 | use Wallabag\CoreBundle\Repository\EntryRepository; |
10 | use Wallabag\CoreBundle\Repository\TagRepository; | 11 | use Wallabag\CoreBundle\Repository\TagRepository; |
11 | use Wallabag\UserBundle\Entity\User; | 12 | use Wallabag\UserBundle\Entity\User; |
@@ -55,8 +56,6 @@ class RuleBasedTagger | |||
55 | /** | 56 | /** |
56 | * Apply all the tagging rules defined by a user on its entries. | 57 | * Apply all the tagging rules defined by a user on its entries. |
57 | * | 58 | * |
58 | * @param User $user | ||
59 | * | ||
60 | * @return array<Entry> A list of modified entries | 59 | * @return array<Entry> A list of modified entries |
61 | */ | 60 | */ |
62 | public function tagAllForUser(User $user) | 61 | public function tagAllForUser(User $user) |
@@ -108,8 +107,6 @@ class RuleBasedTagger | |||
108 | /** | 107 | /** |
109 | * Retrieves the tagging rules for a given user. | 108 | * Retrieves the tagging rules for a given user. |
110 | * | 109 | * |
111 | * @param User $user | ||
112 | * | ||
113 | * @return array<TaggingRule> | 110 | * @return array<TaggingRule> |
114 | */ | 111 | */ |
115 | private function getRulesForUser(User $user) | 112 | private function getRulesForUser(User $user) |
diff --git a/src/Wallabag/CoreBundle/Helper/TagsAssigner.php b/src/Wallabag/CoreBundle/Helper/TagsAssigner.php index e6b4989f..433b09fe 100644 --- a/src/Wallabag/CoreBundle/Helper/TagsAssigner.php +++ b/src/Wallabag/CoreBundle/Helper/TagsAssigner.php | |||
@@ -21,7 +21,6 @@ class TagsAssigner | |||
21 | /** | 21 | /** |
22 | * Assign some tags to an entry. | 22 | * Assign some tags to an entry. |
23 | * | 23 | * |
24 | * @param Entry $entry | ||
25 | * @param array|string $tags An array of tag or a string coma separated of tag | 24 | * @param array|string $tags An array of tag or a string coma separated of tag |
26 | * @param array $entitiesReady Entities from the EntityManager which are persisted but not yet flushed | 25 | * @param array $entitiesReady Entities from the EntityManager which are persisted but not yet flushed |
27 | * It is mostly to fix duplicate tag on import @see http://stackoverflow.com/a/7879164/569101 | 26 | * It is mostly to fix duplicate tag on import @see http://stackoverflow.com/a/7879164/569101 |
diff --git a/src/Wallabag/CoreBundle/Helper/UrlHasher.php b/src/Wallabag/CoreBundle/Helper/UrlHasher.php new file mode 100644 index 00000000..6753745f --- /dev/null +++ b/src/Wallabag/CoreBundle/Helper/UrlHasher.php | |||
@@ -0,0 +1,22 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Helper; | ||
4 | |||
5 | /** | ||
6 | * Hash URLs for privacy and performance. | ||
7 | */ | ||
8 | class UrlHasher | ||
9 | { | ||
10 | /** | ||
11 | * Hash the given url using the given algorithm. | ||
12 | * Hashed url are faster to be retrieved in the database than the real url. | ||
13 | * | ||
14 | * @param string $algorithm | ||
15 | * | ||
16 | * @return string | ||
17 | */ | ||
18 | public static function hashUrl(string $url, $algorithm = 'sha1') | ||
19 | { | ||
20 | return hash($algorithm, urldecode($url)); | ||
21 | } | ||
22 | } | ||
diff --git a/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php b/src/Wallabag/CoreBundle/ParamConverter/UsernameFeedTokenConverter.php index 4a2fcab5..e220abfc 100644 --- a/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php +++ b/src/Wallabag/CoreBundle/ParamConverter/UsernameFeedTokenConverter.php | |||
@@ -10,12 +10,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | |||
10 | use Wallabag\UserBundle\Entity\User; | 10 | use Wallabag\UserBundle\Entity\User; |
11 | 11 | ||
12 | /** | 12 | /** |
13 | * ParamConverter used in the RSS controller to retrieve the right user according to | 13 | * ParamConverter used in the Feed controller to retrieve the right user according to |
14 | * username & token given in the url. | 14 | * username & token given in the url. |
15 | * | 15 | * |
16 | * @see http://stfalcon.com/en/blog/post/symfony2-custom-paramconverter | 16 | * @see http://stfalcon.com/en/blog/post/symfony2-custom-paramconverter |
17 | */ | 17 | */ |
18 | class UsernameRssTokenConverter implements ParamConverterInterface | 18 | class UsernameFeedTokenConverter implements ParamConverterInterface |
19 | { | 19 | { |
20 | private $registry; | 20 | private $registry; |
21 | 21 | ||
@@ -67,7 +67,7 @@ class UsernameRssTokenConverter implements ParamConverterInterface | |||
67 | public function apply(Request $request, ParamConverter $configuration) | 67 | public function apply(Request $request, ParamConverter $configuration) |
68 | { | 68 | { |
69 | $username = $request->attributes->get('username'); | 69 | $username = $request->attributes->get('username'); |
70 | $rssToken = $request->attributes->get('token'); | 70 | $feedToken = $request->attributes->get('token'); |
71 | 71 | ||
72 | if (!$request->attributes->has('username') || !$request->attributes->has('token')) { | 72 | if (!$request->attributes->has('username') || !$request->attributes->has('token')) { |
73 | return false; | 73 | return false; |
@@ -78,8 +78,8 @@ class UsernameRssTokenConverter implements ParamConverterInterface | |||
78 | 78 | ||
79 | $userRepository = $em->getRepository($configuration->getClass()); | 79 | $userRepository = $em->getRepository($configuration->getClass()); |
80 | 80 | ||
81 | // Try to find user by its username and config rss_token | 81 | // Try to find user by its username and config feed_token |
82 | $user = $userRepository->findOneByUsernameAndRsstoken($username, $rssToken); | 82 | $user = $userRepository->findOneByUsernameAndFeedtoken($username, $feedToken); |
83 | 83 | ||
84 | if (null === $user || !($user instanceof User)) { | 84 | if (null === $user || !($user instanceof User)) { |
85 | throw new NotFoundHttpException(sprintf('%s not found.', $configuration->getClass())); | 85 | throw new NotFoundHttpException(sprintf('%s not found.', $configuration->getClass())); |
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index 83379998..bfd07937 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php | |||
@@ -3,11 +3,13 @@ | |||
3 | namespace Wallabag\CoreBundle\Repository; | 3 | namespace Wallabag\CoreBundle\Repository; |
4 | 4 | ||
5 | use Doctrine\ORM\EntityRepository; | 5 | use Doctrine\ORM\EntityRepository; |
6 | use Doctrine\ORM\NoResultException; | ||
6 | use Doctrine\ORM\QueryBuilder; | 7 | use Doctrine\ORM\QueryBuilder; |
7 | use Pagerfanta\Adapter\DoctrineORMAdapter; | 8 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
8 | use Pagerfanta\Pagerfanta; | 9 | use Pagerfanta\Pagerfanta; |
9 | use Wallabag\CoreBundle\Entity\Entry; | 10 | use Wallabag\CoreBundle\Entity\Entry; |
10 | use Wallabag\CoreBundle\Entity\Tag; | 11 | use Wallabag\CoreBundle\Entity\Tag; |
12 | use Wallabag\CoreBundle\Helper\UrlHasher; | ||
11 | 13 | ||
12 | class EntryRepository extends EntityRepository | 14 | class EntryRepository extends EntityRepository |
13 | { | 15 | { |
@@ -50,7 +52,7 @@ class EntryRepository extends EntityRepository | |||
50 | public function getBuilderForArchiveByUser($userId) | 52 | public function getBuilderForArchiveByUser($userId) |
51 | { | 53 | { |
52 | return $this | 54 | return $this |
53 | ->getSortedQueryBuilderByUser($userId) | 55 | ->getSortedQueryBuilderByUser($userId, 'archivedAt', 'desc') |
54 | ->andWhere('e.isArchived = true') | 56 | ->andWhere('e.isArchived = true') |
55 | ; | 57 | ; |
56 | } | 58 | } |
@@ -110,8 +112,7 @@ class EntryRepository extends EntityRepository | |||
110 | */ | 112 | */ |
111 | public function getBuilderForUntaggedByUser($userId) | 113 | public function getBuilderForUntaggedByUser($userId) |
112 | { | 114 | { |
113 | return $this | 115 | return $this->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId)); |
114 | ->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId)); | ||
115 | } | 116 | } |
116 | 117 | ||
117 | /** | 118 | /** |
@@ -129,6 +130,21 @@ class EntryRepository extends EntityRepository | |||
129 | } | 130 | } |
130 | 131 | ||
131 | /** | 132 | /** |
133 | * Retrieve the number of untagged entries for a user. | ||
134 | * | ||
135 | * @param int $userId | ||
136 | * | ||
137 | * @return int | ||
138 | */ | ||
139 | public function countUntaggedEntriesByUser($userId) | ||
140 | { | ||
141 | return (int) $this->getRawBuilderForUntaggedByUser($userId) | ||
142 | ->select('count(e.id)') | ||
143 | ->getQuery() | ||
144 | ->getSingleScalarResult(); | ||
145 | } | ||
146 | |||
147 | /** | ||
132 | * Find Entries. | 148 | * Find Entries. |
133 | * | 149 | * |
134 | * @param int $userId | 150 | * @param int $userId |
@@ -139,15 +155,30 @@ class EntryRepository extends EntityRepository | |||
139 | * @param string $order | 155 | * @param string $order |
140 | * @param int $since | 156 | * @param int $since |
141 | * @param string $tags | 157 | * @param string $tags |
158 | * @param string $detail 'metadata' or 'full'. Include content field if 'full' | ||
159 | * | ||
160 | * @todo Breaking change: replace default detail=full by detail=metadata in a future version | ||
142 | * | 161 | * |
143 | * @return Pagerfanta | 162 | * @return Pagerfanta |
144 | */ | 163 | */ |
145 | public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'ASC', $since = 0, $tags = '') | 164 | public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '', $detail = 'full') |
146 | { | 165 | { |
166 | if (!\in_array(strtolower($detail), ['full', 'metadata'], true)) { | ||
167 | throw new \Exception('Detail "' . $detail . '" parameter is wrong, allowed: full or metadata'); | ||
168 | } | ||
169 | |||
147 | $qb = $this->createQueryBuilder('e') | 170 | $qb = $this->createQueryBuilder('e') |
148 | ->leftJoin('e.tags', 't') | 171 | ->leftJoin('e.tags', 't') |
149 | ->where('e.user = :userId')->setParameter('userId', $userId); | 172 | ->where('e.user = :userId')->setParameter('userId', $userId); |
150 | 173 | ||
174 | if ('metadata' === $detail) { | ||
175 | $fieldNames = $this->getClassMetadata()->getFieldNames(); | ||
176 | $fields = array_filter($fieldNames, function ($k) { | ||
177 | return 'content' !== $k; | ||
178 | }); | ||
179 | $qb->select(sprintf('partial e.{%s}', implode(',', $fields))); | ||
180 | } | ||
181 | |||
151 | if (null !== $isArchived) { | 182 | if (null !== $isArchived) { |
152 | $qb->andWhere('e.isArchived = :isArchived')->setParameter('isArchived', (bool) $isArchived); | 183 | $qb->andWhere('e.isArchived = :isArchived')->setParameter('isArchived', (bool) $isArchived); |
153 | } | 184 | } |
@@ -185,10 +216,16 @@ class EntryRepository extends EntityRepository | |||
185 | } | 216 | } |
186 | } | 217 | } |
187 | 218 | ||
219 | if (!\in_array(strtolower($order), ['asc', 'desc'], true)) { | ||
220 | throw new \Exception('Order "' . $order . '" parameter is wrong, allowed: asc or desc'); | ||
221 | } | ||
222 | |||
188 | if ('created' === $sort) { | 223 | if ('created' === $sort) { |
189 | $qb->orderBy('e.id', $order); | 224 | $qb->orderBy('e.id', $order); |
190 | } elseif ('updated' === $sort) { | 225 | } elseif ('updated' === $sort) { |
191 | $qb->orderBy('e.updatedAt', $order); | 226 | $qb->orderBy('e.updatedAt', $order); |
227 | } elseif ('archived' === $sort) { | ||
228 | $qb->orderBy('e.archivedAt', $order); | ||
192 | } | 229 | } |
193 | 230 | ||
194 | $pagerAdapter = new DoctrineORMAdapter($qb, true, false); | 231 | $pagerAdapter = new DoctrineORMAdapter($qb, true, false); |
@@ -269,7 +306,6 @@ class EntryRepository extends EntityRepository | |||
269 | * DELETE et FROM entry_tag et WHERE et.entry_id IN ( SELECT e.id FROM entry e WHERE e.user_id = :userId ) AND et.tag_id = :tagId | 306 | * DELETE et FROM entry_tag et WHERE et.entry_id IN ( SELECT e.id FROM entry e WHERE e.user_id = :userId ) AND et.tag_id = :tagId |
270 | * | 307 | * |
271 | * @param int $userId | 308 | * @param int $userId |
272 | * @param Tag $tag | ||
273 | */ | 309 | */ |
274 | public function removeTag($userId, Tag $tag) | 310 | public function removeTag($userId, Tag $tag) |
275 | { | 311 | { |
@@ -320,15 +356,44 @@ class EntryRepository extends EntityRepository | |||
320 | * Find an entry by its url and its owner. | 356 | * Find an entry by its url and its owner. |
321 | * If it exists, return the entry otherwise return false. | 357 | * If it exists, return the entry otherwise return false. |
322 | * | 358 | * |
323 | * @param $url | 359 | * @param string $url |
324 | * @param $userId | 360 | * @param int $userId |
325 | * | 361 | * |
326 | * @return Entry|bool | 362 | * @return Entry|false |
327 | */ | 363 | */ |
328 | public function findByUrlAndUserId($url, $userId) | 364 | public function findByUrlAndUserId($url, $userId) |
329 | { | 365 | { |
366 | return $this->findByHashedUrlAndUserId( | ||
367 | UrlHasher::hashUrl($url), | ||
368 | $userId | ||
369 | ); | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * Find an entry by its hashed url and its owner. | ||
374 | * If it exists, return the entry otherwise return false. | ||
375 | * | ||
376 | * @param string $hashedUrl Url hashed using sha1 | ||
377 | * @param int $userId | ||
378 | * | ||
379 | * @return Entry|false | ||
380 | */ | ||
381 | public function findByHashedUrlAndUserId($hashedUrl, $userId) | ||
382 | { | ||
383 | // try first using hashed_url (to use the database index) | ||
330 | $res = $this->createQueryBuilder('e') | 384 | $res = $this->createQueryBuilder('e') |
331 | ->where('e.url = :url')->setParameter('url', urldecode($url)) | 385 | ->where('e.hashedUrl = :hashed_url')->setParameter('hashed_url', $hashedUrl) |
386 | ->andWhere('e.user = :user_id')->setParameter('user_id', $userId) | ||
387 | ->getQuery() | ||
388 | ->getResult(); | ||
389 | |||
390 | if (\count($res)) { | ||
391 | return current($res); | ||
392 | } | ||
393 | |||
394 | // then try using hashed_given_url (to use the database index) | ||
395 | $res = $this->createQueryBuilder('e') | ||
396 | ->where('e.hashedGivenUrl = :hashed_given_url')->setParameter('hashed_given_url', $hashedUrl) | ||
332 | ->andWhere('e.user = :user_id')->setParameter('user_id', $userId) | 397 | ->andWhere('e.user = :user_id')->setParameter('user_id', $userId) |
333 | ->getQuery() | 398 | ->getQuery() |
334 | ->getResult(); | 399 | ->getResult(); |
@@ -412,8 +477,8 @@ class EntryRepository extends EntityRepository | |||
412 | /** | 477 | /** |
413 | * Find all entries by url and owner. | 478 | * Find all entries by url and owner. |
414 | * | 479 | * |
415 | * @param $url | 480 | * @param string $url |
416 | * @param $userId | 481 | * @param int $userId |
417 | * | 482 | * |
418 | * @return array | 483 | * @return array |
419 | */ | 484 | */ |
@@ -427,6 +492,49 @@ class EntryRepository extends EntityRepository | |||
427 | } | 492 | } |
428 | 493 | ||
429 | /** | 494 | /** |
495 | * Returns a random entry, filtering by status. | ||
496 | * | ||
497 | * @param int $userId | ||
498 | * @param string $type Can be unread, archive, starred, etc | ||
499 | * | ||
500 | * @throws NoResultException | ||
501 | * | ||
502 | * @return Entry | ||
503 | */ | ||
504 | public function getRandomEntry($userId, $type = '') | ||
505 | { | ||
506 | $qb = $this->getQueryBuilderByUser($userId) | ||
507 | ->select('e.id'); | ||
508 | |||
509 | switch ($type) { | ||
510 | case 'unread': | ||
511 | $qb->andWhere('e.isArchived = false'); | ||
512 | break; | ||
513 | case 'archive': | ||
514 | $qb->andWhere('e.isArchived = true'); | ||
515 | break; | ||
516 | case 'starred': | ||
517 | $qb->andWhere('e.isStarred = true'); | ||
518 | break; | ||
519 | case 'untagged': | ||
520 | $qb->leftJoin('e.tags', 't'); | ||
521 | $qb->andWhere('t.id is null'); | ||
522 | break; | ||
523 | } | ||
524 | |||
525 | $ids = $qb->getQuery()->getArrayResult(); | ||
526 | |||
527 | if (empty($ids)) { | ||
528 | throw new NoResultException(); | ||
529 | } | ||
530 | |||
531 | // random select one in the list | ||
532 | $randomId = $ids[mt_rand(0, \count($ids) - 1)]['id']; | ||
533 | |||
534 | return $this->find($randomId); | ||
535 | } | ||
536 | |||
537 | /** | ||
430 | * Return a query builder to be used by other getBuilderFor* method. | 538 | * Return a query builder to be used by other getBuilderFor* method. |
431 | * | 539 | * |
432 | * @param int $userId | 540 | * @param int $userId |
@@ -456,15 +564,13 @@ class EntryRepository extends EntityRepository | |||
456 | /** | 564 | /** |
457 | * Return the given QueryBuilder with an orderBy() call. | 565 | * Return the given QueryBuilder with an orderBy() call. |
458 | * | 566 | * |
459 | * @param QueryBuilder $qb | 567 | * @param string $sortBy |
460 | * @param string $sortBy | 568 | * @param string $direction |
461 | * @param string $direction | ||
462 | * | 569 | * |
463 | * @return QueryBuilder | 570 | * @return QueryBuilder |
464 | */ | 571 | */ |
465 | private function sortQueryBuilder(QueryBuilder $qb, $sortBy = 'createdAt', $direction = 'desc') | 572 | private function sortQueryBuilder(QueryBuilder $qb, $sortBy = 'createdAt', $direction = 'desc') |
466 | { | 573 | { |
467 | return $qb | 574 | return $qb->orderBy(sprintf('e.%s', $sortBy), $direction); |
468 | ->orderBy(sprintf('e.%s', $sortBy), $direction); | ||
469 | } | 575 | } |
470 | } | 576 | } |
diff --git a/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php b/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php index 36906761..aeadd770 100644 --- a/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php +++ b/src/Wallabag/CoreBundle/Repository/SiteCredentialRepository.php | |||
@@ -19,16 +19,16 @@ class SiteCredentialRepository extends \Doctrine\ORM\EntityRepository | |||
19 | /** | 19 | /** |
20 | * Retrieve one username/password for the given host and userId. | 20 | * Retrieve one username/password for the given host and userId. |
21 | * | 21 | * |
22 | * @param string $host | 22 | * @param array $hosts An array of host to look for |
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 findOneByHostsAndUser($hosts, $userId) |
28 | { | 28 | { |
29 | $res = $this->createQueryBuilder('s') | 29 | $res = $this->createQueryBuilder('s') |
30 | ->select('s.username', 's.password') | 30 | ->select('s.username', 's.password') |
31 | ->where('s.host = :hostname')->setParameter('hostname', $host) | 31 | ->where('s.host IN (:hosts)')->setParameter('hosts', $hosts) |
32 | ->andWhere('s.user = :userId')->setParameter('userId', $userId) | 32 | ->andWhere('s.user = :userId')->setParameter('userId', $userId) |
33 | ->setMaxResults(1) | 33 | ->setMaxResults(1) |
34 | ->getQuery() | 34 | ->getQuery() |
diff --git a/src/Wallabag/CoreBundle/Repository/TagRepository.php b/src/Wallabag/CoreBundle/Repository/TagRepository.php index 3ae9d414..8464a6a5 100644 --- a/src/Wallabag/CoreBundle/Repository/TagRepository.php +++ b/src/Wallabag/CoreBundle/Repository/TagRepository.php | |||
@@ -3,6 +3,7 @@ | |||
3 | namespace Wallabag\CoreBundle\Repository; | 3 | namespace Wallabag\CoreBundle\Repository; |
4 | 4 | ||
5 | use Doctrine\ORM\EntityRepository; | 5 | use Doctrine\ORM\EntityRepository; |
6 | use Doctrine\ORM\QueryBuilder; | ||
6 | use Wallabag\CoreBundle\Entity\Tag; | 7 | use Wallabag\CoreBundle\Entity\Tag; |
7 | 8 | ||
8 | class TagRepository extends EntityRepository | 9 | class TagRepository extends EntityRepository |
@@ -45,12 +46,8 @@ class TagRepository extends EntityRepository | |||
45 | */ | 46 | */ |
46 | public function findAllTags($userId) | 47 | public function findAllTags($userId) |
47 | { | 48 | { |
48 | $ids = $this->createQueryBuilder('t') | 49 | $ids = $this->getQueryBuilderByUser($userId) |
49 | ->select('t.id') | 50 | ->select('t.id') |
50 | ->leftJoin('t.entries', 'e') | ||
51 | ->where('e.user = :userId')->setParameter('userId', $userId) | ||
52 | ->groupBy('t.id') | ||
53 | ->orderBy('t.slug') | ||
54 | ->getQuery() | 51 | ->getQuery() |
55 | ->getArrayResult(); | 52 | ->getArrayResult(); |
56 | 53 | ||
@@ -71,18 +68,30 @@ class TagRepository extends EntityRepository | |||
71 | */ | 68 | */ |
72 | public function findAllFlatTagsWithNbEntries($userId) | 69 | public function findAllFlatTagsWithNbEntries($userId) |
73 | { | 70 | { |
74 | return $this->createQueryBuilder('t') | 71 | return $this->getQueryBuilderByUser($userId) |
75 | ->select('t.id, t.label, t.slug, count(e.id) as nbEntries') | 72 | ->select('t.id, t.label, t.slug, count(e.id) as nbEntries') |
76 | ->distinct(true) | 73 | ->distinct(true) |
77 | ->leftJoin('t.entries', 'e') | ||
78 | ->where('e.user = :userId') | ||
79 | ->groupBy('t.id') | ||
80 | ->orderBy('t.slug') | ||
81 | ->setParameter('userId', $userId) | ||
82 | ->getQuery() | 74 | ->getQuery() |
83 | ->getArrayResult(); | 75 | ->getArrayResult(); |
84 | } | 76 | } |
85 | 77 | ||
78 | public function findByLabelsAndUser($labels, $userId) | ||
79 | { | ||
80 | $qb = $this->getQueryBuilderByUser($userId) | ||
81 | ->select('t.id'); | ||
82 | |||
83 | $ids = $qb->andWhere($qb->expr()->in('t.label', $labels)) | ||
84 | ->getQuery() | ||
85 | ->getArrayResult(); | ||
86 | |||
87 | $tags = []; | ||
88 | foreach ($ids as $id) { | ||
89 | $tags[] = $this->find($id); | ||
90 | } | ||
91 | |||
92 | return $tags; | ||
93 | } | ||
94 | |||
86 | /** | 95 | /** |
87 | * Used only in test case to get a tag for our entry. | 96 | * Used only in test case to get a tag for our entry. |
88 | * | 97 | * |
@@ -101,13 +110,9 @@ class TagRepository extends EntityRepository | |||
101 | 110 | ||
102 | public function findForArchivedArticlesByUser($userId) | 111 | public function findForArchivedArticlesByUser($userId) |
103 | { | 112 | { |
104 | $ids = $this->createQueryBuilder('t') | 113 | $ids = $this->getQueryBuilderByUser($userId) |
105 | ->select('t.id') | 114 | ->select('t.id') |
106 | ->leftJoin('t.entries', 'e') | ||
107 | ->where('e.user = :userId')->setParameter('userId', $userId) | ||
108 | ->andWhere('e.isArchived = true') | 115 | ->andWhere('e.isArchived = true') |
109 | ->groupBy('t.id') | ||
110 | ->orderBy('t.slug') | ||
111 | ->getQuery() | 116 | ->getQuery() |
112 | ->getArrayResult(); | 117 | ->getArrayResult(); |
113 | 118 | ||
@@ -118,4 +123,20 @@ class TagRepository extends EntityRepository | |||
118 | 123 | ||
119 | return $tags; | 124 | return $tags; |
120 | } | 125 | } |
126 | |||
127 | /** | ||
128 | * Retrieve a sorted list of tags used by a user. | ||
129 | * | ||
130 | * @param int $userId | ||
131 | * | ||
132 | * @return QueryBuilder | ||
133 | */ | ||
134 | private function getQueryBuilderByUser($userId) | ||
135 | { | ||
136 | return $this->createQueryBuilder('t') | ||
137 | ->leftJoin('t.entries', 'e') | ||
138 | ->where('e.user = :userId')->setParameter('userId', $userId) | ||
139 | ->groupBy('t.id') | ||
140 | ->orderBy('t.slug'); | ||
141 | } | ||
121 | } | 142 | } |
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index 85306276..3f3d4de7 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml | |||
@@ -22,10 +22,10 @@ services: | |||
22 | tags: | 22 | tags: |
23 | - { name: form.type } | 23 | - { name: form.type } |
24 | 24 | ||
25 | wallabag_core.param_converter.username_rsstoken_converter: | 25 | wallabag_core.param_converter.username_feed_token_converter: |
26 | class: Wallabag\CoreBundle\ParamConverter\UsernameRssTokenConverter | 26 | class: Wallabag\CoreBundle\ParamConverter\UsernameFeedTokenConverter |
27 | tags: | 27 | tags: |
28 | - { name: request.param_converter, converter: username_rsstoken_converter } | 28 | - { name: request.param_converter, converter: username_feed_token_converter } |
29 | arguments: | 29 | arguments: |
30 | - "@doctrine" | 30 | - "@doctrine" |
31 | 31 | ||
@@ -42,7 +42,7 @@ services: | |||
42 | - | 42 | - |
43 | error_message: '%wallabag_core.fetching_error_message%' | 43 | error_message: '%wallabag_core.fetching_error_message%' |
44 | error_message_title: '%wallabag_core.fetching_error_message_title%' | 44 | error_message_title: '%wallabag_core.fetching_error_message_title%' |
45 | - "@wallabag_core.guzzle.http_client" | 45 | - "@wallabag_core.http_client" |
46 | - "@wallabag_core.graby.config_builder" | 46 | - "@wallabag_core.graby.config_builder" |
47 | calls: | 47 | calls: |
48 | - [ setLogger, [ "@logger" ] ] | 48 | - [ setLogger, [ "@logger" ] ] |
@@ -55,9 +55,8 @@ services: | |||
55 | - {} | 55 | - {} |
56 | - "@logger" | 56 | - "@logger" |
57 | 57 | ||
58 | wallabag_core.guzzle.http_client: | 58 | wallabag_core.http_client: |
59 | class: GuzzleHttp\ClientInterface | 59 | alias: 'httplug.client.wallabag_core' |
60 | factory: ["@wallabag_core.guzzle.http_client_factory", buildHttpClient] | ||
61 | 60 | ||
62 | wallabag_core.guzzle_authenticator.config_builder: | 61 | wallabag_core.guzzle_authenticator.config_builder: |
63 | class: Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder | 62 | class: Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder |
@@ -73,7 +72,7 @@ services: | |||
73 | bd_guzzle_site_authenticator.site_config_builder: | 72 | bd_guzzle_site_authenticator.site_config_builder: |
74 | alias: wallabag_core.guzzle_authenticator.config_builder | 73 | alias: wallabag_core.guzzle_authenticator.config_builder |
75 | 74 | ||
76 | wallabag_core.guzzle.http_client_factory: | 75 | wallabag_core.http_client_factory: |
77 | class: Wallabag\CoreBundle\Helper\HttpClientFactory | 76 | class: Wallabag\CoreBundle\Helper\HttpClientFactory |
78 | arguments: | 77 | arguments: |
79 | - "@wallabag_core.guzzle.cookie_jar" | 78 | - "@wallabag_core.guzzle.cookie_jar" |
@@ -83,8 +82,10 @@ services: | |||
83 | - ["addSubscriber", ["@bd_guzzle_site_authenticator.authenticator_subscriber"]] | 82 | - ["addSubscriber", ["@bd_guzzle_site_authenticator.authenticator_subscriber"]] |
84 | 83 | ||
85 | wallabag_core.guzzle.cookie_jar: | 84 | wallabag_core.guzzle.cookie_jar: |
86 | class: GuzzleHttp\Cookie\FileCookieJar | 85 | class: Wallabag\CoreBundle\Helper\FileCookieJar |
87 | arguments: ["%kernel.cache_dir%/cookiejar.json"] | 86 | arguments: |
87 | - "@logger" | ||
88 | - "%kernel.cache_dir%/cookiejar.json" | ||
88 | 89 | ||
89 | wallabag_core.content_proxy: | 90 | wallabag_core.content_proxy: |
90 | class: Wallabag\CoreBundle\Helper\ContentProxy | 91 | class: Wallabag\CoreBundle\Helper\ContentProxy |
@@ -181,6 +182,7 @@ services: | |||
181 | 182 | ||
182 | wallabag_core.exception_controller: | 183 | wallabag_core.exception_controller: |
183 | class: Wallabag\CoreBundle\Controller\ExceptionController | 184 | class: Wallabag\CoreBundle\Controller\ExceptionController |
185 | public: true | ||
184 | arguments: | 186 | arguments: |
185 | - '@twig' | 187 | - '@twig' |
186 | - '%kernel.debug%' | 188 | - '%kernel.debug%' |
@@ -211,10 +213,38 @@ services: | |||
211 | - "@logger" | 213 | - "@logger" |
212 | 214 | ||
213 | wallabag_core.entry.download_images.client: | 215 | wallabag_core.entry.download_images.client: |
214 | class: GuzzleHttp\Client | 216 | alias: 'httplug.client.wallabag_core.entry.download_images' |
215 | 217 | ||
216 | wallabag_core.helper.crypto_proxy: | 218 | wallabag_core.helper.crypto_proxy: |
217 | class: Wallabag\CoreBundle\Helper\CryptoProxy | 219 | class: Wallabag\CoreBundle\Helper\CryptoProxy |
218 | arguments: | 220 | arguments: |
219 | - "%wallabag_core.site_credentials.encryption_key_path%" | 221 | - "%wallabag_core.site_credentials.encryption_key_path%" |
220 | - "@logger" | 222 | - "@logger" |
223 | |||
224 | wallabag_core.command.clean_duplicates: | ||
225 | class: Wallabag\CoreBundle\Command\CleanDuplicatesCommand | ||
226 | tags: ['console.command'] | ||
227 | |||
228 | wallabag_core.command.export: | ||
229 | class: Wallabag\CoreBundle\Command\ExportCommand | ||
230 | tags: ['console.command'] | ||
231 | |||
232 | wallabag_core.command.install: | ||
233 | class: Wallabag\CoreBundle\Command\InstallCommand | ||
234 | tags: ['console.command'] | ||
235 | |||
236 | wallabag_core.command.list_user: | ||
237 | class: Wallabag\CoreBundle\Command\ListUserCommand | ||
238 | tags: ['console.command'] | ||
239 | |||
240 | wallabag_core.command.reload_entry: | ||
241 | class: Wallabag\CoreBundle\Command\ReloadEntryCommand | ||
242 | tags: ['console.command'] | ||
243 | |||
244 | wallabag_core.command.show_user: | ||
245 | class: Wallabag\CoreBundle\Command\ShowUserCommand | ||
246 | tags: ['console.command'] | ||
247 | |||
248 | wallabag_core.command.tag_all: | ||
249 | class: Wallabag\CoreBundle\Command\TagAllCommand | ||
250 | tags: ['console.command'] | ||
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml index e3ff21f1..47de066f 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Tilbage til de ulæste artikler' | 33 | back_to_unread: 'Tilbage til de ulæste artikler' |
34 | # users_management: 'Users management' | 34 | # users_management: 'Users management' |
35 | # site_credentials: 'Site credentials' | 35 | # site_credentials: 'Site credentials' |
36 | # quickstart: "Quickstart" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Tilføj ny artikel' | 38 | add_new_entry: 'Tilføj ny artikel' |
38 | search: 'Søg' | 39 | search: 'Søg' |
39 | filter_entries: 'Filtrer artikler' | 40 | filter_entries: 'Filtrer artikler' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | # export: 'Export' | 42 | # export: 'Export' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Indtast søgning' | 44 | input_label: 'Indtast søgning' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Opsætning' | 55 | page_title: 'Opsætning' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Indstillinger' | 57 | settings: 'Indstillinger' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Brugeroplysninger' | 59 | user_info: 'Brugeroplysninger' |
58 | password: 'Adgangskode' | 60 | password: 'Adgangskode' |
59 | # rules: 'Tagging rules' | 61 | # rules: 'Tagging rules' |
60 | new_user: 'Tilføj bruger' | 62 | new_user: 'Tilføj bruger' |
63 | # reset: 'Reset area' | ||
61 | form: | 64 | form: |
62 | save: 'Gem' | 65 | save: 'Gem' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Poster pr. side' | 68 | items_per_page_label: 'Poster pr. side' |
66 | language_label: 'Sprog' | 69 | language_label: 'Sprog' |
67 | reading_speed: | 70 | reading_speed: |
68 | # label: 'Reading speed' | 71 | # label: 'Reading speed (words per minute)' |
69 | # help_message: 'You can use online tools to estimate your reading speed:' | 72 | # help_message: 'You can use online tools to estimate your reading speed:' |
70 | # 100_word: 'I read ~100 words per minute' | ||
71 | # 200_word: 'I read ~200 words per minute' | ||
72 | # 300_word: 'I read ~300 words per minute' | ||
73 | # 400_word: 'I read ~400 words per minute' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | # label: 'Where do you want to be redirected to after marking an article as read?' | 74 | # label: 'Where do you want to be redirected to after marking an article as read?' |
76 | # redirect_homepage: 'To the homepage' | 75 | # redirect_homepage: 'To the homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." | 82 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." |
84 | # help_language: "You can change the language of wallabag interface." | 83 | # help_language: "You can change the language of wallabag interface." |
85 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." | 84 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'RSS-feeds fra wallabag gør det muligt at læse de artikler, der gemmes i wallabag, med din RSS-læser. Det kræver, at du genererer et token først.' | 86 | description: 'RSS-feeds fra wallabag gør det muligt at læse de artikler, der gemmes i wallabag, med din RSS-læser. Det kræver, at du genererer et token først.' |
88 | token_label: 'RSS-Token' | 87 | token_label: 'RSS-Token' |
89 | no_token: 'Intet token' | 88 | no_token: 'Intet token' |
90 | token_create: 'Opret token' | 89 | token_create: 'Opret token' |
91 | token_reset: 'Nulstil token' | 90 | token_reset: 'Nulstil token' |
92 | rss_links: 'RSS-Links' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'RSS-Links' |
93 | feed_link: | ||
94 | unread: 'Ulæst' | 94 | unread: 'Ulæst' |
95 | starred: 'Favoritter' | 95 | starred: 'Favoritter' |
96 | archive: 'Arkiv' | 96 | archive: 'Arkiv' |
97 | # all: 'All' | 97 | # all: 'All' |
98 | # rss_limit: 'Number of items in the feed' | 98 | # feed_limit: 'Number of items in the feed' |
99 | form_user: | 99 | form_user: |
100 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'Navn' | 102 | name_label: 'Navn' |
102 | email_label: 'Emailadresse' | 103 | email_label: 'Emailadresse' |
103 | # twoFactorAuthentication_label: 'Two factor authentication' | 104 | two_factor: |
104 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 105 | # emailTwoFactor_label: 'Using email (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. |
@@ -127,6 +136,15 @@ config: | |||
127 | # edit_rule_label: 'edit' | 136 | # edit_rule_label: 'edit' |
128 | # rule_label: 'Rule' | 137 | # rule_label: 'Rule' |
129 | # tags_label: 'Tags' | 138 | # tags_label: 'Tags' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | # faq: | 148 | # faq: |
131 | # title: 'FAQ' | 149 | # title: 'FAQ' |
132 | # tagging_rules_definition_title: 'What does « tagging rules » mean?' | 150 | # tagging_rules_definition_title: 'What does « tagging rules » mean?' |
@@ -159,6 +177,15 @@ config: | |||
159 | # and: 'One rule AND another' | 177 | # 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>' | 178 | # 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>' | 179 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | # default_title: 'Title of the entry' | 191 | # default_title: 'Title of the entry' |
@@ -237,7 +264,7 @@ entry: | |||
237 | # provided_by: 'Provided by' | 264 | # provided_by: 'Provided by' |
238 | new: | 265 | new: |
239 | page_title: 'Gem ny artikel' | 266 | page_title: 'Gem ny artikel' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.dk' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | # delete: "Are you sure you want to remove that article?" | 281 | # delete: "Are you sure you want to remove that article?" |
255 | # delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | # delete_tag: "Are you sure you want to remove that tag from that article?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'Om' | 290 | page_title: 'Om' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | # title: 'Configure the application' | 380 | # title: 'Configure the application' |
349 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' | 381 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' |
350 | # language: 'Change language and design' | 382 | # language: 'Change language and design' |
351 | # rss: 'Enable RSS feeds' | 383 | # feed: 'Enable RSS feeds' |
352 | # tagging_rules: 'Write rules to automatically tag your articles' | 384 | # tagging_rules: 'Write rules to automatically tag your articles' |
353 | # admin: | 385 | # admin: |
354 | # title: 'Administration' | 386 | # title: 'Administration' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' | 429 | # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' |
398 | # see_untagged_entries: 'See untagged entries' | 430 | # see_untagged_entries: 'See untagged entries' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | # add: 'Add' | 433 | # add: 'Add' |
401 | # placeholder: 'You can add several tags, separated by a comma.' | 434 | # placeholder: 'You can add several tags, separated by a comma.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
402 | 437 | ||
403 | # export: | 438 | # export: |
404 | # 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>' | 439 | # 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>' |
440 | # unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | # page_title: 'Import' | 443 | # page_title: 'Import' |
@@ -429,6 +465,9 @@ import: | |||
429 | # wallabag_v2: | 465 | # wallabag_v2: |
430 | # page_title: 'Import > Wallabag v2' | 466 | # page_title: 'Import > Wallabag v2' |
431 | # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' | 467 | # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | # readability: | 471 | # readability: |
433 | # page_title: 'Import > Readability' | 472 | # page_title: 'Import > Readability' |
434 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' | 473 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' |
@@ -482,6 +521,7 @@ developer: | |||
482 | # redirect_uris_label: 'Redirect URIs' | 521 | # redirect_uris_label: 'Redirect URIs' |
483 | # save_label: 'Create a new client' | 522 | # save_label: 'Create a new client' |
484 | # action_back: 'Back' | 523 | # action_back: 'Back' |
524 | # copy_to_clipboard: Copy | ||
485 | # client_parameter: | 525 | # client_parameter: |
486 | # page_title: 'API clients management > Client parameters' | 526 | # page_title: 'API clients management > Client parameters' |
487 | # page_description: 'Here are your client parameters.' | 527 | # page_description: 'Here are your client parameters.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'Emailadresse' | 563 | email_label: 'Emailadresse' |
524 | # enabled_label: 'Enabled' | 564 | # enabled_label: 'Enabled' |
525 | # last_login_label: 'Last login' | 565 | # last_login_label: 'Last login' |
526 | # twofactor_label: Two factor authentication | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
527 | # save: Save | 568 | # save: Save |
528 | # delete: Delete | 569 | # delete: Delete |
529 | # delete_confirm: Are you sure? | 570 | # delete_confirm: Are you sure? |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | # create_new_one: Create a new credential | 585 | # create_new_one: Create a new credential |
545 | # form: | 586 | # form: |
546 | # username_label: 'Username' | 587 | # username_label: 'Username' |
547 | # host_label: 'Host' | 588 | # host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | # password_label: 'Password' | 589 | # password_label: 'Password' |
549 | # save: Save | 590 | # save: Save |
550 | # delete: Delete | 591 | # delete: Delete |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Adgangskode opdateret' | 602 | password_updated: 'Adgangskode opdateret' |
562 | # password_not_updated_demo: "In demonstration mode, you can't change password for this user." | 603 | # password_not_updated_demo: "In demonstration mode, you can't change password for this user." |
563 | user_updated: 'Oplysninger opdateret' | 604 | user_updated: 'Oplysninger opdateret' |
564 | rss_updated: 'RSS-oplysninger opdateret' | 605 | feed_updated: 'RSS-oplysninger opdateret' |
565 | # tagging_rules_updated: 'Tagging rules updated' | 606 | # tagging_rules_updated: 'Tagging rules updated' |
566 | # tagging_rules_deleted: 'Tagging rule deleted' | 607 | # tagging_rules_deleted: 'Tagging rule deleted' |
567 | # rss_token_updated: 'RSS token updated' | 608 | # feed_token_updated: 'RSS token updated' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
568 | # annotations_reset: Annotations reset | 610 | # annotations_reset: Annotations reset |
569 | # tags_reset: Tags reset | 611 | # tags_reset: Tags reset |
570 | # entries_reset: Entries reset | 612 | # entries_reset: Entries reset |
571 | # archived_reset: Archived entries deleted | 613 | # archived_reset: Archived entries deleted |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | # entry_already_saved: 'Entry already saved on %date%' | 619 | # entry_already_saved: 'Entry already saved on %date%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Artikel markeret som favorit' | 627 | entry_starred: 'Artikel markeret som favorit' |
583 | entry_unstarred: 'Artikel ikke længere markeret som favorit' | 628 | entry_unstarred: 'Artikel ikke længere markeret som favorit' |
584 | entry_deleted: 'Artikel slettet' | 629 | entry_deleted: 'Artikel slettet' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | # tag_added: 'Tag added' | 633 | # tag_added: 'Tag added' |
634 | # tag_renamed: 'Tag renamed' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | # failed: 'Import failed, please try again.' | 637 | # 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 c297ffb5..50e67d47 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Zurück zu ungelesenen Artikeln' | 33 | back_to_unread: 'Zurück zu ungelesenen Artikeln' |
34 | users_management: 'Benutzerverwaltung' | 34 | users_management: 'Benutzerverwaltung' |
35 | site_credentials: 'Zugangsdaten' | 35 | site_credentials: 'Zugangsdaten' |
36 | quickstart: "Schnelleinstieg" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Neuen Artikel hinzufügen' | 38 | add_new_entry: 'Neuen Artikel hinzufügen' |
38 | search: 'Suche' | 39 | search: 'Suche' |
39 | filter_entries: 'Artikel filtern' | 40 | filter_entries: 'Artikel filtern' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | export: 'Exportieren' | 42 | export: 'Exportieren' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Suchbegriff hier eingeben' | 44 | input_label: 'Suchbegriff hier eingeben' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Einstellungen' | 55 | page_title: 'Einstellungen' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Einstellungen' | 57 | settings: 'Einstellungen' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Benutzerinformation' | 59 | user_info: 'Benutzerinformation' |
58 | password: 'Kennwort' | 60 | password: 'Kennwort' |
59 | rules: 'Tagging-Regeln' | 61 | rules: 'Tagging-Regeln' |
60 | new_user: 'Benutzer hinzufügen' | 62 | new_user: 'Benutzer hinzufügen' |
63 | reset: 'Zurücksetzen' | ||
61 | form: | 64 | form: |
62 | save: 'Speichern' | 65 | save: 'Speichern' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Einträge pro Seite' | 68 | items_per_page_label: 'Einträge pro Seite' |
66 | language_label: 'Sprache' | 69 | language_label: 'Sprache' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Lesegeschwindigkeit' | 71 | label: 'Lesegeschwindigkeit (Wörter pro Minute)' |
69 | help_message: 'Du kannst Online-Tools nutzen, um deine Lesegeschwindigkeit herauszufinden.' | 72 | help_message: 'Du kannst Online-Tools nutzen, um deine Lesegeschwindigkeit herauszufinden.' |
70 | 100_word: 'Ich lese ~100 Wörter pro Minute' | ||
71 | 200_word: 'Ich lese ~200 Wörter pro Minute' | ||
72 | 300_word: 'Ich lese ~300 Wörter pro Minute' | ||
73 | 400_word: 'Ich lese ~400 Wörter pro Minute' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: 'Wohin soll nach dem Gelesenmarkieren eines Artikels weitergeleitet werden?' | 74 | label: 'Wohin soll nach dem Gelesenmarkieren eines Artikels weitergeleitet werden?' |
76 | redirect_homepage: 'Zur Homepage' | 75 | redirect_homepage: 'Zur Homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag berechnet eine Lesezeit pro Artikel. Hier kannst du definieren, ob du ein schneller oder langsamer Leser bist. wallabag wird die Lesezeiten danach neu berechnen." | 82 | help_reading_speed: "wallabag berechnet eine Lesezeit pro Artikel. Hier kannst du definieren, ob du ein schneller oder langsamer Leser bist. wallabag wird die Lesezeiten danach neu berechnen." |
84 | help_language: "Du kannst die Sprache der wallabag-Oberfläche ändern." | 83 | help_language: "Du kannst die Sprache der wallabag-Oberfläche ändern." |
85 | help_pocket_consumer_key: "Nötig für den Pocket-Import. Du kannst ihn in deinem Pocket account einrichten." | 84 | help_pocket_consumer_key: "Nötig für den Pocket-Import. Du kannst ihn in deinem Pocket account einrichten." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'Die RSS-Feeds von wallabag erlauben es dir, deine gespeicherten Artikel mit deinem bevorzugten RSS-Reader zu lesen. Vorher musst du jedoch einen Token erstellen.' | 86 | description: 'Die RSS-Feeds von wallabag erlauben es dir, deine gespeicherten Artikel mit deinem bevorzugten RSS-Reader zu lesen. Vorher musst du jedoch einen Token erstellen.' |
88 | token_label: 'RSS-Token' | 87 | token_label: 'RSS-Token' |
89 | no_token: 'Kein Token' | 88 | no_token: 'Kein Token' |
90 | token_create: 'Token erstellen' | 89 | token_create: 'Token erstellen' |
91 | token_reset: 'Token zurücksetzen' | 90 | token_reset: 'Token zurücksetzen' |
92 | rss_links: 'RSS-Links' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'RSS-Links' |
93 | feed_link: | ||
94 | unread: 'Ungelesene' | 94 | unread: 'Ungelesene' |
95 | starred: 'Favoriten' | 95 | starred: 'Favoriten' |
96 | archive: 'Archivierte' | 96 | archive: 'Archivierte' |
97 | all: 'Alle' | 97 | all: 'Alle' |
98 | rss_limit: 'Anzahl der Einträge pro Feed' | 98 | feed_limit: 'Anzahl der Einträge pro Feed' |
99 | form_user: | 99 | 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" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'Name' | 102 | name_label: 'Name' |
102 | email_label: 'E-Mail-Adresse' | 103 | email_label: 'E-Mail-Adresse' |
103 | twoFactorAuthentication_label: 'Zwei-Faktor-Authentifizierung' | 104 | two_factor: |
104 | help_twoFactorAuthentication: "Wenn du 2FA aktivierst, wirst du bei jedem Login einen Code per E-Mail bekommen." | 105 | # emailTwoFactor_label: 'Using email (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: 'Lösche mein Konto (a.k.a Gefahrenzone)' | 115 | 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.' | 116 | 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.' |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'bearbeiten' | 136 | edit_rule_label: 'bearbeiten' |
128 | rule_label: 'Regel' | 137 | rule_label: 'Regel' |
129 | tags_label: 'Tags' | 138 | tags_label: 'Tags' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: 'Was bedeuten die "Tagging-Regeln"?' | 150 | tagging_rules_definition_title: 'Was bedeuten die "Tagging-Regeln"?' |
@@ -159,6 +177,15 @@ config: | |||
159 | and: 'Eine Regel UND eine andere' | 177 | and: 'Eine Regel UND eine andere' |
160 | matches: 'Testet, ob eine <i>Variable</i> auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title matches "Fußball"</code>' | 178 | matches: 'Testet, ob eine <i>Variable</i> auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title matches "Fußball"</code>' |
161 | notmatches: 'Testet, ob ein <i>Titel</i> nicht auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title notmatches "Fußball"</code>' | 179 | notmatches: 'Testet, ob ein <i>Titel</i> nicht auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title notmatches "Fußball"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'Titel des Eintrags' | 191 | default_title: 'Titel des Eintrags' |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | delete: 'Bist du sicher, dass du diesen Artikel löschen möchtest?' | 281 | delete: 'Bist du sicher, dass du diesen Artikel löschen möchtest?' |
255 | delete_tag: 'Bist du sicher, dass du diesen Tag vom Artikel entfernen möchtest?' | 282 | delete_tag: 'Bist du sicher, dass du diesen Tag vom Artikel entfernen möchtest?' |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'Über' | 290 | page_title: 'Über' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: 'Anwendung konfigurieren' | 380 | title: 'Anwendung konfigurieren' |
349 | description: 'Um die Applikation für dich anzupassen, schau in die Konfiguration von wallabag.' | 381 | description: 'Um die Applikation für dich anzupassen, schau in die Konfiguration von wallabag.' |
350 | language: 'Sprache und Design ändern' | 382 | language: 'Sprache und Design ändern' |
351 | rss: 'RSS-Feeds aktivieren' | 383 | feed: 'RSS-Feeds aktivieren' |
352 | tagging_rules: 'Schreibe Regeln, um deine Beiträge automatisch zu taggen (verschlagworten)' | 384 | tagging_rules: 'Schreibe Regeln, um deine Beiträge automatisch zu taggen (verschlagworten)' |
353 | admin: | 385 | admin: |
354 | title: 'Administration' | 386 | title: 'Administration' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: '{0} Es gibt keine Tags.|{1} Es gibt einen Tag.|]1,Inf[ Es gibt %count% Tags.' | 429 | number_on_the_page: '{0} Es gibt keine Tags.|{1} Es gibt einen Tag.|]1,Inf[ Es gibt %count% Tags.' |
398 | see_untagged_entries: 'Zeige nicht getaggte Einträge' | 430 | see_untagged_entries: 'Zeige nicht getaggte Einträge' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | add: 'Hinzufügen' | 433 | add: 'Hinzufügen' |
401 | placeholder: 'Du kannst verschiedene Tags, getrennt von einem Komma, hinzufügen.' | 434 | placeholder: 'Du kannst verschiedene Tags, getrennt von einem Komma, hinzufügen.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
402 | 437 | ||
403 | export: | 438 | export: |
404 | 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>' | 439 | 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>' |
440 | # unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Importieren' | 443 | page_title: 'Importieren' |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Aus wallabag v2 importieren' | 466 | page_title: 'Aus wallabag v2 importieren' |
431 | description: 'Dieser Import wird all deine Artikel aus wallabag v2 importieren. Gehe auf "Alle Artikel" und dann, in der Exportieren-Seitenleiste auf "JSON". Dabei erhältst du eine "All articles.json"-Datei.' | 467 | description: 'Dieser Import wird all deine Artikel aus wallabag v2 importieren. Gehe auf "Alle Artikel" und dann, in der Exportieren-Seitenleiste auf "JSON". Dabei erhältst du eine "All articles.json"-Datei.' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Aus Readability importieren' | 472 | page_title: 'Aus Readability importieren' |
434 | description: 'Dieser Import wird all deine Artikel aus Readability importieren. Auf der Tools Seite (https://www.readability.com/tools/) klickst du auf "Exportiere deine Daten" in dem Abschnitt "Datenexport". Du wirst eine E-Mail mit einem Downloadlink zu einer json Datei, die aber nicht auf .json endet, erhalten' | 473 | description: 'Dieser Import wird all deine Artikel aus Readability importieren. Auf der Tools Seite (https://www.readability.com/tools/) klickst du auf "Exportiere deine Daten" in dem Abschnitt "Datenexport". Du wirst eine E-Mail mit einem Downloadlink zu einer json Datei, die aber nicht auf .json endet, erhalten' |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: 'Weiterleitungs-URIs' | 521 | redirect_uris_label: 'Weiterleitungs-URIs' |
483 | save_label: 'Neuen Client erstellen' | 522 | save_label: 'Neuen Client erstellen' |
484 | action_back: 'Zurück' | 523 | action_back: 'Zurück' |
524 | # copy_to_clipboard: Copy | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: 'API-Client-Verwaltung > Client-Parameter' | 526 | page_title: 'API-Client-Verwaltung > Client-Parameter' |
487 | page_description: 'Dies sind deine Client-Parameter.' | 527 | page_description: 'Dies sind deine Client-Parameter.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'E-Mail-Adresse' | 563 | email_label: 'E-Mail-Adresse' |
524 | enabled_label: 'Aktiviert' | 564 | enabled_label: 'Aktiviert' |
525 | last_login_label: 'Letzter Login' | 565 | last_login_label: 'Letzter Login' |
526 | twofactor_label: 'Zwei-Faktor-Authentifizierung' | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
527 | save: 'Speichern' | 568 | save: 'Speichern' |
528 | delete: 'Löschen' | 569 | delete: 'Löschen' |
529 | delete_confirm: 'Bist du sicher?' | 570 | delete_confirm: 'Bist du sicher?' |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | create_new_one: 'Einen neuen Seitenzugang anlegen' | 585 | create_new_one: 'Einen neuen Seitenzugang anlegen' |
545 | form: | 586 | form: |
546 | username_label: 'Benutzername' | 587 | username_label: 'Benutzername' |
547 | host_label: 'Host' | 588 | host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | password_label: 'Passwort' | 589 | password_label: 'Passwort' |
549 | save: 'Speichern' | 590 | save: 'Speichern' |
550 | delete: 'Löschen' | 591 | delete: 'Löschen' |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Kennwort aktualisiert' | 602 | password_updated: 'Kennwort aktualisiert' |
562 | password_not_updated_demo: 'Im Testmodus kannst du das Kennwort nicht ändern.' | 603 | password_not_updated_demo: 'Im Testmodus kannst du das Kennwort nicht ändern.' |
563 | user_updated: 'Information aktualisiert' | 604 | user_updated: 'Information aktualisiert' |
564 | rss_updated: 'RSS-Informationen aktualisiert' | 605 | feed_updated: 'RSS-Informationen aktualisiert' |
565 | tagging_rules_updated: 'Tagging-Regeln aktualisiert' | 606 | tagging_rules_updated: 'Tagging-Regeln aktualisiert' |
566 | tagging_rules_deleted: 'Tagging-Regel gelöscht' | 607 | tagging_rules_deleted: 'Tagging-Regel gelöscht' |
567 | rss_token_updated: 'RSS-Token aktualisiert' | 608 | feed_token_updated: 'RSS-Token aktualisiert' |
568 | annotations_reset: 'Anmerkungen zurücksetzen' | 609 | # feed_token_revoked: 'RSS token revoked' |
569 | tags_reset: 'Tags zurücksetzen' | 610 | annotations_reset: Anmerkungen zurücksetzen |
570 | entries_reset: 'Einträge zurücksetzen' | 611 | tags_reset: Tags zurücksetzen |
571 | archived_reset: 'Archiverte Einträge zurücksetzen' | 612 | entries_reset: Einträge zurücksetzen |
613 | archived_reset: Archiverte Einträge zurücksetzen | ||
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Eintrag bereits am %date% gespeichert' | 619 | entry_already_saved: 'Eintrag bereits am %date% gespeichert' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Eintrag favorisiert' | 627 | entry_starred: 'Eintrag favorisiert' |
583 | entry_unstarred: 'Eintrag defavorisiert' | 628 | entry_unstarred: 'Eintrag defavorisiert' |
584 | entry_deleted: 'Eintrag gelöscht' | 629 | entry_deleted: 'Eintrag gelöscht' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Tag hinzugefügt' | 633 | tag_added: 'Tag hinzugefügt' |
634 | #tag_renamed: 'Tag renamed' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'Import fehlgeschlagen, bitte erneut probieren.' | 637 | 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 169ae728..27585f77 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml | |||
@@ -5,7 +5,7 @@ security: | |||
5 | forgot_password: 'Forgot your password?' | 5 | forgot_password: 'Forgot your password?' |
6 | submit: 'Login' | 6 | submit: 'Login' |
7 | register: 'Register' | 7 | register: 'Register' |
8 | username: 'Username' | 8 | username: 'Login' |
9 | password: 'Password' | 9 | password: 'Password' |
10 | cancel: 'Cancel' | 10 | cancel: 'Cancel' |
11 | resetting: | 11 | resetting: |
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Back to unread articles' | 33 | back_to_unread: 'Back to unread articles' |
34 | users_management: 'Users management' | 34 | users_management: 'Users management' |
35 | site_credentials: 'Site credentials' | 35 | site_credentials: 'Site credentials' |
36 | quickstart: "Quickstart" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Add a new entry' | 38 | add_new_entry: 'Add a new entry' |
38 | search: 'Search' | 39 | search: 'Search' |
39 | filter_entries: 'Filter entries' | 40 | filter_entries: 'Filter entries' |
41 | random_entry: Jump to a random entry from that list | ||
40 | export: 'Export' | 42 | export: 'Export' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Enter your search here' | 44 | input_label: 'Enter your search here' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Config' | 55 | page_title: 'Config' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Settings' | 57 | settings: 'Settings' |
56 | rss: 'RSS' | 58 | feed: 'Feeds' |
57 | user_info: 'User information' | 59 | user_info: 'User information' |
58 | password: 'Password' | 60 | password: 'Password' |
59 | rules: 'Tagging rules' | 61 | rules: 'Tagging rules' |
60 | new_user: 'Add a user' | 62 | new_user: 'Add a user' |
63 | reset: 'Reset area' | ||
61 | form: | 64 | form: |
62 | save: 'Save' | 65 | save: 'Save' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Items per page' | 68 | items_per_page_label: 'Items per page' |
66 | language_label: 'Language' | 69 | language_label: 'Language' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Reading speed' | 71 | label: 'Reading speed (words per minute)' |
69 | help_message: 'You can use online tools to estimate your reading speed:' | 72 | help_message: 'You can use online tools to estimate your reading speed:' |
70 | 100_word: 'I read ~100 words per minute' | ||
71 | 200_word: 'I read ~200 words per minute' | ||
72 | 300_word: 'I read ~300 words per minute' | ||
73 | 400_word: 'I read ~400 words per minute' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: 'What to do after removing, starring or marking as read an article?' | 74 | label: 'What to do after removing, starring or marking as read an article?' |
76 | redirect_homepage: 'Go to the homepage' | 75 | redirect_homepage: 'Go to the homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." | 82 | help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." |
84 | help_language: "You can change the language of wallabag interface." | 83 | help_language: "You can change the language of wallabag interface." |
85 | help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." | 84 | help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'RSS feeds provided by wallabag allow you to read your saved articles with your favourite RSS reader. You need to generate a token first.' | 86 | description: 'Atom feeds provided by wallabag allow you to read your saved articles with your favourite Atom reader. You need to generate a token first.' |
88 | token_label: 'RSS token' | 87 | token_label: 'Feed token' |
89 | no_token: 'No token' | 88 | no_token: 'No token' |
90 | token_create: 'Create your token' | 89 | token_create: 'Create your token' |
91 | token_reset: 'Regenerate your token' | 90 | token_reset: 'Regenerate your token' |
92 | rss_links: 'RSS links' | 91 | token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'Feed links' |
93 | feed_link: | ||
94 | unread: 'Unread' | 94 | unread: 'Unread' |
95 | starred: 'Starred' | 95 | starred: 'Starred' |
96 | archive: 'Archived' | 96 | archive: 'Archived' |
97 | all: 'All' | 97 | all: 'All' |
98 | rss_limit: 'Number of items in the feed' | 98 | feed_limit: 'Number of items in the feed' |
99 | form_user: | 99 | form_user: |
100 | two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connection." | 100 | 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 | login_label: 'Login (can not be changed)' | ||
101 | name_label: 'Name' | 102 | name_label: 'Name' |
102 | email_label: 'Email' | 103 | email_label: 'Email' |
103 | twoFactorAuthentication_label: 'Two factor authentication' | 104 | two_factor: |
104 | help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 105 | emailTwoFactor_label: 'Using email (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. |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'edit' | 136 | edit_rule_label: 'edit' |
128 | rule_label: 'Rule' | 137 | rule_label: 'Rule' |
129 | tags_label: 'Tags' | 138 | tags_label: 'Tags' |
139 | card: | ||
140 | new_tagging_rule: Create a tagging rule | ||
141 | import_tagging_rules: Import tagging rules | ||
142 | import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | export_tagging_rules: Export tagging rules | ||
144 | export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | file_label: JSON file | ||
146 | import_submit: Import | ||
147 | export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: 'What does « tagging rules » mean?' | 150 | tagging_rules_definition_title: 'What does « tagging rules » mean?' |
@@ -159,6 +177,15 @@ config: | |||
159 | and: 'One rule AND another' | 177 | 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>' | 178 | 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>' | 179 | notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
180 | otp: | ||
181 | page_title: Two-factor authentication | ||
182 | app: | ||
183 | 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. | ||
184 | two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | 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:' | ||
186 | two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | cancel: Cancel | ||
188 | enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'Title of the entry' | 191 | default_title: 'Title of the entry' |
@@ -237,7 +264,7 @@ entry: | |||
237 | provided_by: 'Provided by' | 264 | provided_by: 'Provided by' |
238 | new: | 265 | new: |
239 | page_title: 'Save new entry' | 266 | page_title: 'Save new entry' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.com' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | delete: "Are you sure you want to remove that article?" | 281 | delete: "Are you sure you want to remove that article?" |
255 | delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | delete_tag: "Are you sure you want to remove that tag from that article?" |
283 | metadata: | ||
284 | reading_time: "Estimated reading time" | ||
285 | reading_time_minutes_short: "%readingTime% min" | ||
286 | address: "Address" | ||
287 | added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'About' | 290 | page_title: 'About' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: 'Configure the application' | 380 | title: 'Configure the application' |
349 | description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' | 381 | description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' |
350 | language: 'Change language and design' | 382 | language: 'Change language and design' |
351 | rss: 'Enable RSS feeds' | 383 | feed: 'Enable feeds' |
352 | tagging_rules: 'Write rules to automatically tag your articles' | 384 | tagging_rules: 'Write rules to automatically tag your articles' |
353 | admin: | 385 | admin: |
354 | title: 'Administration' | 386 | title: 'Administration' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: '{0} There are no tags.|{1} There is one tag.|]1,Inf[ There are %count% tags.' | 429 | number_on_the_page: '{0} There are no tags.|{1} There is one tag.|]1,Inf[ There are %count% tags.' |
398 | see_untagged_entries: 'See untagged entries' | 430 | see_untagged_entries: 'See untagged entries' |
431 | no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | add: 'Add' | 433 | add: 'Add' |
401 | placeholder: 'You can add several tags, separated by a comma.' | 434 | placeholder: 'You can add several tags, separated by a comma.' |
435 | rename: | ||
436 | placeholder: 'You can update tag name.' | ||
402 | 437 | ||
403 | export: | 438 | export: |
404 | 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>' | 439 | 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>' |
440 | unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Import' | 443 | page_title: 'Import' |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Import > Wallabag v2' | 466 | page_title: 'Import > Wallabag v2' |
431 | description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' | 467 | description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' |
468 | elcurator: | ||
469 | page_title: 'Import > elCurator' | ||
470 | description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Import > Readability' | 472 | page_title: 'Import > Readability' |
434 | description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' | 473 | description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: 'Redirect URIs (optional)' | 521 | redirect_uris_label: 'Redirect URIs (optional)' |
483 | save_label: 'Create a new client' | 522 | save_label: 'Create a new client' |
484 | action_back: 'Back' | 523 | action_back: 'Back' |
524 | copy_to_clipboard: Copy | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: 'API clients management > Client parameters' | 526 | page_title: 'API clients management > Client parameters' |
487 | page_description: 'Here are your client parameters.' | 527 | page_description: 'Here are your client parameters.' |
@@ -515,7 +555,7 @@ user: | |||
515 | no: No | 555 | no: No |
516 | create_new_one: Create a new user | 556 | create_new_one: Create a new user |
517 | form: | 557 | form: |
518 | username_label: 'Username' | 558 | username_label: 'Login' |
519 | name_label: 'Name' | 559 | name_label: 'Name' |
520 | password_label: 'Password' | 560 | password_label: 'Password' |
521 | repeat_new_password_label: 'Repeat new password' | 561 | repeat_new_password_label: 'Repeat new password' |
@@ -523,13 +563,14 @@ user: | |||
523 | email_label: 'Email' | 563 | email_label: 'Email' |
524 | enabled_label: 'Enabled' | 564 | enabled_label: 'Enabled' |
525 | last_login_label: 'Last login' | 565 | last_login_label: 'Last login' |
526 | twofactor_label: Two factor authentication | 566 | twofactor_email_label: Two factor authentication by email |
567 | twofactor_google_label: Two factor authentication by OTP app | ||
527 | save: Save | 568 | save: Save |
528 | delete: Delete | 569 | delete: Delete |
529 | delete_confirm: Are you sure? | 570 | delete_confirm: Are you sure? |
530 | back_to_list: Back to list | 571 | back_to_list: Back to list |
531 | search: | 572 | search: |
532 | placeholder: Filter by username or email | 573 | placeholder: Filter by login or email |
533 | 574 | ||
534 | site_credential: | 575 | site_credential: |
535 | page_title: Site credentials management | 576 | page_title: Site credentials management |
@@ -543,8 +584,8 @@ site_credential: | |||
543 | no: No | 584 | no: No |
544 | create_new_one: Create a new credential | 585 | create_new_one: Create a new credential |
545 | form: | 586 | form: |
546 | username_label: 'Username' | 587 | username_label: 'Login' |
547 | host_label: 'Host' | 588 | host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | password_label: 'Password' | 589 | password_label: 'Password' |
549 | save: Save | 590 | save: Save |
550 | delete: Delete | 591 | delete: Delete |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Password updated' | 602 | password_updated: 'Password updated' |
562 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." | 603 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." |
563 | user_updated: 'Information updated' | 604 | user_updated: 'Information updated' |
564 | rss_updated: 'RSS information updated' | 605 | feed_updated: 'Feed information updated' |
565 | tagging_rules_updated: 'Tagging rules updated' | 606 | tagging_rules_updated: 'Tagging rules updated' |
566 | tagging_rules_deleted: 'Tagging rule deleted' | 607 | tagging_rules_deleted: 'Tagging rule deleted' |
567 | rss_token_updated: 'RSS token updated' | 608 | feed_token_updated: 'Feed token updated' |
609 | feed_token_revoked: 'RSS token revoked' | ||
568 | annotations_reset: Annotations reset | 610 | annotations_reset: Annotations reset |
569 | tags_reset: Tags reset | 611 | tags_reset: Tags reset |
570 | entries_reset: Entries reset | 612 | entries_reset: Entries reset |
571 | archived_reset: Archived entries deleted | 613 | archived_reset: Archived entries deleted |
614 | otp_enabled: Two-factor authentication enabled | ||
615 | tagging_rules_imported: Tagging rules imported | ||
616 | tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Entry already saved on %date%' | 619 | entry_already_saved: 'Entry already saved on %date%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Entry starred' | 627 | entry_starred: 'Entry starred' |
583 | entry_unstarred: 'Entry unstarred' | 628 | entry_unstarred: 'Entry unstarred' |
584 | entry_deleted: 'Entry deleted' | 629 | entry_deleted: 'Entry deleted' |
630 | no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Tag added' | 633 | tag_added: 'Tag added' |
634 | tag_renamed: 'Tag renamed' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'Import failed, please try again.' | 637 | 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 039a1867..2cf67176 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml | |||
@@ -32,11 +32,13 @@ menu: | |||
32 | save_link: 'Guardar un enlace' | 32 | save_link: 'Guardar un enlace' |
33 | back_to_unread: 'Volver a los artículos sin leer' | 33 | back_to_unread: 'Volver a los artículos sin leer' |
34 | users_management: 'Configuración de usuarios' | 34 | users_management: 'Configuración de usuarios' |
35 | # site_credentials: 'Site credentials' | 35 | site_credentials: 'Credenciales del sitio' |
36 | quickstart: "Inicio rápido" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Añadir un nuevo artículo' | 38 | add_new_entry: 'Añadir un nuevo artículo' |
38 | search: 'Buscar' | 39 | search: 'Buscar' |
39 | filter_entries: 'Filtrar los artículos' | 40 | filter_entries: 'Filtrar los artículos' |
41 | random_entry: 'Ir a un artículo aleatório de esta lista' | ||
40 | export: 'Exportar' | 42 | export: 'Exportar' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Introduzca su búsqueda aquí' | 44 | input_label: 'Introduzca su búsqueda aquí' |
@@ -45,7 +47,7 @@ footer: | |||
45 | wallabag: | 47 | wallabag: |
46 | elsewhere: 'Lleva wallabag contigo' | 48 | elsewhere: 'Lleva wallabag contigo' |
47 | social: 'Social' | 49 | social: 'Social' |
48 | powered_by: 'funciona con' | 50 | powered_by: 'impulsado por' |
49 | about: 'Acerca de' | 51 | about: 'Acerca de' |
50 | stats: Desde el %user_creation% has leído %nb_archives% artículos. ¡Eso hace unos %per_day% por día! | 52 | stats: Desde el %user_creation% has leído %nb_archives% artículos. ¡Eso hace unos %per_day% por día! |
51 | 53 | ||
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Configuración' | 55 | page_title: 'Configuración' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Configuración' | 57 | settings: 'Configuración' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Información de usuario' | 59 | user_info: 'Información de usuario' |
58 | password: 'Contraseña' | 60 | password: 'Contraseña' |
59 | rules: 'Reglas de etiquetado automáticas' | 61 | rules: 'Reglas de etiquetado automáticas' |
60 | new_user: 'Añadir un usuario' | 62 | new_user: 'Añadir un usuario' |
63 | reset: 'Reiniciar mi cuenta' | ||
61 | form: | 64 | form: |
62 | save: 'Guardar' | 65 | save: 'Guardar' |
63 | form_settings: | 66 | form_settings: |
@@ -65,43 +68,49 @@ config: | |||
65 | items_per_page_label: 'Número de artículos por página' | 68 | items_per_page_label: 'Número de artículos por página' |
66 | language_label: 'Idioma' | 69 | language_label: 'Idioma' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Velocidad de lectura' | 71 | label: 'Velocidad de lectura (palabras por minuto)' |
69 | help_message: 'Puede utilizar herramientas en línea para calcular su velocidad de lectura:' | 72 | help_message: 'Puede utilizar herramientas en línea para calcular su velocidad de lectura:' |
70 | 100_word: 'Leo ~100 palabras por minuto' | ||
71 | 200_word: 'Leo ~200 palabras por minuto' | ||
72 | 300_word: 'Leo ~300 palabras por minuto' | ||
73 | 400_word: 'Leo ~400 palabras por minuto' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: '¿Dónde quieres ser redirigido después de marcar un artículo como leído?' | 74 | label: '¿Dónde quieres ser redirigido después de marcar un artículo como leído?' |
76 | redirect_homepage: 'A la página de inicio' | 75 | redirect_homepage: 'A la página de inicio' |
77 | redirect_current_page: 'A la página actual' | 76 | redirect_current_page: 'A la página actual' |
78 | pocket_consumer_key_label: Clave de consumidor para importar contenidos de Pocket | 77 | pocket_consumer_key_label: Clave de consumidor para importar contenidos de Pocket |
79 | android_configuration: Configura tu aplicación Android | 78 | android_configuration: Configura tu aplicación Android |
80 | # android_instruction: "Touch here to prefill your Android application" | 79 | android_instruction: "Toca aquí para prellenar tu aplicación Android" |
81 | help_theme: "wallabag es personalizable. Puedes elegir tu tema preferido aquí." | 80 | help_theme: "wallabag es personalizable. Puedes elegir tu tema preferido aquí." |
82 | help_items_per_page: "Puedes cambiar el número de artículos mostrados en cada página." | 81 | help_items_per_page: "Puedes cambiar el número de artículos mostrados en cada página." |
83 | help_reading_speed: "wallabag calcula un tiempo de lectura para cada artículo. Puedes definir aquí, gracias a esta lista, si eres un lector rápido o lento. wallabag recalculará el tiempo de lectura para cada artículo." | 82 | help_reading_speed: "wallabag calcula un tiempo de lectura para cada artículo. Puedes definir aquí, gracias a esta lista, si eres un lector rápido o lento. wallabag recalculará el tiempo de lectura para cada artículo." |
84 | help_language: "Puedes cambiar el idioma de la interfaz de wallabag." | 83 | help_language: "Puedes cambiar el idioma de la interfaz de wallabag." |
85 | help_pocket_consumer_key: "Requerido para la importación desde Pocket. Puedes crearla en tu cuenta de Pocket." | 84 | help_pocket_consumer_key: "Requerido para la importación desde Pocket. Puedes crearla en tu cuenta de Pocket." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'Los feeds RSS de wallabag permiten leer los artículos guardados con su lector RSS favorito. Primero necesitas generar un token.' | 86 | description: 'Los feeds RSS de wallabag permiten leer los artículos guardados con tu lector RSS favorito. Primero necesitas generar un token.' |
88 | token_label: 'Token RSS' | 87 | token_label: 'Token RSS' |
89 | no_token: 'Sin token' | 88 | no_token: 'Sin token' |
90 | token_create: 'Crear token' | 89 | token_create: 'Crear token' |
91 | token_reset: 'Reiniciar token' | 90 | token_reset: 'Reiniciar token' |
92 | rss_links: 'URLs de feeds RSS' | 91 | token_revoke: 'Revocar token' |
93 | rss_link: | 92 | feed_links: 'URLs de feeds RSS' |
94 | unread: 'sin leer' | 93 | feed_link: |
95 | starred: 'favoritos' | 94 | unread: 'Sin leer' |
96 | archive: 'archivados' | 95 | starred: 'Favoritos' |
97 | # all: 'All' | 96 | archive: 'Archivados' |
98 | rss_limit: 'Límite de artículos en feed RSS' | 97 | all: 'Todos' |
98 | feed_limit: 'Límite de artículos en feed RSS' | ||
99 | form_user: | 99 | 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." | 100 | two_factor_description: "Activar la autenticación de dos pasos significa que recibirás un correo electrónico con un código o que necesitarás usar una aplicación OTP (como Google Authenticator, Authy or FreeOTP) para conseguir un código de utilización única en cada nueva conexión no confiable. No puedes usar los dos métodos." |
101 | login_label: 'Nombre de usuario (no se puede cambiar)' | ||
101 | name_label: 'Nombre' | 102 | name_label: 'Nombre' |
102 | email_label: 'Dirección de e-mail' | 103 | email_label: 'Dirección de correo electrónico' |
103 | twoFactorAuthentication_label: 'Autenticación en dos pasos' | 104 | 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." | 105 | emailTwoFactor_label: 'Usando el correo electrónico (recibe un código por correo electrónico)' |
106 | googleTwoFactor_label: 'Usando una aplicación OTP (abre la aplicación, por ejemplo Google Authenticator, Authy o FreeOTP, para conseguir un código de utilización única)' | ||
107 | table_method: 'Método' | ||
108 | table_state: 'Estado' | ||
109 | table_action: 'Acción' | ||
110 | state_enabled: 'Activado' | ||
111 | state_disabled: 'Desactivado' | ||
112 | action_email: 'Usar correo electrónico' | ||
113 | action_app: 'Usar aplicación OTP' | ||
105 | delete: | 114 | delete: |
106 | title: Eliminar mi cuenta (Zona peligrosa) | 115 | 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. | 116 | 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. |
@@ -113,7 +122,7 @@ config: | |||
113 | annotations: Eliminar TODAS las anotaciones | 122 | annotations: Eliminar TODAS las anotaciones |
114 | tags: Eliminar TODAS las etiquetas | 123 | tags: Eliminar TODAS las etiquetas |
115 | entries: Eliminar TODOS los artículos | 124 | entries: Eliminar TODOS los artículos |
116 | # archived: Remove ALL archived entries | 125 | archived: Eliminar TODOS los artículos archivados |
117 | confirm: ¿Estás completamente seguro? (NO SE PUEDE DESHACER) | 126 | confirm: ¿Estás completamente seguro? (NO SE PUEDE DESHACER) |
118 | form_password: | 127 | form_password: |
119 | description: "Puedes cambiar la contraseña aquí. Tu nueva contraseña debe tener al menos 8 caracteres." | 128 | description: "Puedes cambiar la contraseña aquí. Tu nueva contraseña debe tener al menos 8 caracteres." |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'editar' | 136 | edit_rule_label: 'editar' |
128 | rule_label: 'Regla' | 137 | rule_label: 'Regla' |
129 | tags_label: 'Etiquetas' | 138 | tags_label: 'Etiquetas' |
139 | card: | ||
140 | new_tagging_rule: Crear una regla de etiquetado | ||
141 | import_tagging_rules: Importar reglas de etiquetado | ||
142 | import_tagging_rules_detail: Debes seleccionar un archivo JSON exportado previamente. | ||
143 | export_tagging_rules: Exportar reglas de etiquetado | ||
144 | export_tagging_rules_detail: Un archivo JSON será descargado y este podrá ser utilizado para volver a importar las reglas de etiquetado o como copia de seguridad. | ||
145 | file_label: Archivo JSON | ||
146 | import_submit: Importar | ||
147 | export: Exportar | ||
130 | faq: | 148 | faq: |
131 | title: 'Preguntas frecuentes' | 149 | title: 'Preguntas frecuentes' |
132 | tagging_rules_definition_title: '¿Qué significa « reglas de etiquetado automático »?' | 150 | tagging_rules_definition_title: '¿Qué significa « reglas de etiquetado automático »?' |
@@ -157,8 +175,17 @@ config: | |||
157 | not_equal_to: 'Diferente de…' | 175 | not_equal_to: 'Diferente de…' |
158 | or: 'Una regla U otra' | 176 | or: 'Una regla U otra' |
159 | and: 'Una regla Y la otra' | 177 | 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>' | 178 | matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayúsculas).<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>' | 179 | notmatches: 'Prueba si <i>subject</i> no corresponde a una <i>búsqueda</i> (insensible a mayúsculas).<br />Example: <code>title notmatches "fútbol"</code>' |
180 | otp: | ||
181 | page_title: Autenticación de dos pasos | ||
182 | app: | ||
183 | two_factor_code_description_1: Acabas de activar la autenticación en dos factores con OTP, abre tu aplicación OTP y consigue un código de utilización única. Desaparecerá al volver a cargar la página. | ||
184 | two_factor_code_description_2: 'Puedes escanear el código QR con tu aplicación:' | ||
185 | two_factor_code_description_3: 'No olvides guardar los códigos de seguridad en un lugar seguro, los puedes utilizar en caso de que pierdas el accesso a tu aplicación OTP:' | ||
186 | two_factor_code_description_4: 'Prueba un código generado por tu aplicación OTP:' | ||
187 | cancel: Cancelar | ||
188 | enable: Activar | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'Título del artículo' | 191 | default_title: 'Título del artículo' |
@@ -192,8 +219,8 @@ entry: | |||
192 | unread_label: 'Sin leer' | 219 | unread_label: 'Sin leer' |
193 | preview_picture_label: 'Tiene imagen de previsualización' | 220 | preview_picture_label: 'Tiene imagen de previsualización' |
194 | preview_picture_help: 'Imagen de previsualización' | 221 | preview_picture_help: 'Imagen de previsualización' |
195 | # is_public_label: 'Has a public link' | 222 | is_public_label: 'Tiene un enlace público' |
196 | # is_public_help: 'Public link' | 223 | is_public_help: 'Enlace público' |
197 | language_label: 'Idioma' | 224 | language_label: 'Idioma' |
198 | http_status_label: 'Código de estado HTTP' | 225 | http_status_label: 'Código de estado HTTP' |
199 | reading_time: | 226 | reading_time: |
@@ -220,7 +247,7 @@ entry: | |||
220 | delete: 'Eliminar' | 247 | delete: 'Eliminar' |
221 | add_a_tag: 'Añadir una etiqueta' | 248 | add_a_tag: 'Añadir una etiqueta' |
222 | share_content: 'Compartir' | 249 | share_content: 'Compartir' |
223 | share_email_label: 'e-mail' | 250 | share_email_label: 'Correo electrónico' |
224 | public_link: 'enlace público' | 251 | public_link: 'enlace público' |
225 | delete_public_link: 'eliminar enlace público' | 252 | delete_public_link: 'eliminar enlace público' |
226 | export: 'Exportar' | 253 | export: 'Exportar' |
@@ -232,12 +259,12 @@ entry: | |||
232 | original_article: 'original' | 259 | original_article: 'original' |
233 | annotations_on_the_entry: '{0} Sin anotaciones|{1} Una anotación|]1,Inf[ %count% anotaciones' | 260 | annotations_on_the_entry: '{0} Sin anotaciones|{1} Una anotación|]1,Inf[ %count% anotaciones' |
234 | created_at: 'Fecha de creación' | 261 | created_at: 'Fecha de creación' |
235 | # published_at: 'Publication date' | 262 | published_at: 'Fecha de publicación' |
236 | # published_by: 'Published by' | 263 | published_by: 'Publicado por' |
237 | # provided_by: 'Provided by' | 264 | provided_by: 'Proporcionado por' |
238 | new: | 265 | new: |
239 | page_title: 'Guardar un nuevo artículo' | 266 | page_title: 'Guardar un nuevo artículo' |
240 | placeholder: 'http://sitioweb.com' | 267 | placeholder: 'https://sitioweb.es' |
241 | form_new: | 268 | form_new: |
242 | url_label: URL | 269 | url_label: URL |
243 | search: | 270 | search: |
@@ -246,13 +273,18 @@ entry: | |||
246 | page_title: 'Editar un artículo' | 273 | page_title: 'Editar un artículo' |
247 | title_label: 'Título' | 274 | title_label: 'Título' |
248 | url_label: 'URL' | 275 | url_label: 'URL' |
249 | # origin_url_label: 'Origin url (from where you found that entry)' | 276 | origin_url_label: 'URL de origen (de dónde has encontrado este artículo)' |
250 | save_label: 'Guardar' | 277 | save_label: 'Guardar' |
251 | public: | 278 | public: |
252 | shared_by_wallabag: "Este artículo se ha compartido con <a href='%wallabag_instance%'>wallabag</a>" | 279 | shared_by_wallabag: "Este artículo se ha compartido con <a href='%wallabag_instance%'>wallabag</a>" |
253 | confirm: | 280 | confirm: |
254 | # delete: "Are you sure you want to remove that article?" | 281 | delete: "¿Estás seguro de que quieres eliminar este artículo?" |
255 | # delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | delete_tag: "¿Estás seguro de que quieres eliminar esta etiqueta de este artículo?" |
283 | metadata: | ||
284 | reading_time: "Tiempo de lectura estimado" | ||
285 | reading_time_minutes_short: "%readingTime% min" | ||
286 | address: "Dirección" | ||
287 | added_on: "Añadido el" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'Acerca de' | 290 | page_title: 'Acerca de' |
@@ -274,14 +306,14 @@ about: | |||
274 | bug_reports: 'Reporte de errores' | 306 | bug_reports: 'Reporte de errores' |
275 | support: '<a href="https://github.com/wallabag/wallabag/issues">en GitHub</a>' | 307 | support: '<a href="https://github.com/wallabag/wallabag/issues">en GitHub</a>' |
276 | helping: | 308 | helping: |
277 | description: 'wallabag es software libre y gratuito. Usted puede ayudarnos :' | 309 | description: 'wallabag es software libre y gratuito. Usted puede ayudarnos:' |
278 | by_contributing: 'contribuyendo al proyecto :' | 310 | by_contributing: 'contribuyendo al proyecto :' |
279 | by_contributing_2: 'nuestras necesidades están en un ticket' | 311 | by_contributing_2: 'nuestras necesidades están en un ticket' |
280 | by_paypal: 'vía Paypal' | 312 | by_paypal: 'vía Paypal' |
281 | contributors: | 313 | contributors: |
282 | description: 'Gracias a los colaboradores de la aplicación web de wallabag' | 314 | description: 'Gracias a los colaboradores de la aplicación web de wallabag' |
283 | third_party: | 315 | third_party: |
284 | description: 'Aquí está la lista de bibliotecas de terceros utilizadas por wallabag (con sus licencias) :' | 316 | description: 'Aquí está la lista de bibliotecas de terceros utilizadas por wallabag (con sus licencias):' |
285 | package: 'Paquete' | 317 | package: 'Paquete' |
286 | license: 'Licencia' | 318 | license: 'Licencia' |
287 | 319 | ||
@@ -329,7 +361,7 @@ howto: | |||
329 | article_title: Atajos de teclado disponibles en el artículo | 361 | article_title: Atajos de teclado disponibles en el artículo |
330 | open_original: Abrir la URL original de un artículo | 362 | open_original: Abrir la URL original de un artículo |
331 | toggle_favorite: Marcar como favorito / no favorito el artículo | 363 | toggle_favorite: Marcar como favorito / no favorito el artículo |
332 | toggle_archive: marcar como leído / no leído el artículo | 364 | toggle_archive: Marcar como leído / no leído el artículo |
333 | delete: Borrar el artículo | 365 | delete: Borrar el artículo |
334 | material_title: Atajos de teclado disponibles solo en el tema Material | 366 | material_title: Atajos de teclado disponibles solo en el tema Material |
335 | add_link: Añadir un nuevo artículo | 367 | add_link: Añadir un nuevo artículo |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: 'Configure la aplicación' | 380 | title: 'Configure la aplicación' |
349 | description: 'Para que la aplicación se ajuste a tus necesidades, echa un vistazo a la configuración de wallabag.' | 381 | description: 'Para que la aplicación se ajuste a tus necesidades, echa un vistazo a la configuración de wallabag.' |
350 | language: 'Cambie el idioma y el diseño' | 382 | language: 'Cambie el idioma y el diseño' |
351 | rss: 'Activar los feeds RSS' | 383 | feed: 'Activar los feeds RSS' |
352 | tagging_rules: 'Escribe reglas para etiquetar automáticamente tus artículos' | 384 | tagging_rules: 'Escribe reglas para etiquetar automáticamente tus artículos' |
353 | admin: | 385 | admin: |
354 | title: 'Administración' | 386 | title: 'Administración' |
@@ -388,7 +420,7 @@ quickstart: | |||
388 | title: 'Apoyo' | 420 | title: 'Apoyo' |
389 | description: 'Si necesitas ayuda, estamos a tu disposición.' | 421 | description: 'Si necesitas ayuda, estamos a tu disposición.' |
390 | github: 'En GitHub' | 422 | github: 'En GitHub' |
391 | email: 'Por e-mail' | 423 | email: 'Por correo electrónico' |
392 | gitter: 'En Gitter' | 424 | gitter: 'En Gitter' |
393 | 425 | ||
394 | tag: | 426 | tag: |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: '{0} No hay ninguna etiqueta.|{1} Hay una etiqueta.|]1,Inf[ Hay %count% etiquetas.' | 429 | number_on_the_page: '{0} No hay ninguna etiqueta.|{1} Hay una etiqueta.|]1,Inf[ Hay %count% etiquetas.' |
398 | see_untagged_entries: 'Ver artículos sin etiquetas' | 430 | see_untagged_entries: 'Ver artículos sin etiquetas' |
431 | no_untagged_entries: 'No hay artículos sin etiquetas.' | ||
399 | new: | 432 | new: |
400 | add: 'Añadir' | 433 | add: 'Añadir' |
401 | placeholder: 'Puedes añadir varias etiquetas, separadas por una coma.' | 434 | placeholder: 'Puedes añadir varias etiquetas, separadas por una coma.' |
435 | rename: | ||
436 | placeholder: 'Puedes actualizar el nombre de la etiqueta.' | ||
402 | 437 | ||
403 | # export: | 438 | export: |
404 | # 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>' | 439 | footer_template: '<div style="text-align:center;"><p>Producido por wallabag con %method%</p><p>Por favor abre <a href="https://github.com/wallabag/wallabag/issues">un ticket</a> si tienes algún problema con la visualización de este E-Book en tu dispositivo.</p></div>' |
440 | unknown: 'Desconocido' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Importar' | 443 | page_title: 'Importar' |
@@ -421,7 +457,7 @@ import: | |||
421 | admin_message: 'Debe definir %keyurls%una clave del API Pocket%keyurle%.' | 457 | admin_message: 'Debe definir %keyurls%una clave del API Pocket%keyurle%.' |
422 | user_message: 'El administrador de su servidor debe definir una clave del API Pocket.' | 458 | user_message: 'El administrador de su servidor debe definir una clave del API Pocket.' |
423 | authorize_message: 'Puede importar sus datos desde su cuenta de Pocket. Sólo tiene que hacer clic el botón para autorizar que wallabag se conecte a getpocket.com.' | 459 | authorize_message: 'Puede importar sus datos desde su cuenta de Pocket. Sólo tiene que hacer clic el botón para autorizar que wallabag se conecte a getpocket.com.' |
424 | connect_to_pocket: 'Conectar a Pocket e importar los datos' | 460 | connect_to_pocket: 'Conectarse a Pocket e importar los datos' |
425 | wallabag_v1: | 461 | wallabag_v1: |
426 | page_title: 'Importar > Wallabag v1' | 462 | page_title: 'Importar > Wallabag v1' |
427 | description: 'Importa todos tus artículos de wallabag v1. En la configuración de wallabag v1, haga clic en "Exportar JSON" dentro de la sección "Exportar datos de wallabag". Obtendrás un archivo llamado "wallabag-export-1-xxxx-xx-xx.json".' | 463 | description: 'Importa todos tus artículos de wallabag v1. En la configuración de wallabag v1, haga clic en "Exportar JSON" dentro de la sección "Exportar datos de wallabag". Obtendrás un archivo llamado "wallabag-export-1-xxxx-xx-xx.json".' |
@@ -429,13 +465,16 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Importar > Wallabag v2' | 466 | page_title: 'Importar > Wallabag v2' |
431 | description: 'Importa todos tus artículos de wallabag v2. En la sección Todos los artículos, en la barra lateral, haga clic en "JSON". Obtendrás un archivo llamado "All articles.json".' | 467 | description: 'Importa todos tus artículos de wallabag v2. En la sección Todos los artículos, en la barra lateral, haga clic en "JSON". Obtendrás un archivo llamado "All articles.json".' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Importar > Readability' | 472 | page_title: 'Importar > Readability' |
434 | description: 'Importa todos tus artículos de Readability. En la página de herramientas (https://www.readability.com/tools/), haga clic en "Exportar tus datos" en la sección "Exportar datos". Recibirás un e-mail para descargar un JSON (que no tiene extensión .json).' | 473 | description: 'Importa todos tus artículos de Readability. En la página de herramientas (https://www.readability.com/tools/), haga clic en "Exportar tus datos" en la sección "Exportar datos". Recibirás un correo electrónico para descargar un JSON (que no tiene extensión .json).' |
435 | how_to: 'Seleccione el archivo exportado de Readability y haga clic en el botón para subirlo e importarlo.' | 474 | how_to: 'Seleccione el archivo exportado de Readability y haga clic en el botón para subirlo e importarlo.' |
436 | worker: | 475 | worker: |
437 | enabled: "La importación se realiza de forma asíncrona. Una vez que la tarea de importación ha comenzado, un trabajador externo se encargará de los artículos uno a uno. El servicio actual es:" | 476 | enabled: "La importación se realiza de forma asíncrona. Una vez que la tarea de importación ha comenzado, un trabajador externo se encargará de los artículos uno a uno. El servicio actual es:" |
438 | download_images_warning: "Tienes activado descargar imágenes de los artículos. Esto justo con la importación clásica de artículos puede tardar mucho tiempo en ser procesado (o incluso fallar). <strong>Recomendamos encarecidamente</strong> habilitar la importación asíncrona para evitar errores." | 477 | download_images_warning: "Tienes activado descargar imágenes de los artículos. Esto junto con la importación clásica de artículos puede tardar mucho tiempo en ser procesado (o incluso fallar). <strong>Recomendamos encarecidamente</strong> habilitar la importación asíncrona para evitar errores." |
439 | firefox: | 478 | firefox: |
440 | page_title: 'Importar > Firefox' | 479 | page_title: 'Importar > Firefox' |
441 | description: "Importa todos tus marcadores de Firefox. En la ventana de marcadores (Ctrl+Mayus+O), en \"Importar y respaldar\", elige \"Copiar...\". Obtendrás un archivo .json." | 480 | description: "Importa todos tus marcadores de Firefox. En la ventana de marcadores (Ctrl+Mayus+O), en \"Importar y respaldar\", elige \"Copiar...\". Obtendrás un archivo .json." |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: 'URIs de redirección' | 521 | redirect_uris_label: 'URIs de redirección' |
483 | save_label: 'Crear un nuevo cliente' | 522 | save_label: 'Crear un nuevo cliente' |
484 | action_back: 'Volver' | 523 | action_back: 'Volver' |
524 | copy_to_clipboard: 'Copiar' | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: 'Gestión de clientes API > Parámetros del cliente' | 526 | page_title: 'Gestión de clientes API > Parámetros del cliente' |
487 | page_description: 'Aquí están los parámetros del cliente.' | 527 | page_description: 'Aquí están los parámetros del cliente.' |
@@ -493,14 +533,14 @@ developer: | |||
493 | howto: | 533 | howto: |
494 | page_title: 'Gestión de clientes API > Cómo crear mi primera aplicación' | 534 | page_title: 'Gestión de clientes API > Cómo crear mi primera aplicación' |
495 | description: | 535 | description: |
496 | paragraph_1: 'Los siguientes comandos hacen uso de la <a href="https://github.com/jkbrzt/httpie">biblioteca HTTPie</a>. Compruebe que está instalada en su sistema antes de usarla.' | 536 | paragraph_1: 'Los siguientes comandos hacen uso de la <a href="https://github.com/jkbrzt/httpie">biblioteca HTTPie</a>. Comprueba que está instalada en tu sistema antes de usarla.' |
497 | paragraph_2: 'Necesitas un token para establecer la comunicación entre una aplicación de terceros y la API de wallabag.' | 537 | paragraph_2: 'Necesitas un token para establecer la comunicación entre una aplicación de terceros y la API de wallabag.' |
498 | paragraph_3: 'Para crear este token, necesitas <a href="%link%">crear un nuevo cliente</a>.' | 538 | paragraph_3: 'Para crear este token, necesitas <a href="%link%">crear un nuevo cliente</a>.' |
499 | paragraph_4: 'Ahora crea tu token (reemplace client_id, client_secret, username y password con los valores generados):' | 539 | paragraph_4: 'Ahora crea tu token (reemplaza client_id, client_secret, username y password con los valores generados):' |
500 | paragraph_5: 'Este API devolverá una respuesta como esta:' | 540 | paragraph_5: 'Este API devolverá una respuesta como esta:' |
501 | paragraph_6: 'El access_token es útil para llamar a los métodos del API. Por ejemplo:' | 541 | paragraph_6: 'El access_token es útil para llamar a los métodos del API. Por ejemplo:' |
502 | paragraph_7: 'Esta llamada devolverá todos los artículos de tu usuario.' | 542 | paragraph_7: 'Esta llamada devolverá todos los artículos de tu usuario.' |
503 | paragraph_8: 'Si quiere ver todos los métodos del API, puede verlos en <a href="%link%">nuestra documentación del API</a>.' | 543 | paragraph_8: 'Si quieres ver todos los métodos del API, puedes verlos en <a href="%link%">nuestra documentación del API</a>.' |
504 | back: 'Volver' | 544 | back: 'Volver' |
505 | 545 | ||
506 | user: | 546 | user: |
@@ -520,36 +560,37 @@ user: | |||
520 | password_label: 'Contraseña' | 560 | password_label: 'Contraseña' |
521 | repeat_new_password_label: 'Confirmar la contraseña' | 561 | repeat_new_password_label: 'Confirmar la contraseña' |
522 | plain_password_label: '????' | 562 | plain_password_label: '????' |
523 | email_label: 'E-mail' | 563 | email_label: 'Correo electrónico' |
524 | enabled_label: 'Activado' | 564 | enabled_label: 'Activado' |
525 | last_login_label: 'Último inicio de sesión' | 565 | last_login_label: 'Último inicio de sesión' |
526 | twofactor_label: Autenticación en dos pasos | 566 | twofactor_email_label: 'Autenticación de dos pasos por correo electrónico' |
567 | twofactor_google_label: 'Autenticación de dos pasos por aplicación OTP' | ||
527 | save: Guardar | 568 | save: Guardar |
528 | delete: Eliminar | 569 | delete: Eliminar |
529 | delete_confirm: ¿Estás seguro? | 570 | delete_confirm: ¿Estás seguro? |
530 | back_to_list: Volver a la lista | 571 | back_to_list: Volver a la lista |
531 | search: | 572 | search: |
532 | # placeholder: Filter by username or email | 573 | placeholder: 'Filtrar por nombre de usuario o correo electrónico' |
533 | 574 | ||
534 | site_credential: | 575 | site_credential: |
535 | # page_title: Site credentials management | 576 | page_title: 'Gestión de credenciales del sitio' |
536 | # new_site_credential: Create a credential | 577 | new_site_credential: 'Crear una credencial' |
537 | # edit_site_credential: Edit an existing credential | 578 | edit_site_credential: 'Editar una credencial existente' |
538 | # description: "Here you can manage all credentials for sites which required them (create, edit and delete), like a paywall, an authentication, etc." | 579 | description: "Aquí puedes gestionar todas las credenciales para los sitios que las necesiten (crear, editar y borrar), como un paywall, una autenticación, etc." |
539 | # list: | 580 | list: |
540 | # actions: Actions | 581 | actions: 'Acciones' |
541 | # edit_action: Edit | 582 | edit_action: 'Editar' |
542 | # yes: Yes | 583 | yes: 'Sí' |
543 | # no: No | 584 | no: 'No' |
544 | # create_new_one: Create a new credential | 585 | create_new_one: 'Crear una nueva credencial' |
545 | # form: | 586 | form: |
546 | # username_label: 'Username' | 587 | username_label: 'Nombre de usuario' |
547 | # host_label: 'Host' | 588 | host_label: 'Host (subdominio.ejemplo.org, .ejemplo.org, etc.)' |
548 | # password_label: 'Password' | 589 | password_label: 'Contraseña' |
549 | # save: Save | 590 | save: 'Guardar' |
550 | # delete: Delete | 591 | delete: 'Borrar' |
551 | # delete_confirm: Are you sure? | 592 | delete_confirm: '¿Estás seguro?' |
552 | # back_to_list: Back to list | 593 | back_to_list: 'Volver a la lista' |
553 | 594 | ||
554 | error: | 595 | error: |
555 | page_title: Ha ocurrido un error | 596 | page_title: Ha ocurrido un error |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Contraseña actualizada' | 602 | password_updated: 'Contraseña actualizada' |
562 | password_not_updated_demo: "En el modo demo, no puede cambiar la contraseña del usuario." | 603 | password_not_updated_demo: "En el modo demo, no puede cambiar la contraseña del usuario." |
563 | user_updated: 'Información actualizada' | 604 | user_updated: 'Información actualizada' |
564 | rss_updated: 'Configuración RSS actualizada' | 605 | feed_updated: 'Configuración RSS actualizada' |
565 | tagging_rules_updated: 'Regla de etiquetado actualizada' | 606 | tagging_rules_updated: 'Regla de etiquetado actualizada' |
566 | tagging_rules_deleted: 'Regla de etiquetado eliminada' | 607 | tagging_rules_deleted: 'Regla de etiquetado eliminada' |
567 | rss_token_updated: 'Token RSS actualizado' | 608 | feed_token_updated: 'Token RSS actualizado' |
609 | feed_token_revoked: 'Token RSS revocado' | ||
568 | annotations_reset: Anotaciones reiniciadas | 610 | annotations_reset: Anotaciones reiniciadas |
569 | tags_reset: Etiquetas reiniciadas | 611 | tags_reset: Etiquetas reiniciadas |
570 | entries_reset: Artículos reiniciados | 612 | entries_reset: Artículos reiniciados |
571 | # archived_reset: Archived entries deleted | 613 | archived_reset: Artículos archivados borrados |
614 | otp_enabled: Autenticación de dos pasos activada | ||
615 | tagging_rules_imported: Reglas de etiquetado importadas | ||
616 | tagging_rules_not_imported: Un error se ha producico en la importación de las reglas de etiquetado | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Artículo ya guardado el %fecha%' | 619 | entry_already_saved: 'Artículo ya guardado el %fecha%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Artículo marcado como favorito' | 627 | entry_starred: 'Artículo marcado como favorito' |
583 | entry_unstarred: 'Artículo desmarcado como favorito' | 628 | entry_unstarred: 'Artículo desmarcado como favorito' |
584 | entry_deleted: 'Artículo eliminado' | 629 | entry_deleted: 'Artículo eliminado' |
630 | no_random_entry: 'Ningún artículo con esos criterios fue encontrado' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Etiqueta añadida' | 633 | tag_added: 'Etiqueta añadida' |
634 | tag_renamed: 'Etiqueta renombrada' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'Importación fallida, por favor, inténtelo de nuevo.' | 637 | failed: 'Importación fallida, por favor, inténtelo de nuevo.' |
@@ -596,15 +643,15 @@ flashes: | |||
596 | rabbit_enabled_not_installed: RabbitMQ está activado para gestionar la importación asíncrona pero parece que <u>no se puede conectar</u>. Por favor, comprueba la configuración de RabbitMQ. | 643 | rabbit_enabled_not_installed: RabbitMQ está activado para gestionar la importación asíncrona pero parece que <u>no se puede conectar</u>. Por favor, comprueba la configuración de RabbitMQ. |
597 | developer: | 644 | developer: |
598 | notice: | 645 | notice: |
599 | client_created: 'Creado el cliente %name%.' | 646 | client_created: 'El cliente %name% ha sido creado.' |
600 | client_deleted: 'Eliminado el cliente %name%' | 647 | client_deleted: 'El cliente %name% ha sido eliminado' |
601 | user: | 648 | user: |
602 | notice: | 649 | notice: |
603 | added: 'Añadido el usuario "%username%"' | 650 | added: 'El usuario "%username%" ha sido añadido' |
604 | updated: 'Actualizado el usuario "%username%"' | 651 | updated: 'El usuario "%username%" ha sido actualizado' |
605 | deleted: 'Eliminado el usuario "%username%"' | 652 | deleted: 'El usuario "%username%" ha sido eliminado' |
606 | site_credential: | 653 | site_credential: |
607 | notice: | 654 | notice: |
608 | # added: 'Site credential for "%host%" added' | 655 | added: 'Credenciales del sitio añadidas para "%host%"' |
609 | # updated: 'Site credential for "%host%" updated' | 656 | updated: 'Credenciales del sitio actualizadas para "%host%"' |
610 | # deleted: 'Site credential for "%host%" deleted' | 657 | deleted: 'Credenciales del sitio eliminadas para "%host%"' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml index b3f2eb58..c1fb74d3 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'بازگشت به خواندهنشدهها' | 33 | back_to_unread: 'بازگشت به خواندهنشدهها' |
34 | # users_management: 'Users management' | 34 | # users_management: 'Users management' |
35 | # site_credentials: 'Site credentials' | 35 | # site_credentials: 'Site credentials' |
36 | quickstart: "Quickstart" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'افزودن مقالهٔ تازه' | 38 | add_new_entry: 'افزودن مقالهٔ تازه' |
38 | search: 'جستجو' | 39 | search: 'جستجو' |
39 | filter_entries: 'فیلترکردن مقالهها' | 40 | filter_entries: 'فیلترکردن مقالهها' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | export: 'برونبری' | 42 | export: 'برونبری' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'جستجوی خود را اینجا بنویسید:' | 44 | input_label: 'جستجوی خود را اینجا بنویسید:' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'پیکربندی' | 55 | page_title: 'پیکربندی' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'تنظیمات' | 57 | settings: 'تنظیمات' |
56 | rss: 'آر-اس-اس' | 58 | feed: 'آر-اس-اس' |
57 | user_info: 'اطلاعات کاربر' | 59 | user_info: 'اطلاعات کاربر' |
58 | password: 'رمز' | 60 | password: 'رمز' |
59 | rules: 'برچسبگذاری خودکار' | 61 | rules: 'برچسبگذاری خودکار' |
60 | new_user: 'افزودن کاربر' | 62 | new_user: 'افزودن کاربر' |
63 | # reset: 'Reset area' | ||
61 | form: | 64 | form: |
62 | save: 'ذخیره' | 65 | save: 'ذخیره' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'تعداد مقاله در هر صفحه' | 68 | items_per_page_label: 'تعداد مقاله در هر صفحه' |
66 | language_label: 'زبان' | 69 | language_label: 'زبان' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'سرعت خواندن' | 71 | # label: 'Reading speed (words per minute)' |
69 | help_message: 'سرعت خواندنتان را با ابزارهای آنلاین تخمین بزنید:' | 72 | help_message: 'سرعت خواندنتان را با ابزارهای آنلاین تخمین بزنید:' |
70 | 100_word: 'من تقریباً ۱۰۰ واژه را در دقیقه میخوانم' | ||
71 | 200_word: 'من تقریباً ۲۰۰ واژه را در دقیقه میخوانم' | ||
72 | 300_word: 'من تقریباً ۳۰۰ واژه را در دقیقه میخوانم' | ||
73 | 400_word: 'من تقریباً ۴۰۰ واژه را در دقیقه میخوانم' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | # label: 'Where do you want to be redirected to after marking an article as read?' | 74 | # label: 'Where do you want to be redirected to after marking an article as read?' |
76 | # redirect_homepage: 'To the homepage' | 75 | # redirect_homepage: 'To the homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." | 82 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." |
84 | # help_language: "You can change the language of wallabag interface." | 83 | # help_language: "You can change the language of wallabag interface." |
85 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." | 84 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'با خوراک آر-اس-اس که wallabag در اختیارتان میگذارد، میتوانید مقالههای ذخیرهشده را در نرمافزار آر-اس-اس دلخواه خود بخوانید. برای این کار نخست باید یک کد بسازید.' | 86 | description: 'با خوراک آر-اس-اس که wallabag در اختیارتان میگذارد، میتوانید مقالههای ذخیرهشده را در نرمافزار آر-اس-اس دلخواه خود بخوانید. برای این کار نخست باید یک کد بسازید.' |
88 | token_label: 'کد آر-اس-اس' | 87 | token_label: 'کد آر-اس-اس' |
89 | no_token: 'بدون کد' | 88 | no_token: 'بدون کد' |
90 | token_create: 'کد خود را بسازید' | 89 | token_create: 'کد خود را بسازید' |
91 | token_reset: 'بازنشانی کد' | 90 | token_reset: 'بازنشانی کد' |
92 | rss_links: 'پیوند آر-اس-اس' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'پیوند آر-اس-اس' |
93 | feed_link: | ||
94 | unread: 'خواندهنشده' | 94 | unread: 'خواندهنشده' |
95 | starred: 'برگزیده' | 95 | starred: 'برگزیده' |
96 | archive: 'بایگانی' | 96 | archive: 'بایگانی' |
97 | # all: 'All' | 97 | # all: 'All' |
98 | rss_limit: 'محدودیت آر-اس-اس' | 98 | feed_limit: 'محدودیت آر-اس-اس' |
99 | form_user: | 99 | form_user: |
100 | two_factor_description: "با فعالکردن تأیید ۲مرحلهای هر بار که اتصال تأییدنشدهای برقرار شد، به شما یک کد از راه ایمیل فرستاده میشود" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'نام' | 102 | name_label: 'نام' |
102 | email_label: 'نشانی ایمیل' | 103 | email_label: 'نشانی ایمیل' |
103 | twoFactorAuthentication_label: 'تأیید ۲مرحلهای' | 104 | two_factor: |
104 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 105 | # emailTwoFactor_label: 'Using email (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. |
@@ -127,6 +136,15 @@ config: | |||
127 | # edit_rule_label: 'edit' | 136 | # edit_rule_label: 'edit' |
128 | rule_label: 'قانون' | 137 | rule_label: 'قانون' |
129 | tags_label: 'برچسبها' | 138 | tags_label: 'برچسبها' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'پرسشهای متداول' | 149 | title: 'پرسشهای متداول' |
132 | tagging_rules_definition_title: 'برچسبگذاری خودکار یعنی چه؟' | 150 | tagging_rules_definition_title: 'برچسبگذاری خودکار یعنی چه؟' |
@@ -159,6 +177,15 @@ config: | |||
159 | # and: 'One rule AND another' | 177 | # 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>' | 178 | # 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>' | 179 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | # default_title: 'Title of the entry' | 191 | # default_title: 'Title of the entry' |
@@ -237,7 +264,7 @@ entry: | |||
237 | # provided_by: 'Provided by' | 264 | # provided_by: 'Provided by' |
238 | new: | 265 | new: |
239 | page_title: 'ذخیرهٔ مقالهٔ تازه' | 266 | page_title: 'ذخیرهٔ مقالهٔ تازه' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.ir' |
241 | form_new: | 268 | form_new: |
242 | url_label: نشانی | 269 | url_label: نشانی |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | # delete: "Are you sure you want to remove that article?" | 281 | # delete: "Are you sure you want to remove that article?" |
255 | # delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | # delete_tag: "Are you sure you want to remove that tag from that article?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'درباره' | 290 | page_title: 'درباره' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: 'برنامه را تنظیم کنید' | 380 | title: 'برنامه را تنظیم کنید' |
349 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' | 381 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' |
350 | language: 'زبان و نمای برنامه را تغییر دهید' | 382 | language: 'زبان و نمای برنامه را تغییر دهید' |
351 | rss: 'خوراک آر-اس-اس را فعال کنید' | 383 | feed: 'خوراک آر-اس-اس را فعال کنید' |
352 | tagging_rules: 'قانونهای برچسبگذاری خودکار مقالههایتان را تعریف کنید' | 384 | tagging_rules: 'قانونهای برچسبگذاری خودکار مقالههایتان را تعریف کنید' |
353 | admin: | 385 | admin: |
354 | title: 'مدیریت' | 386 | title: 'مدیریت' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: '{0} هیچ برچسبی نیست.|{1} یک برچسب هست.|]1,Inf[ %count% برچسب هست.' | 429 | number_on_the_page: '{0} هیچ برچسبی نیست.|{1} یک برچسب هست.|]1,Inf[ %count% برچسب هست.' |
398 | # see_untagged_entries: 'See untagged entries' | 430 | # see_untagged_entries: 'See untagged entries' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | # add: 'Add' | 433 | # add: 'Add' |
401 | # placeholder: 'You can add several tags, separated by a comma.' | 434 | # placeholder: 'You can add several tags, separated by a comma.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
402 | 437 | ||
403 | # export: | 438 | # export: |
404 | # 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>' | 439 | # 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>' |
440 | # unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'درونریزی' | 443 | page_title: 'درونریزی' |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'درونریزی > Wallabag v2' | 466 | page_title: 'درونریزی > Wallabag v2' |
431 | description: 'این برنامه همهٔ دادههای شما را در نسخهٔ ۲ wallabag درونریزی میکند. به بخش «همهٔ مقالهها» بروید و در بخش «برونریزی» روی "JSON" کلیک کنید. با این کار شما پروندهای به شکل "All articles.json" دریافت خواهید کرد.' | 467 | description: 'این برنامه همهٔ دادههای شما را در نسخهٔ ۲ wallabag درونریزی میکند. به بخش «همهٔ مقالهها» بروید و در بخش «برونریزی» روی "JSON" کلیک کنید. با این کار شما پروندهای به شکل "All articles.json" دریافت خواهید کرد.' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'درونریزی > Readability' | 472 | page_title: 'درونریزی > Readability' |
434 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' | 473 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' |
@@ -482,6 +521,7 @@ developer: | |||
482 | # redirect_uris_label: 'Redirect URIs' | 521 | # redirect_uris_label: 'Redirect URIs' |
483 | # save_label: 'Create a new client' | 522 | # save_label: 'Create a new client' |
484 | # action_back: 'بازگشت' | 523 | # action_back: 'بازگشت' |
524 | # copy_to_clipboard: Copy | ||
485 | # client_parameter: | 525 | # client_parameter: |
486 | # page_title: 'API clients management > Client parameters' | 526 | # page_title: 'API clients management > Client parameters' |
487 | # page_description: 'Here are your client parameters.' | 527 | # page_description: 'Here are your client parameters.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'نشانی ایمیل' | 563 | email_label: 'نشانی ایمیل' |
524 | # enabled_label: 'Enabled' | 564 | # enabled_label: 'Enabled' |
525 | # last_login_label: 'Last login' | 565 | # last_login_label: 'Last login' |
526 | # twofactor_label: Two factor authentication | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
527 | # save: Save | 568 | # save: Save |
528 | # delete: Delete | 569 | # delete: Delete |
529 | # delete_confirm: Are you sure? | 570 | # delete_confirm: Are you sure? |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | # create_new_one: Create a new credential | 585 | # create_new_one: Create a new credential |
545 | # form: | 586 | # form: |
546 | # username_label: 'Username' | 587 | # username_label: 'Username' |
547 | # host_label: 'Host' | 588 | # host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | # password_label: 'Password' | 589 | # password_label: 'Password' |
549 | # save: Save | 590 | # save: Save |
550 | # delete: Delete | 591 | # delete: Delete |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'رمز بهروز شد' | 602 | password_updated: 'رمز بهروز شد' |
562 | password_not_updated_demo: "در حالت نمایشی نمیتوانید رمز کاربر را عوض کنید." | 603 | password_not_updated_demo: "در حالت نمایشی نمیتوانید رمز کاربر را عوض کنید." |
563 | user_updated: 'اطلاعات بهروز شد' | 604 | user_updated: 'اطلاعات بهروز شد' |
564 | rss_updated: 'اطلاعات آر-اس-اس بهروز شد' | 605 | feed_updated: 'اطلاعات آر-اس-اس بهروز شد' |
565 | tagging_rules_updated: 'برچسبگذاری خودکار بهروز شد' | 606 | tagging_rules_updated: 'برچسبگذاری خودکار بهروز شد' |
566 | tagging_rules_deleted: 'قانون برچسبگذاری پاک شد' | 607 | tagging_rules_deleted: 'قانون برچسبگذاری پاک شد' |
567 | rss_token_updated: 'کد آر-اس-اس بهروز شد' | 608 | feed_token_updated: 'کد آر-اس-اس بهروز شد' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
568 | # annotations_reset: Annotations reset | 610 | # annotations_reset: Annotations reset |
569 | # tags_reset: Tags reset | 611 | # tags_reset: Tags reset |
570 | # entries_reset: Entries reset | 612 | # entries_reset: Entries reset |
571 | # archived_reset: Archived entries deleted | 613 | # archived_reset: Archived entries deleted |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود' | 619 | entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'مقاله برگزیده شد' | 627 | entry_starred: 'مقاله برگزیده شد' |
583 | entry_unstarred: 'مقاله نابرگزیده شد' | 628 | entry_unstarred: 'مقاله نابرگزیده شد' |
584 | entry_deleted: 'مقاله پاک شد' | 629 | entry_deleted: 'مقاله پاک شد' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'برچسب افزوده شد' | 633 | tag_added: 'برچسب افزوده شد' |
634 | # tag_renamed: 'Tag renamed' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'درونریزی شکست خورد. لطفاً دوباره تلاش کنید.' | 637 | failed: 'درونریزی شکست خورد. لطفاً دوباره تلاش کنید.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml index 5cdd836e..2b8bb092 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml | |||
@@ -5,7 +5,7 @@ security: | |||
5 | forgot_password: "Mot de passe oublié ?" | 5 | forgot_password: "Mot de passe oublié ?" |
6 | submit: "Se connecter" | 6 | submit: "Se connecter" |
7 | register: "Créer un compte" | 7 | register: "Créer un compte" |
8 | username: "Nom d’utilisateur" | 8 | username: "Identifiant" |
9 | password: "Mot de passe" | 9 | password: "Mot de passe" |
10 | cancel: "Annuler" | 10 | cancel: "Annuler" |
11 | resetting: | 11 | resetting: |
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: "Retour aux articles non lus" | 33 | back_to_unread: "Retour aux articles non lus" |
34 | users_management: "Gestion des utilisateurs" | 34 | users_management: "Gestion des utilisateurs" |
35 | site_credentials: 'Accès aux sites' | 35 | site_credentials: 'Accès aux sites' |
36 | quickstart: "Pour bien débuter" | ||
36 | top: | 37 | top: |
37 | add_new_entry: "Sauvegarder un nouvel article" | 38 | add_new_entry: "Sauvegarder un nouvel article" |
38 | search: "Rechercher" | 39 | search: "Rechercher" |
39 | filter_entries: "Filtrer les articles" | 40 | filter_entries: "Filtrer les articles" |
41 | random_entry: Aller à un article aléatoire de cette liste | ||
40 | export: "Exporter" | 42 | export: "Exporter" |
41 | search_form: | 43 | search_form: |
42 | input_label: "Saisissez votre terme de recherche" | 44 | input_label: "Saisissez votre terme de recherche" |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: "Configuration" | 55 | page_title: "Configuration" |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: "Paramètres" | 57 | settings: "Paramètres" |
56 | rss: "RSS" | 58 | feed: "Flux" |
57 | user_info: "Mon compte" | 59 | user_info: "Mon compte" |
58 | password: "Mot de passe" | 60 | password: "Mot de passe" |
59 | rules: "Règles de tag automatiques" | 61 | rules: "Règles de tag automatiques" |
60 | new_user: "Créer un compte" | 62 | new_user: "Créer un compte" |
63 | reset: "Réinitialisation" | ||
61 | form: | 64 | form: |
62 | save: "Enregistrer" | 65 | save: "Enregistrer" |
63 | form_settings: | 66 | form_settings: |
@@ -65,14 +68,10 @@ config: | |||
65 | items_per_page_label: "Nombre d’articles par page" | 68 | items_per_page_label: "Nombre d’articles par page" |
66 | language_label: "Langue" | 69 | language_label: "Langue" |
67 | reading_speed: | 70 | reading_speed: |
68 | label: "Vitesse de lecture" | 71 | label: "Vitesse de lecture (mots par minute)" |
69 | help_message: "Vous pouvez utiliser un outil en ligne pour estimer votre vitesse de lecture :" | 72 | help_message: "Vous pouvez utiliser un outil en ligne pour estimer votre vitesse de lecture :" |
70 | 100_word: "Je lis environ 100 mots par minute" | ||
71 | 200_word: "Je lis environ 200 mots par minute" | ||
72 | 300_word: "Je lis environ 300 mots par minute" | ||
73 | 400_word: "Je lis environ 400 mots par minute" | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: "Que faire lorsqu'un article est supprimé, marqué comme lu ou marqué comme favoris ?" | 74 | label: "Que faire lorsqu'un article est supprimé, marqué comme lu ou marqué comme favori ?" |
76 | redirect_homepage: "Retourner à la page d’accueil" | 75 | redirect_homepage: "Retourner à la page d’accueil" |
77 | redirect_current_page: "Rester sur la page actuelle" | 76 | redirect_current_page: "Rester sur la page actuelle" |
78 | pocket_consumer_key_label: "Clé d’authentification Pocket pour importer les données" | 77 | pocket_consumer_key_label: "Clé d’authentification Pocket pour importer les données" |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article." | 82 | help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article." |
84 | help_language: "Vous pouvez définir la langue de l’interface de wallabag." | 83 | help_language: "Vous pouvez définir la langue de l’interface de wallabag." |
85 | help_pocket_consumer_key: "Nécessaire pour l’import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket." | 84 | help_pocket_consumer_key: "Nécessaire pour l’import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket." |
86 | form_rss: | 85 | form_feed: |
87 | description: "Les flux RSS fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton." | 86 | description: "Les flux Atom fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton." |
88 | token_label: "Jeton RSS" | 87 | token_label: "Jeton de flux" |
89 | no_token: "Aucun jeton généré" | 88 | no_token: "Aucun jeton généré" |
90 | token_create: "Créez votre jeton" | 89 | token_create: "Créez votre jeton" |
91 | token_reset: "Réinitialisez votre jeton" | 90 | token_reset: "Réinitialisez votre jeton" |
92 | rss_links: "Adresses de vos flux RSS" | 91 | token_revoke: 'Supprimer le jeton' |
93 | rss_link: | 92 | feed_links: "Adresses de vos flux" |
93 | feed_link: | ||
94 | unread: "Non lus" | 94 | unread: "Non lus" |
95 | starred: "Favoris" | 95 | starred: "Favoris" |
96 | archive: "Lus" | 96 | archive: "Lus" |
97 | all: "Tous" | 97 | all: "Tous" |
98 | rss_limit: "Nombre d’articles dans le flux" | 98 | feed_limit: "Nombre d’articles dans le flux" |
99 | form_user: | 99 | 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." | 100 | 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 | login_label: 'Identifiant' | ||
101 | name_label: "Nom" | 102 | name_label: "Nom" |
102 | email_label: "Adresse courriel" | 103 | email_label: "Adresse courriel" |
103 | twoFactorAuthentication_label: "Double authentification" | 104 | two_factor: |
104 | help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." | 105 | emailTwoFactor_label: 'En utlisant l’email (recevez un code par email)' |
106 | 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)' | ||
107 | table_method: Méthode | ||
108 | table_state: État | ||
109 | table_action: Action | ||
110 | state_enabled: Activé | ||
111 | state_disabled: Désactivé | ||
112 | action_email: Utiliser l'email | ||
113 | action_app: Utiliser une app OTP | ||
105 | delete: | 114 | delete: |
106 | title: "Supprimer mon compte (attention danger !)" | 115 | 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é." | 116 | 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é." |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: "éditer" | 136 | edit_rule_label: "éditer" |
128 | rule_label: "Règle" | 137 | rule_label: "Règle" |
129 | tags_label: "Tags" | 138 | tags_label: "Tags" |
139 | card: | ||
140 | new_tagging_rule: Créer une règle | ||
141 | import_tagging_rules: Importer des règles | ||
142 | import_tagging_rules_detail: Vous devez sélectionné un fichier JSON que vous avez précédemment exporté. | ||
143 | export_tagging_rules: Exporter les règles | ||
144 | export_tagging_rules_detail: Un fichier JSON sera téléchargé et vous pourrez l'utiliser pour ré-importer les règles ou comme sauvegarde. | ||
145 | file_label: Fichier JSON | ||
146 | import_submit: Importer | ||
147 | export: Export | ||
130 | faq: | 148 | faq: |
131 | title: "FAQ" | 149 | title: "FAQ" |
132 | tagging_rules_definition_title: "Que signifient les règles de tag automatiques ?" | 150 | tagging_rules_definition_title: "Que signifient les règles de tag automatiques ?" |
@@ -159,6 +177,15 @@ config: | |||
159 | and: "Une règle ET l’autre" | 177 | 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>" | 178 | 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>" | 179 | 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>" |
180 | otp: | ||
181 | page_title: Authentification double-facteur | ||
182 | app: | ||
183 | 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. | ||
184 | two_factor_code_description_2: 'Vous pouvez scanner le QR code avec votre application :' | ||
185 | 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 :' | ||
186 | two_factor_code_description_4: 'Testez un code généré par votre application OTP :' | ||
187 | cancel: Annuler | ||
188 | enable: Activer | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: "Titre de l’article" | 191 | default_title: "Titre de l’article" |
@@ -237,7 +264,7 @@ entry: | |||
237 | provided_by: "Fourni par" | 264 | provided_by: "Fourni par" |
238 | new: | 265 | new: |
239 | page_title: "Sauvegarder un nouvel article" | 266 | page_title: "Sauvegarder un nouvel article" |
240 | placeholder: "http://website.com" | 267 | placeholder: "https://website.fr" |
241 | form_new: | 268 | form_new: |
242 | url_label: "Adresse" | 269 | url_label: "Adresse" |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | delete: "Voulez-vous vraiment supprimer cet article ?" | 281 | delete: "Voulez-vous vraiment supprimer cet article ?" |
255 | delete_tag: "Voulez-vous vraiment supprimer ce tag de cet article ?" | 282 | delete_tag: "Voulez-vous vraiment supprimer ce tag de cet article ?" |
283 | metadata: | ||
284 | reading_time: "Durée de lecture estimée" | ||
285 | reading_time_minutes_short: "%readingTime% min" | ||
286 | address: "Adresse" | ||
287 | added_on: "Ajouté le" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: "À propos" | 290 | page_title: "À propos" |
@@ -290,7 +322,7 @@ howto: | |||
290 | tab_menu: | 322 | tab_menu: |
291 | add_link: "Ajouter un lien" | 323 | add_link: "Ajouter un lien" |
292 | shortcuts: "Utiliser les raccourcis" | 324 | shortcuts: "Utiliser les raccourcis" |
293 | page_description: "Il y a plusieurs façon d’enregistrer un article :" | 325 | page_description: "Il y a plusieurs façons d’enregistrer un article :" |
294 | top_menu: | 326 | top_menu: |
295 | browser_addons: "Extensions de navigateur" | 327 | browser_addons: "Extensions de navigateur" |
296 | mobile_apps: "Applications smartphone" | 328 | mobile_apps: "Applications smartphone" |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: "Configurez l’application" | 380 | title: "Configurez l’application" |
349 | description: "Pour voir une application qui vous correspond, allez voir du côté de la configuration de wallabag." | 381 | description: "Pour voir une application qui vous correspond, allez voir du côté de la configuration de wallabag." |
350 | language: "Changez la langue et le design de l’application" | 382 | language: "Changez la langue et le design de l’application" |
351 | rss: "Activez les flux RSS" | 383 | feed: "Activez les flux Atom" |
352 | tagging_rules: "Écrivez des règles pour classer automatiquement vos articles" | 384 | tagging_rules: "Écrivez des règles pour classer automatiquement vos articles" |
353 | admin: | 385 | admin: |
354 | title: "Administration" | 386 | title: "Administration" |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." | 429 | number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." |
398 | see_untagged_entries: "Voir les articles sans tag" | 430 | see_untagged_entries: "Voir les articles sans tag" |
431 | no_untagged_entries: 'Aucun article sans tag.' | ||
399 | new: | 432 | new: |
400 | add: "Ajouter" | 433 | add: "Ajouter" |
401 | placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule." | 434 | placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule." |
435 | rename: | ||
436 | placeholder: 'Vous pouvez changer le nom de votre tag.' | ||
402 | 437 | ||
403 | export: | 438 | export: |
404 | 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>' | 439 | 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>' |
440 | unknown: 'Inconnu' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: "Importer" | 443 | page_title: "Importer" |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: "Importer > wallabag v2" | 466 | page_title: "Importer > wallabag v2" |
431 | description: "Cet outil va importer tous vos articles d’une autre instance de wallabag v2. Allez dans tous vos articles, puis, sur la barre latérale, cliquez sur « JSON ». Vous allez récupérer un fichier « All articles.json »" | 467 | description: "Cet outil va importer tous vos articles d’une autre instance de wallabag v2. Allez dans tous vos articles, puis, sur la barre latérale, cliquez sur « JSON ». Vous allez récupérer un fichier « All articles.json »" |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: "Importer > Readability" | 472 | page_title: "Importer > Readability" |
434 | description: "Cet outil va importer toutes vos données de Readability. Sur la page des outils (https://www.readability.com/tools/), cliquez sur « Export your data » dans la section « Data Export ». Vous allez recevoir un courriel avec un lien pour télécharger le json." | 473 | description: "Cet outil va importer toutes vos données de Readability. Sur la page des outils (https://www.readability.com/tools/), cliquez sur « Export your data » dans la section « Data Export ». Vous allez recevoir un courriel avec un lien pour télécharger le json." |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: "Adresses de redirection (optionnel)" | 521 | redirect_uris_label: "Adresses de redirection (optionnel)" |
483 | save_label: "Créer un nouveau client" | 522 | save_label: "Créer un nouveau client" |
484 | action_back: "Retour" | 523 | action_back: "Retour" |
524 | copy_to_clipboard: Copier | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: "Gestion des clients API > Les paramètres de votre client" | 526 | page_title: "Gestion des clients API > Les paramètres de votre client" |
487 | page_description: "Voilà les paramètres de votre client" | 527 | page_description: "Voilà les paramètres de votre client" |
@@ -515,7 +555,7 @@ user: | |||
515 | no: "Non" | 555 | no: "Non" |
516 | create_new_one: "Créer un nouvel utilisateur" | 556 | create_new_one: "Créer un nouvel utilisateur" |
517 | form: | 557 | form: |
518 | username_label: "Nom d’utilisateur" | 558 | username_label: "Identifiant (ne peut être changé)" |
519 | name_label: "Nom" | 559 | name_label: "Nom" |
520 | password_label: "Mot de passe" | 560 | password_label: "Mot de passe" |
521 | repeat_new_password_label: "Confirmez votre nouveau mot de passe" | 561 | repeat_new_password_label: "Confirmez votre nouveau mot de passe" |
@@ -524,12 +564,14 @@ user: | |||
524 | enabled_label: "Activé" | 564 | enabled_label: "Activé" |
525 | last_login_label: "Dernière connexion" | 565 | last_login_label: "Dernière connexion" |
526 | twofactor_label: "Double authentification" | 566 | twofactor_label: "Double authentification" |
567 | twofactor_email_label: Double authentification par email | ||
568 | twofactor_google_label: Double authentification par OTP app | ||
527 | save: "Sauvegarder" | 569 | save: "Sauvegarder" |
528 | delete: "Supprimer" | 570 | delete: "Supprimer" |
529 | delete_confirm: "Êtes-vous sûr ?" | 571 | delete_confirm: "Êtes-vous sûr ?" |
530 | back_to_list: "Revenir à la liste" | 572 | back_to_list: "Revenir à la liste" |
531 | search: | 573 | search: |
532 | placeholder: "Filtrer par nom d’utilisateur ou email" | 574 | placeholder: "Filtrer par identifiant ou email" |
533 | 575 | ||
534 | site_credential: | 576 | site_credential: |
535 | page_title: Gestion des accès aux sites | 577 | page_title: Gestion des accès aux sites |
@@ -544,7 +586,7 @@ site_credential: | |||
544 | create_new_one: Créer un nouvel accès à un site | 586 | create_new_one: Créer un nouvel accès à un site |
545 | form: | 587 | form: |
546 | username_label: 'Identifiant' | 588 | username_label: 'Identifiant' |
547 | host_label: 'Domaine' | 589 | host_label: 'Domaine (subdomain.example.org, .example.org, etc.)' |
548 | password_label: 'Mot de passe' | 590 | password_label: 'Mot de passe' |
549 | save: "Sauvegarder" | 591 | save: "Sauvegarder" |
550 | delete: "Supprimer" | 592 | delete: "Supprimer" |
@@ -561,14 +603,18 @@ flashes: | |||
561 | password_updated: "Votre mot de passe a bien été mis à jour" | 603 | password_updated: "Votre mot de passe a bien été mis à jour" |
562 | password_not_updated_demo: "En démo, vous ne pouvez pas changer le mot de passe de cet utilisateur." | 604 | password_not_updated_demo: "En démo, vous ne pouvez pas changer le mot de passe de cet utilisateur." |
563 | user_updated: "Vos informations personnelles ont bien été mises à jour" | 605 | user_updated: "Vos informations personnelles ont bien été mises à jour" |
564 | rss_updated: "La configuration des flux RSS a bien été mise à jour" | 606 | feed_updated: "La configuration des flux a bien été mise à jour" |
565 | tagging_rules_updated: "Règles mises à jour" | 607 | tagging_rules_updated: "Règles mises à jour" |
566 | tagging_rules_deleted: "Règle supprimée" | 608 | tagging_rules_deleted: "Règle supprimée" |
567 | rss_token_updated: "Jeton RSS mis à jour" | 609 | feed_token_updated: "Jeton des flux mis à jour" |
610 | feed_token_revoked: 'Jeton des flux supprimé' | ||
568 | annotations_reset: "Annotations supprimées" | 611 | annotations_reset: "Annotations supprimées" |
569 | tags_reset: "Tags supprimés" | 612 | tags_reset: "Tags supprimés" |
570 | entries_reset: "Articles supprimés" | 613 | entries_reset: "Articles supprimés" |
571 | archived_reset: "Articles archivés supprimés" | 614 | archived_reset: "Articles archivés supprimés" |
615 | otp_enabled: "Authentification à double-facteur activée" | ||
616 | tagging_rules_imported: Règles bien importées | ||
617 | tagging_rules_not_imported: Impossible d'importer les règles | ||
572 | entry: | 618 | entry: |
573 | notice: | 619 | notice: |
574 | entry_already_saved: "Article déjà sauvegardé le %date%" | 620 | entry_already_saved: "Article déjà sauvegardé le %date%" |
@@ -582,9 +628,11 @@ flashes: | |||
582 | entry_starred: "Article ajouté dans les favoris" | 628 | entry_starred: "Article ajouté dans les favoris" |
583 | entry_unstarred: "Article retiré des favoris" | 629 | entry_unstarred: "Article retiré des favoris" |
584 | entry_deleted: "Article supprimé" | 630 | entry_deleted: "Article supprimé" |
631 | no_random_entry: "Aucun article correspond aux critères n'a été trouvé" | ||
585 | tag: | 632 | tag: |
586 | notice: | 633 | notice: |
587 | tag_added: "Tag ajouté" | 634 | tag_added: "Tag ajouté" |
635 | tag_renamed: "Tag renommé" | ||
588 | import: | 636 | import: |
589 | notice: | 637 | notice: |
590 | failed: "L’import a échoué, veuillez ré-essayer" | 638 | 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 83b3edcd..8cee3e52 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Torna ai contenuti non letti' | 33 | back_to_unread: 'Torna ai contenuti non letti' |
34 | users_management: 'Gestione utenti' | 34 | users_management: 'Gestione utenti' |
35 | site_credentials: 'Credenziali sito' | 35 | site_credentials: 'Credenziali sito' |
36 | quickstart: "Introduzione" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Aggiungi un nuovo contenuto' | 38 | add_new_entry: 'Aggiungi un nuovo contenuto' |
38 | search: 'Cerca' | 39 | search: 'Cerca' |
39 | filter_entries: 'Filtra contenuti' | 40 | filter_entries: 'Filtra contenuti' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | export: 'Esporta' | 42 | export: 'Esporta' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Inserisci qui la tua ricerca' | 44 | input_label: 'Inserisci qui la tua ricerca' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Configurazione' | 55 | page_title: 'Configurazione' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Impostazioni' | 57 | settings: 'Impostazioni' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Informazioni utente' | 59 | user_info: 'Informazioni utente' |
58 | password: 'Password' | 60 | password: 'Password' |
59 | rules: 'Regole di etichettatura' | 61 | rules: 'Regole di etichettatura' |
60 | new_user: 'Aggiungi utente' | 62 | new_user: 'Aggiungi utente' |
63 | reset: 'Area di reset' | ||
61 | form: | 64 | form: |
62 | save: 'Salva' | 65 | save: 'Salva' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Elementi per pagina' | 68 | items_per_page_label: 'Elementi per pagina' |
66 | language_label: 'Lingua' | 69 | language_label: 'Lingua' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Velocità di lettura' | 71 | label: 'Velocità di lettura (parole al minuto)' |
69 | help_message: 'Puoi utilizzare degli strumenti online per valutare la tua velocità di lettura:' | 72 | help_message: 'Puoi utilizzare degli strumenti online per valutare la tua velocità di lettura:' |
70 | 100_word: 'Leggo ~100 parole al minuto' | ||
71 | 200_word: 'Leggo ~200 parole al minuto' | ||
72 | 300_word: 'Leggo ~300 parole al minuto' | ||
73 | 400_word: 'Leggo ~400 parole al minuto' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: "Dove vuoi essere reindirizzato dopo aver segnato l'articolo come già letto?" | 74 | label: "Dove vuoi essere reindirizzato dopo aver segnato l'articolo come già letto?" |
76 | redirect_homepage: 'Alla homepage' | 75 | redirect_homepage: 'Alla homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag calcola un tempo di lettura per ogni articolo. Puoi definire qui, grazie a questa lista, se sei un lettore lento o veloce. wallabag ricalcolerà la velocità di lettura per ogni articolo." | 82 | help_reading_speed: "wallabag calcola un tempo di lettura per ogni articolo. Puoi definire qui, grazie a questa lista, se sei un lettore lento o veloce. wallabag ricalcolerà la velocità di lettura per ogni articolo." |
84 | help_language: "Puoi cambiare la lingua dell'interfaccia di wallabag." | 83 | help_language: "Puoi cambiare la lingua dell'interfaccia di wallabag." |
85 | help_pocket_consumer_key: "Richiesta per importare da Pocket. La puoi creare nel tuo account Pocket." | 84 | help_pocket_consumer_key: "Richiesta per importare da Pocket. La puoi creare nel tuo account Pocket." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'I feed RSS generati da wallabag ti permettono di leggere i tuoi contenuti salvati con il tuo lettore di RSS preferito. Prima, devi generare un token.' | 86 | description: 'I feed RSS generati da wallabag ti permettono di leggere i tuoi contenuti salvati con il tuo lettore di RSS preferito. Prima, devi generare un token.' |
88 | token_label: 'Token RSS' | 87 | token_label: 'Token RSS' |
89 | no_token: 'Nessun token' | 88 | no_token: 'Nessun token' |
90 | token_create: 'Crea il tuo token' | 89 | token_create: 'Crea il tuo token' |
91 | token_reset: 'Rigenera il tuo token' | 90 | token_reset: 'Rigenera il tuo token' |
92 | rss_links: 'Collegamenti RSS' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'Collegamenti RSS' |
93 | feed_link: | ||
94 | unread: 'Non letti' | 94 | unread: 'Non letti' |
95 | starred: 'Preferiti' | 95 | starred: 'Preferiti' |
96 | archive: 'Archiviati' | 96 | archive: 'Archiviati' |
97 | # all: 'All' | 97 | # all: 'All' |
98 | rss_limit: 'Numero di elementi nel feed' | 98 | feed_limit: 'Numero di elementi nel feed' |
99 | form_user: | 99 | 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" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'Nome' | 102 | name_label: 'Nome' |
102 | email_label: 'E-mail' | 103 | email_label: 'E-mail' |
103 | twoFactorAuthentication_label: 'Autenticazione a due fattori' | 104 | two_factor: |
104 | help_twoFactorAuthentication: "Se abiliti l'autenticazione a due fattori, ogni volta che vorrai connetterti a wallabag, riceverai un codice via E-mail." | 105 | # emailTwoFactor_label: 'Using email (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: 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. |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'modifica' | 136 | edit_rule_label: 'modifica' |
128 | rule_label: 'Regola' | 137 | rule_label: 'Regola' |
129 | tags_label: 'Etichetta' | 138 | tags_label: 'Etichetta' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: 'Cosa significa « regole di etichettatura » ?' | 150 | tagging_rules_definition_title: 'Cosa significa « regole di etichettatura » ?' |
@@ -159,6 +177,15 @@ config: | |||
159 | and: "Una regola E un'altra" | 177 | 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>' | 178 | 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>' | 179 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: "Titolo del contenuto" | 191 | default_title: "Titolo del contenuto" |
@@ -237,7 +264,7 @@ entry: | |||
237 | # provided_by: 'Provided by' | 264 | # provided_by: 'Provided by' |
238 | new: | 265 | new: |
239 | page_title: 'Salva un nuovo contenuto' | 266 | page_title: 'Salva un nuovo contenuto' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.it' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | delete: "Vuoi veramente rimuovere quell'articolo?" | 281 | delete: "Vuoi veramente rimuovere quell'articolo?" |
255 | delete_tag: "Vuoi veramente rimuovere quell'etichetta da quell'articolo?" | 282 | delete_tag: "Vuoi veramente rimuovere quell'etichetta da quell'articolo?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'A proposito' | 290 | page_title: 'A proposito' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: "Configura l'applicazione" | 380 | title: "Configura l'applicazione" |
349 | description: "Per avere un'applicazione che ti soddisfi, dai un'occhiata alla configurazione di wallabag." | 381 | description: "Per avere un'applicazione che ti soddisfi, dai un'occhiata alla configurazione di wallabag." |
350 | language: 'Cambia lingua e design' | 382 | language: 'Cambia lingua e design' |
351 | rss: 'Abilita i feed RSS' | 383 | feed: 'Abilita i feed RSS' |
352 | tagging_rules: 'Scrivi delle regole per taggare automaticamente i contenuti' | 384 | tagging_rules: 'Scrivi delle regole per taggare automaticamente i contenuti' |
353 | admin: | 385 | admin: |
354 | title: 'Amministrazione' | 386 | title: 'Amministrazione' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: "{0} Non ci sono etichette.|{1} C'è un'etichetta.|]1,Inf[ ci sono %count% etichette." | 429 | number_on_the_page: "{0} Non ci sono etichette.|{1} C'è un'etichetta.|]1,Inf[ ci sono %count% etichette." |
398 | see_untagged_entries: 'Vedi articoli non etichettati' | 430 | see_untagged_entries: 'Vedi articoli non etichettati' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | add: 'Aggiungi' | 433 | add: 'Aggiungi' |
401 | placeholder: 'Puoi aggiungere varie etichette, separate da una virgola.' | 434 | placeholder: 'Puoi aggiungere varie etichette, separate da una virgola.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
402 | 437 | ||
403 | # export: | 438 | # export: |
404 | # 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>' | 439 | # 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>' |
440 | # unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Importa' | 443 | page_title: 'Importa' |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Importa da > Wallabag v2' | 466 | page_title: 'Importa da > Wallabag v2' |
431 | description: 'Questo importatore copierà tutti i tuoi dati da un wallabag v2. Vai in "Tutti i contenuti", e, nella barra laterale di esportazione, clicca su "JSON". Otterrai un file "Tutti i contenuti.json' | 467 | description: 'Questo importatore copierà tutti i tuoi dati da un wallabag v2. Vai in "Tutti i contenuti", e, nella barra laterale di esportazione, clicca su "JSON". Otterrai un file "Tutti i contenuti.json' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Importa da > Readability' | 472 | page_title: 'Importa da > Readability' |
434 | description: 'Questo importatore copierà tutti i tuoi articoli da Readability. Nella pagina strumenti (https://www.readability.com/tools/), clicca su "Export your data" nella sezione "Data Export". Riceverai una E-mail per scaricare un file json (che tuttavia non termina con .json).' | 473 | description: 'Questo importatore copierà tutti i tuoi articoli da Readability. Nella pagina strumenti (https://www.readability.com/tools/), clicca su "Export your data" nella sezione "Data Export". Riceverai una E-mail per scaricare un file json (che tuttavia non termina con .json).' |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: 'Redirect URI' | 521 | redirect_uris_label: 'Redirect URI' |
483 | save_label: 'Crea un nuovo client' | 522 | save_label: 'Crea un nuovo client' |
484 | action_back: 'Indietro' | 523 | action_back: 'Indietro' |
524 | # copy_to_clipboard: Copy | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: 'Gestione client API > Parametri Client' | 526 | page_title: 'Gestione client API > Parametri Client' |
487 | page_description: 'Questi sono i tuoi parametri del client.' | 527 | page_description: 'Questi sono i tuoi parametri del client.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'E-mail' | 563 | email_label: 'E-mail' |
524 | enabled_label: 'Abilitato' | 564 | enabled_label: 'Abilitato' |
525 | last_login_label: 'Ultima connessione' | 565 | last_login_label: 'Ultima connessione' |
526 | twofactor_label: Autenticazione a due fattori | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
527 | save: Salva | 568 | save: Salva |
528 | delete: Cancella | 569 | delete: Cancella |
529 | delete_confirm: Sei sicuro? | 570 | delete_confirm: Sei sicuro? |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | # create_new_one: Create a new credential | 585 | # create_new_one: Create a new credential |
545 | # form: | 586 | # form: |
546 | # username_label: 'Username' | 587 | # username_label: 'Username' |
547 | # host_label: 'Host' | 588 | # host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | # password_label: 'Password' | 589 | # password_label: 'Password' |
549 | # save: Save | 590 | # save: Save |
550 | # delete: Delete | 591 | # delete: Delete |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Password aggiornata' | 602 | password_updated: 'Password aggiornata' |
562 | password_not_updated_demo: "In modalità demo, non puoi cambiare la password dell'utente." | 603 | password_not_updated_demo: "In modalità demo, non puoi cambiare la password dell'utente." |
563 | user_updated: 'Informazioni aggiornate' | 604 | user_updated: 'Informazioni aggiornate' |
564 | rss_updated: 'Informazioni RSS aggiornate' | 605 | feed_updated: 'Informazioni RSS aggiornate' |
565 | tagging_rules_updated: 'Regole di etichettatura aggiornate' | 606 | tagging_rules_updated: 'Regole di etichettatura aggiornate' |
566 | tagging_rules_deleted: 'Regola di etichettatura eliminate' | 607 | tagging_rules_deleted: 'Regola di etichettatura eliminate' |
567 | rss_token_updated: 'RSS token aggiornato' | 608 | feed_token_updated: 'RSS token aggiornato' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
568 | annotations_reset: Reset annotazioni | 610 | annotations_reset: Reset annotazioni |
569 | tags_reset: Reset etichette | 611 | tags_reset: Reset etichette |
570 | entries_reset: Reset articoli | 612 | entries_reset: Reset articoli |
571 | # archived_reset: Archived entries deleted | 613 | # archived_reset: Archived entries deleted |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Contenuto già salvato in data %date%' | 619 | entry_already_saved: 'Contenuto già salvato in data %date%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Contenuto segnato come preferito' | 627 | entry_starred: 'Contenuto segnato come preferito' |
583 | entry_unstarred: 'Contenuto rimosso dai preferiti' | 628 | entry_unstarred: 'Contenuto rimosso dai preferiti' |
584 | entry_deleted: 'Contenuto eliminato' | 629 | entry_deleted: 'Contenuto eliminato' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Etichetta aggiunta' | 633 | tag_added: 'Etichetta aggiunta' |
634 | # tag_renamed: 'Tag renamed' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'Importazione fallita, riprova.' | 637 | 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 95bc9560..052582ab 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Tornar als articles pas legits' | 33 | back_to_unread: 'Tornar als articles pas legits' |
34 | users_management: 'Gestion dels utilizaires' | 34 | users_management: 'Gestion dels utilizaires' |
35 | site_credentials: 'Identificants del site' | 35 | site_credentials: 'Identificants del site' |
36 | quickstart: "Per ben començar" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Enregistrar un novèl article' | 38 | add_new_entry: 'Enregistrar un novèl article' |
38 | search: 'Cercar' | 39 | search: 'Cercar' |
39 | filter_entries: 'Filtrar los articles' | 40 | filter_entries: 'Filtrar los articles' |
41 | random_entry: "Sautar a un article a l'azard" | ||
40 | export: 'Exportar' | 42 | export: 'Exportar' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Picatz vòstre mot-clau a cercar aquí' | 44 | input_label: 'Picatz vòstre mot-clau a cercar aquí' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Configuracion' | 55 | page_title: 'Configuracion' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Paramètres' | 57 | settings: 'Paramètres' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Mon compte' | 59 | user_info: 'Mon compte' |
58 | password: 'Senhal' | 60 | password: 'Senhal' |
59 | rules: "Règlas d'etiquetas automaticas" | 61 | rules: "Règlas d'etiquetas automaticas" |
60 | new_user: 'Crear un compte' | 62 | new_user: 'Crear un compte' |
63 | reset: 'Zòna de reïnicializacion' | ||
61 | form: | 64 | form: |
62 | save: 'Enregistrar' | 65 | save: 'Enregistrar' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: "Nombre d'articles per pagina" | 68 | items_per_page_label: "Nombre d'articles per pagina" |
66 | language_label: 'Lenga' | 69 | language_label: 'Lenga' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Velocitat de lectura' | 71 | label: 'Velocitat de lectura (mots per minuta)' |
69 | help_message: 'Podètz utilizar una aisina en linha per estimar vòstra velocitat de lectura :' | 72 | help_message: 'Podètz utilizar una aisina en linha per estimar vòstra velocitat de lectura :' |
70 | 100_word: "Legissi a l'entorn de 100 mots per minuta" | ||
71 | 200_word: "Legissi a l'entorn de 200 mots per minuta" | ||
72 | 300_word: "Legissi a l'entorn de 300 mots per minuta" | ||
73 | 400_word: "Legissi a l'entorn de 400 mots per minuta" | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: 'Ont volètz èsser menat aprèp aver marcat un article coma legit ?' | 74 | label: 'Ont volètz èsser menat aprèp aver marcat un article coma legit ?' |
76 | redirect_homepage: "A la pagina d’acuèlh" | 75 | redirect_homepage: "A la pagina d’acuèlh" |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag calcula lo temps de lectura per cada article. Podètz lo definir aquí, gràcias a aquesta lista, se sètz un legeire rapid o lent. wallabag tornarà calcular lo temps de lectura per cada article." | 82 | help_reading_speed: "wallabag calcula lo temps de lectura per cada article. Podètz lo definir aquí, gràcias a aquesta lista, se sètz un legeire rapid o lent. wallabag tornarà calcular lo temps de lectura per cada article." |
84 | help_language: "Podètz cambiar la lenga de l'interfàcia de wallabag." | 83 | help_language: "Podètz cambiar la lenga de l'interfàcia de wallabag." |
85 | help_pocket_consumer_key: "Requesida per l'importacion de Pocket. Podètz la crear dins vòstre compte Pocket." | 84 | help_pocket_consumer_key: "Requesida per l'importacion de Pocket. Podètz la crear dins vòstre compte Pocket." |
86 | form_rss: | 85 | form_feed: |
87 | description: "Los fluxes RSS fornits per wallabag vos permeton de legir vòstres articles salvagardats dins vòstre lector de fluxes preferit. Per los poder emplegar, vos cal, d'en primièr crear un geton." | 86 | description: "Los fluxes RSS fornits per wallabag vos permeton de legir vòstres articles salvagardats dins vòstre lector de fluxes preferit. Per los poder emplegar, vos cal, d'en primièr crear un geton." |
88 | token_label: 'Geton RSS' | 87 | token_label: 'Geton RSS' |
89 | no_token: 'Pas cap de geton generat' | 88 | no_token: 'Pas cap de geton generat' |
90 | token_create: 'Creatz vòstre geton' | 89 | token_create: 'Creatz vòstre geton' |
91 | token_reset: 'Reïnicializatz vòstre geton' | 90 | token_reset: 'Reïnicializatz vòstre geton' |
92 | rss_links: 'URLs de vòstres fluxes RSS' | 91 | oken_revoke: 'Revocar lo geton' |
93 | rss_link: | 92 | feed_links: 'URLs de vòstres fluxes RSS' |
93 | feed_link: | ||
94 | unread: 'Pas legits' | 94 | unread: 'Pas legits' |
95 | starred: 'Favorits' | 95 | starred: 'Favorits' |
96 | archive: 'Legits' | 96 | archive: 'Legits' |
97 | all: 'Totes' | 97 | all: 'Totes' |
98 | rss_limit: "Nombre d'articles dins un flux RSS" | 98 | feed_limit: "Nombre d'articles dins un flux" |
99 | form_user: | 99 | 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." | 100 | two_factor_description: "L’activacion de l’autentificacion en dos temps indica que recebretz un còdi per corrièl amb un còdi O que vos cal utilizar una aplicacion OTP (coma Google Authenticator, Authy o FreeOTP) per obténer un còdi a usatge unic cada còp qu’i a una connexion pas fisabla. Podètz pas causir las doas opcions." |
101 | login_label: 'Identificant (se pòt pas cambiar)' | ||
101 | name_label: 'Nom' | 102 | name_label: 'Nom' |
102 | email_label: 'Adreça de corrièl' | 103 | email_label: 'Adreça de corrièl' |
103 | twoFactorAuthentication_label: 'Dobla autentificacion' | 104 | two_factor: |
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." | 105 | emailTwoFactor_label: 'En utilizar lo corrièl (recebre un còdi per corrièl)' |
106 | googleTwoFactor_label: 'En utilizar una aplicacion OTP (Dobrir l’aplicacion, coma Google Authenticator, Authy o FreeOTP, per obténer un còdi a usatge unic)' | ||
107 | table_method: Metòde | ||
108 | table_state: Estat | ||
109 | table_action: Accion | ||
110 | state_enabled: Activada | ||
111 | state_disabled: Desactivada | ||
112 | action_email: Utilizar lo corrièl | ||
113 | action_app: Utilizar una aplicacion OTP | ||
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. |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'modificar' | 136 | edit_rule_label: 'modificar' |
128 | rule_label: 'Règla' | 137 | rule_label: 'Règla' |
129 | tags_label: 'Etiquetas' | 138 | tags_label: 'Etiquetas' |
139 | card: | ||
140 | new_tagging_rule: Crear una règla d’etiquetatge | ||
141 | import_tagging_rules: Importar de règlas d’etiquetatge | ||
142 | import_tagging_rules_detail: Vos cal causir un fichièr JSON qu’importèretz per abans. | ||
143 | export_tagging_rules: Exportar las règlas d’etiquetatge | ||
144 | export_tagging_rules_detail: Telecargarà un fichièr JSON que podètz utilizar per importar las règlas d’etiquetatge endacòm mai o per las salvagardar. | ||
145 | file_label: fichièr JSON | ||
146 | import_submit: Importar | ||
147 | export: Exportar | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: "Qué significa las règlas d'etiquetas automaticas ?" | 150 | tagging_rules_definition_title: "Qué significa las règlas d'etiquetas automaticas ?" |
@@ -159,6 +177,15 @@ config: | |||
159 | and: "Una règla E l'autra" | 177 | 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>' | 178 | 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>' | 179 | 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>' |
180 | otp: | ||
181 | page_title: Autentificacion en dos temps | ||
182 | app: | ||
183 | two_factor_code_description_1: Avètz pas qu’activat l’autentificacion en dos temps, dobrissètz l’aplicacion OTP e utilizatz aqueste còdi per obténer un senhal unic. Apareisserà aprèp un recargament de pagina. | ||
184 | two_factor_code_description_2: 'Podètz numerizar aqueste còdi QR amb l’aplicacion :' | ||
185 | two_factor_code_description_3: 'Amai, enregistratz aquestes còdis de recuperacion dins un lòc segur, los podètz utilizar se per cas perdatz l’accès a l’aplicacion OTP :' | ||
186 | two_factor_code_description_4: 'Ensajatz un còdi de vòstra aplicacion configurada app :' | ||
187 | cancel: Anullar | ||
188 | enable: Activar | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: "Títol de l'article" | 191 | default_title: "Títol de l'article" |
@@ -186,7 +213,7 @@ entry: | |||
186 | export_title: 'Exportar' | 213 | export_title: 'Exportar' |
187 | filters: | 214 | filters: |
188 | title: 'Filtres' | 215 | title: 'Filtres' |
189 | status_label: 'Estatus' | 216 | status_label: 'Estat' |
190 | archived_label: 'Legits' | 217 | archived_label: 'Legits' |
191 | starred_label: 'Favorits' | 218 | starred_label: 'Favorits' |
192 | unread_label: 'Pas legits' | 219 | unread_label: 'Pas legits' |
@@ -195,7 +222,7 @@ entry: | |||
195 | is_public_label: 'Ten un ligam public' | 222 | is_public_label: 'Ten un ligam public' |
196 | is_public_help: 'Ligam public' | 223 | is_public_help: 'Ligam public' |
197 | language_label: 'Lenga' | 224 | language_label: 'Lenga' |
198 | http_status_label: 'Estatut HTTP' | 225 | http_status_label: 'Estat HTTP' |
199 | reading_time: | 226 | reading_time: |
200 | label: 'Durada de lectura en minutas' | 227 | label: 'Durada de lectura en minutas' |
201 | from: 'de' | 228 | from: 'de' |
@@ -237,7 +264,7 @@ entry: | |||
237 | provided_by: 'Provesit per' | 264 | provided_by: 'Provesit per' |
238 | new: | 265 | new: |
239 | page_title: 'Enregistrar un novèl article' | 266 | page_title: 'Enregistrar un novèl article' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.cat' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | delete: "Sètz segur de voler suprimir aqueste article ?" | 281 | delete: "Sètz segur de voler suprimir aqueste article ?" |
255 | delete_tag: "Sètz segur de voler levar aquesta etiqueta de l'article ?" | 282 | delete_tag: "Sètz segur de voler levar aquesta etiqueta de l'article ?" |
283 | metadata: | ||
284 | reading_time: "Temps de lectura estimat" | ||
285 | reading_time_minutes_short: "%readingTime% min" | ||
286 | address: "Adreça" | ||
287 | added_on: "Ajustat a" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'A prepaus' | 290 | page_title: 'A prepaus' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: "Configuratz l'aplicacion" | 380 | title: "Configuratz l'aplicacion" |
349 | description: "Per fin d'aver una aplicacion que vos va ben, anatz veire la configuracion de wallabag." | 381 | description: "Per fin d'aver una aplicacion que vos va ben, anatz veire la configuracion de wallabag." |
350 | language: "Cambiatz la lenga e l'estil de l'aplicacion" | 382 | language: "Cambiatz la lenga e l'estil de l'aplicacion" |
351 | rss: 'Activatz los fluxes RSS' | 383 | feed: 'Activatz los fluxes RSS' |
352 | tagging_rules: 'Escrivètz de règlas per classar automaticament vòstres articles' | 384 | tagging_rules: 'Escrivètz de règlas per classar automaticament vòstres articles' |
353 | admin: | 385 | admin: |
354 | title: 'Administracion' | 386 | title: 'Administracion' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: "{0} I a pas cap d'etiquetas.|{1} I a una etiqueta.|]1,Inf[ I a %count% etiquetas." | 429 | number_on_the_page: "{0} I a pas cap d'etiquetas.|{1} I a una etiqueta.|]1,Inf[ I a %count% etiquetas." |
398 | see_untagged_entries: "Afichar las entradas sens etiquetas" | 430 | see_untagged_entries: "Afichar las entradas sens etiquetas" |
431 | no_untagged_entries: 'I a pas cap d’article pas etiquetat.' | ||
399 | new: | 432 | new: |
400 | add: 'Ajustar' | 433 | add: 'Ajustar' |
401 | placeholder: "Podètz ajustar mai qu'una etiqueta, separadas per de virgula." | 434 | placeholder: "Podètz ajustar mai qu'una etiqueta, separadas per de virgula." |
435 | rename: | ||
436 | placeholder: 'Podètz actualizar lo nom de l’etiqueta.' | ||
402 | 437 | ||
403 | export: | 438 | export: |
404 | 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>' | 439 | 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>' |
440 | unknown: 'Desconegut' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Importar' | 443 | page_title: 'Importar' |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Importar > Wallabag v2' | 466 | page_title: 'Importar > Wallabag v2' |
431 | description: "Aquesta aisina importarà totas vòstras donadas d'una instància mai de wallabag v2. Anatz dins totes vòstres articles, puèi, sus la barra laterala, clicatz sus \"JSON\". Traparetz un fichièr \"All articles.json\"." | 467 | description: "Aquesta aisina importarà totas vòstras donadas d'una instància mai de wallabag v2. Anatz dins totes vòstres articles, puèi, sus la barra laterala, clicatz sus \"JSON\". Traparetz un fichièr \"All articles.json\"." |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Importar > Readability' | 472 | page_title: 'Importar > Readability' |
434 | description: "Aquesta aisina importarà totas vòstres articles de Readability. Sus la pagina de l'aisina (https://www.readability.com/tools/), clicatz sus \"Export your data\" dins la seccion \"Data Export\". Recebretz un corrièl per telecargar un json (qu'acaba pas amb un .json de fach)." | 473 | description: "Aquesta aisina importarà totas vòstres articles de Readability. Sus la pagina de l'aisina (https://www.readability.com/tools/), clicatz sus \"Export your data\" dins la seccion \"Data Export\". Recebretz un corrièl per telecargar un json (qu'acaba pas amb un .json de fach)." |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: 'URLs de redireccion' | 521 | redirect_uris_label: 'URLs de redireccion' |
483 | save_label: 'Crear un novèl client' | 522 | save_label: 'Crear un novèl client' |
484 | action_back: 'Retorn' | 523 | action_back: 'Retorn' |
524 | copy_to_clipboard: Copiar | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: 'Gestion dels clients API > Los paramètres de vòstre client' | 526 | page_title: 'Gestion dels clients API > Los paramètres de vòstre client' |
487 | page_description: 'Vaquí los paramètres de vòstre client.' | 527 | page_description: 'Vaquí los paramètres de vòstre client.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'Adreça de corrièl' | 563 | email_label: 'Adreça de corrièl' |
524 | enabled_label: 'Actiu' | 564 | enabled_label: 'Actiu' |
525 | last_login_label: 'Darrièra connexion' | 565 | last_login_label: 'Darrièra connexion' |
526 | twofactor_label: 'Autentificacion doble-factor' | 566 | twofactor_email_label: Autentificacion en dos temps per corrièl |
567 | twofactor_google_label: Autentificacion en dos temps per aplicacion OTP | ||
527 | save: 'Enregistrar' | 568 | save: 'Enregistrar' |
528 | delete: 'Suprimir' | 569 | delete: 'Suprimir' |
529 | delete_confirm: 'Sètz segur ?' | 570 | delete_confirm: 'Sètz segur ?' |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | create_new_one: Crear un novèl identificant | 585 | create_new_one: Crear un novèl identificant |
545 | form: | 586 | form: |
546 | username_label: "Nom d'utilizaire" | 587 | username_label: "Nom d'utilizaire" |
547 | host_label: 'Òste' | 588 | host_label: 'Òste (subdomain.example.org, .example.org, etc.)' |
548 | password_label: 'Senhal' | 589 | password_label: 'Senhal' |
549 | save: 'Enregistrar' | 590 | save: 'Enregistrar' |
550 | delete: 'Suprimir' | 591 | delete: 'Suprimir' |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Vòstre senhal es ben estat mes a jorn' | 602 | password_updated: 'Vòstre senhal es ben estat mes a jorn' |
562 | password_not_updated_demo: "En demostracion, podètz pas cambiar lo senhal d'aqueste utilizaire." | 603 | password_not_updated_demo: "En demostracion, podètz pas cambiar lo senhal d'aqueste utilizaire." |
563 | user_updated: 'Vòstres informacions personnelas son ben estadas mesas a jorn' | 604 | user_updated: 'Vòstres informacions personnelas son ben estadas mesas a jorn' |
564 | rss_updated: 'La configuracion dels fluxes RSS es ben estada mesa a jorn' | 605 | feed_updated: 'La configuracion dels fluxes RSS es ben estada mesa a jorn' |
565 | tagging_rules_updated: 'Règlas misa a jorn' | 606 | tagging_rules_updated: 'Règlas misa a jorn' |
566 | tagging_rules_deleted: 'Règla suprimida' | 607 | tagging_rules_deleted: 'Règla suprimida' |
567 | rss_token_updated: 'Geton RSS mes a jorn' | 608 | feed_token_updated: 'Geton RSS mes a jorn' |
609 | feed_token_revoked: 'Geton RSS revocat' | ||
568 | annotations_reset: Anotacions levadas | 610 | annotations_reset: Anotacions levadas |
569 | tags_reset: Etiquetas levadas | 611 | tags_reset: Etiquetas levadas |
570 | entries_reset: Articles levats | 612 | entries_reset: Articles levats |
571 | archived_reset: Articles archivat suprimits | 613 | archived_reset: Articles archivat suprimits |
614 | otp_enabled: Autentificacion en dos temps activada | ||
615 | tagging_rules_imported: Règlas d’etiquetatge importadas | ||
616 | tagging_rules_not_imported: Error en important las règlas d’etiquetatge | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Article ja salvagardat lo %date%' | 619 | entry_already_saved: 'Article ja salvagardat lo %date%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Article ajustat dins los favorits' | 627 | entry_starred: 'Article ajustat dins los favorits' |
583 | entry_unstarred: 'Article quitat dels favorits' | 628 | entry_unstarred: 'Article quitat dels favorits' |
584 | entry_deleted: 'Article suprimit' | 629 | entry_deleted: 'Article suprimit' |
630 | no_random_entry: 'Cap d’article pas trobat amb aquestes critèris' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Etiqueta ajustada' | 633 | tag_added: 'Etiqueta ajustada' |
634 | tag_renamed: 'Etiqueta renomenada' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: "L'importacion a fracassat, mercés de tornar ensajar." | 637 | 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 a64e60b0..93e8f852 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Powrót do nieprzeczytanych artykułów' | 33 | back_to_unread: 'Powrót do nieprzeczytanych artykułów' |
34 | users_management: 'Zarządzanie użytkownikami' | 34 | users_management: 'Zarządzanie użytkownikami' |
35 | site_credentials: 'Poświadczenia strony' | 35 | site_credentials: 'Poświadczenia strony' |
36 | quickstart: "Szybki start" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Dodaj nowy wpis' | 38 | add_new_entry: 'Dodaj nowy wpis' |
38 | search: 'Szukaj' | 39 | search: 'Szukaj' |
39 | filter_entries: 'Filtruj wpisy' | 40 | filter_entries: 'Filtruj wpisy' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | export: 'Eksportuj' | 42 | export: 'Eksportuj' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Wpisz swoje zapytanie tutaj' | 44 | input_label: 'Wpisz swoje zapytanie tutaj' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Konfiguracja' | 55 | page_title: 'Konfiguracja' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Ustawienia' | 57 | settings: 'Ustawienia' |
56 | rss: 'Kanał RSS' | 58 | feed: 'Kanał RSS' |
57 | user_info: 'Informacje o użytkowniku' | 59 | user_info: 'Informacje o użytkowniku' |
58 | password: 'Hasło' | 60 | password: 'Hasło' |
59 | rules: 'Zasady tagowania' | 61 | rules: 'Zasady tagowania' |
60 | new_user: 'Dodaj użytkownika' | 62 | new_user: 'Dodaj użytkownika' |
63 | reset: 'Reset' | ||
61 | form: | 64 | form: |
62 | save: 'Zapisz' | 65 | save: 'Zapisz' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Ilość elementów na stronie' | 68 | items_per_page_label: 'Ilość elementów na stronie' |
66 | language_label: 'Język' | 69 | language_label: 'Język' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Prędkość czytania' | 71 | label: 'Prędkość czytania (słów na minutę)' |
69 | help_message: 'Możesz skorzystać z narzędzi online do określenia twojej prędkości czytania:' | 72 | help_message: 'Możesz skorzystać z narzędzi online do określenia twojej prędkości czytania:' |
70 | 100_word: 'Czytam ~100 słów na minutę' | ||
71 | 200_word: 'Czytam ~200 słów na minutę' | ||
72 | 300_word: 'Czytam ~300 słów na minutę' | ||
73 | 400_word: 'Czytam ~400 słów na minutę' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: 'Gdzie zostaniesz przekierowany po oznaczeniu artukuły jako przeczytanego' | 74 | label: 'Gdzie zostaniesz przekierowany po oznaczeniu artukuły jako przeczytanego' |
76 | redirect_homepage: 'do strony głównej' | 75 | redirect_homepage: 'do strony głównej' |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag oblicza czas czytania każdego artykułu. Dzięki tej liście możesz określić swoje tempo. Wallabag przeliczy ponownie czas potrzebny, na przeczytanie każdego z artykułów." | 82 | help_reading_speed: "wallabag oblicza czas czytania każdego artykułu. Dzięki tej liście możesz określić swoje tempo. Wallabag przeliczy ponownie czas potrzebny, na przeczytanie każdego z artykułów." |
84 | help_language: "Możesz zmienić język interfejsu wallabag." | 83 | help_language: "Możesz zmienić język interfejsu wallabag." |
85 | help_pocket_consumer_key: "Wymagane dla importu z Pocket. Możesz go stworzyć na swoim koncie Pocket." | 84 | help_pocket_consumer_key: "Wymagane dla importu z Pocket. Możesz go stworzyć na swoim koncie Pocket." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'Kanały RSS prowadzone przez wallabag pozwalają Ci na czytanie twoich zapisanych artykułów w twoim ulubionym czytniku RSS. Musisz najpierw wynegenerować tokena.' | 86 | description: 'Kanały RSS prowadzone przez wallabag pozwalają Ci na czytanie twoich zapisanych artykułów w twoim ulubionym czytniku RSS. Musisz najpierw wynegenerować tokena.' |
88 | token_label: 'Token RSS' | 87 | token_label: 'Token RSS' |
89 | no_token: 'Brak tokena' | 88 | no_token: 'Brak tokena' |
90 | token_create: 'Stwórz tokena' | 89 | token_create: 'Stwórz tokena' |
91 | token_reset: 'Zresetuj swojego tokena' | 90 | token_reset: 'Zresetuj swojego tokena' |
92 | rss_links: 'RSS links' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'RSS links' |
93 | feed_link: | ||
94 | unread: 'Nieprzeczytane' | 94 | unread: 'Nieprzeczytane' |
95 | starred: 'Oznaczone gwiazdką' | 95 | starred: 'Oznaczone gwiazdką' |
96 | archive: 'Archiwum' | 96 | archive: 'Archiwum' |
97 | all: 'Wszystkie' | 97 | all: 'Wszystkie' |
98 | rss_limit: 'Link do RSS' | 98 | feed_limit: 'Link do RSS' |
99 | form_user: | 99 | 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" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'Nazwa' | 102 | name_label: 'Nazwa' |
102 | email_label: 'Adres email' | 103 | email_label: 'Adres email' |
103 | twoFactorAuthentication_label: 'Autoryzacja dwuetapowa' | 104 | two_factor: |
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." | 105 | # emailTwoFactor_label: 'Using email (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: 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. |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'edytuj' | 136 | edit_rule_label: 'edytuj' |
128 | rule_label: 'Reguła' | 137 | rule_label: 'Reguła' |
129 | tags_label: 'Tagi' | 138 | tags_label: 'Tagi' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: 'Co oznaczają « reguły tagowania » ?' | 150 | tagging_rules_definition_title: 'Co oznaczają « reguły tagowania » ?' |
@@ -159,6 +177,15 @@ config: | |||
159 | and: 'Jedna reguła I inna' | 177 | 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>' | 178 | 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>' | 179 | 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>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'Tytuł wpisu' | 191 | default_title: 'Tytuł wpisu' |
@@ -237,7 +264,7 @@ entry: | |||
237 | provided_by: 'Dostarczony przez' | 264 | provided_by: 'Dostarczony przez' |
238 | new: | 265 | new: |
239 | page_title: 'Zapisz nowy wpis' | 266 | page_title: 'Zapisz nowy wpis' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.pl' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | delete: "Czy jesteś pewien, że chcesz usunąć ten artykuł?" | 281 | delete: "Czy jesteś pewien, że chcesz usunąć ten artykuł?" |
255 | delete_tag: "Czy jesteś pewien, że chcesz usunąć ten tag, z tego artykułu?" | 282 | delete_tag: "Czy jesteś pewien, że chcesz usunąć ten tag, z tego artykułu?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'O nas' | 290 | page_title: 'O nas' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: 'Konfiguruj aplikację' | 380 | title: 'Konfiguruj aplikację' |
349 | description: 'W celu dopasowania aplikacji do swoich upodobań, zobacz konfigurację aplikacji' | 381 | description: 'W celu dopasowania aplikacji do swoich upodobań, zobacz konfigurację aplikacji' |
350 | language: 'Zmień język i wygląd' | 382 | language: 'Zmień język i wygląd' |
351 | rss: 'Włącz kanały RSS' | 383 | feed: 'Włącz kanały RSS' |
352 | tagging_rules: 'Napisz reguły pozwalające na automatyczne otagowanie twoich artykułów' | 384 | tagging_rules: 'Napisz reguły pozwalające na automatyczne otagowanie twoich artykułów' |
353 | admin: | 385 | admin: |
354 | title: 'Administracja' | 386 | title: 'Administracja' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: '{0} Nie ma tagów.|{1} Jest jeden tag.|]1,Inf[ Są %count% tagi.' | 429 | number_on_the_page: '{0} Nie ma tagów.|{1} Jest jeden tag.|]1,Inf[ Są %count% tagi.' |
398 | see_untagged_entries: 'Zobacz nieotagowane wpisy' | 430 | see_untagged_entries: 'Zobacz nieotagowane wpisy' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | add: 'Dodaj' | 433 | add: 'Dodaj' |
401 | placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.' | 434 | placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.' |
435 | rename: | ||
436 | placeholder: 'Możesz zaktualizować nazwę taga.' | ||
402 | 437 | ||
403 | export: | 438 | export: |
404 | 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>' | 439 | 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>' |
440 | # unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Import' | 443 | page_title: 'Import' |
@@ -429,6 +465,9 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Import > Wallabag v2' | 466 | page_title: 'Import > Wallabag v2' |
431 | description: 'Ten importer, zaimportuje wszystkie twoje artykułu z wallabag v2. Idź do wszystkich artykułów, a następnie na panelu exportu kliknij na "JSON". Otrzymasz plik "All articles.json".' | 467 | description: 'Ten importer, zaimportuje wszystkie twoje artykułu z wallabag v2. Idź do wszystkich artykułów, a następnie na panelu exportu kliknij na "JSON". Otrzymasz plik "All articles.json".' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Import > Readability' | 472 | page_title: 'Import > Readability' |
434 | description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Readability. Na stronie narzędzi (https://www.readability.com/tools/), kliknij na "Export your data" w sekcji "Data Export". Otrzymach email z plikiem JSON (plik nie będzie zawierał rozszerzenia .json).' | 473 | description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Readability. Na stronie narzędzi (https://www.readability.com/tools/), kliknij na "Export your data" w sekcji "Data Export". Otrzymach email z plikiem JSON (plik nie będzie zawierał rozszerzenia .json).' |
@@ -482,6 +521,7 @@ developer: | |||
482 | redirect_uris_label: 'Przekieruj adresy URI' | 521 | redirect_uris_label: 'Przekieruj adresy URI' |
483 | save_label: 'Stwórz nowego klienta' | 522 | save_label: 'Stwórz nowego klienta' |
484 | action_back: 'Cofnij' | 523 | action_back: 'Cofnij' |
524 | # copy_to_clipboard: Copy | ||
485 | client_parameter: | 525 | client_parameter: |
486 | page_title: 'Zarządzanie klientami API > Parametry klienta' | 526 | page_title: 'Zarządzanie klientami API > Parametry klienta' |
487 | page_description: 'Tutaj znajdują się parametry klienta.' | 527 | page_description: 'Tutaj znajdują się parametry klienta.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'Adres email' | 563 | email_label: 'Adres email' |
524 | enabled_label: 'Włączony' | 564 | enabled_label: 'Włączony' |
525 | last_login_label: 'Ostatnie logowanie' | 565 | last_login_label: 'Ostatnie logowanie' |
526 | twofactor_label: Autoryzacja dwuetapowa | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
527 | save: Zapisz | 568 | save: Zapisz |
528 | delete: Usuń | 569 | delete: Usuń |
529 | delete_confirm: Jesteś pewien? | 570 | delete_confirm: Jesteś pewien? |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | create_new_one: Stwórz nowe poświadczenie | 585 | create_new_one: Stwórz nowe poświadczenie |
545 | form: | 586 | form: |
546 | username_label: 'Nazwa użytkownika' | 587 | username_label: 'Nazwa użytkownika' |
547 | host_label: 'Host' | 588 | host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | password_label: 'Hasło' | 589 | password_label: 'Hasło' |
549 | save: Zapisz | 590 | save: Zapisz |
550 | delete: Usuń | 591 | delete: Usuń |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Hasło zaktualizowane' | 602 | password_updated: 'Hasło zaktualizowane' |
562 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." | 603 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." |
563 | user_updated: 'Informacje zaktualizowane' | 604 | user_updated: 'Informacje zaktualizowane' |
564 | rss_updated: 'Informacje RSS zaktualizowane' | 605 | feed_updated: 'Informacje RSS zaktualizowane' |
565 | tagging_rules_updated: 'Reguły tagowania zaktualizowane' | 606 | tagging_rules_updated: 'Reguły tagowania zaktualizowane' |
566 | tagging_rules_deleted: 'Reguła tagowania usunięta' | 607 | tagging_rules_deleted: 'Reguła tagowania usunięta' |
567 | rss_token_updated: 'Token kanału RSS zaktualizowany' | 608 | feed_token_updated: 'Token kanału RSS zaktualizowany' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
568 | annotations_reset: Zresetuj adnotacje | 610 | annotations_reset: Zresetuj adnotacje |
569 | tags_reset: Zresetuj tagi | 611 | tags_reset: Zresetuj tagi |
570 | entries_reset: Zresetuj wpisy | 612 | entries_reset: Zresetuj wpisy |
571 | archived_reset: Zarchiwizowane wpisy usunięte | 613 | archived_reset: Zarchiwizowane wpisy usunięte |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Wpis już został dodany %date%' | 619 | entry_already_saved: 'Wpis już został dodany %date%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Wpis oznaczony gwiazdką' | 627 | entry_starred: 'Wpis oznaczony gwiazdką' |
583 | entry_unstarred: 'Wpis odznaczony gwiazdką' | 628 | entry_unstarred: 'Wpis odznaczony gwiazdką' |
584 | entry_deleted: 'Wpis usunięty' | 629 | entry_deleted: 'Wpis usunięty' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Tag dodany' | 633 | tag_added: 'Tag dodany' |
634 | tag_renamed: 'Nazwa taga zmieniona' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'Nieudany import, prosimy spróbować ponownie.' | 637 | 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 58d2d058..7159569e 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml | |||
@@ -19,24 +19,26 @@ menu: | |||
19 | unread: 'Não lido' | 19 | unread: 'Não lido' |
20 | starred: 'Destacado' | 20 | starred: 'Destacado' |
21 | archive: 'Arquivo' | 21 | archive: 'Arquivo' |
22 | all_articles: 'Todas as entradas' | 22 | all_articles: 'Todos os artigos' |
23 | config: 'Configurações' | 23 | config: 'Configurações' |
24 | tags: 'Tags' | 24 | tags: 'Tags' |
25 | internal_settings: 'Configurações Internas' | 25 | internal_settings: 'Configurações Internas' |
26 | import: 'Importar' | 26 | import: 'Importar' |
27 | howto: 'How to' | 27 | howto: 'Ajuda' |
28 | # developer: 'API clients management' | 28 | developer: 'Gestão dos clientes API' |
29 | logout: 'Sair' | 29 | logout: 'Sair' |
30 | about: 'Sobre' | 30 | about: 'Sobre' |
31 | search: 'Pesquisa' | 31 | search: 'Pesquisa' |
32 | save_link: 'Salvar um link' | 32 | save_link: 'Salvar um link' |
33 | back_to_unread: 'Voltar para os artigos não lidos' | 33 | back_to_unread: 'Voltar para os artigos não lidos' |
34 | users_management: 'Gestão de Usuários' | 34 | users_management: 'Gestão de Usuários' |
35 | # site_credentials: 'Site credentials' | 35 | site_credentials: 'Credenciais do site' |
36 | quickstart: "Começo Rápido" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Adicionar uma nova entrada' | 38 | add_new_entry: 'Adicionar um novo artigo' |
38 | search: 'Pesquisa' | 39 | search: 'Pesquisa' |
39 | filter_entries: 'Filtrar entradas' | 40 | filter_entries: 'Filtrar os artigos' |
41 | random_entry: Ir para um artigo aleatório desta lista | ||
40 | export: 'Exportar' | 42 | export: 'Exportar' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Digite aqui sua pesquisa' | 44 | input_label: 'Digite aqui sua pesquisa' |
@@ -50,14 +52,15 @@ footer: | |||
50 | stats: 'Desde %user_creation% você leu %nb_archives% artigos. Isso é %per_day% por dia!' | 52 | stats: 'Desde %user_creation% você leu %nb_archives% artigos. Isso é %per_day% por dia!' |
51 | 53 | ||
52 | config: | 54 | config: |
53 | page_title: 'Config' | 55 | page_title: 'Configurações' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Configurações' | 57 | settings: 'Configurações' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Informação do Usuário' | 59 | user_info: 'Informação do Usuário' |
58 | password: 'Senha' | 60 | password: 'Senha' |
59 | rules: 'Regras de tags' | 61 | rules: 'Regras de tags' |
60 | new_user: 'Adicionar um usuário' | 62 | new_user: 'Adicionar um usuário' |
63 | reset: 'Reiniciar minha conta' | ||
61 | form: | 64 | form: |
62 | save: 'Salvar' | 65 | save: 'Salvar' |
63 | form_settings: | 66 | form_settings: |
@@ -65,68 +68,83 @@ config: | |||
65 | items_per_page_label: 'Itens por página' | 68 | items_per_page_label: 'Itens por página' |
66 | language_label: 'Idioma' | 69 | language_label: 'Idioma' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'Velocidade de leitura' | 71 | label: 'Velocidade de leitura (palavras por minuto)' |
69 | help_message: 'Você pode usar ferramentas online para estimar sua velocidade de leitura:' | 72 | help_message: 'Você pode usar ferramentas online para estimar sua velocidade de leitura:' |
70 | 100_word: 'Posso ler ~100 palavras por minuto' | ||
71 | 200_word: 'Posso ler ~200 palavras por minuto' | ||
72 | 300_word: 'Posso ler ~300 palavras por minuto' | ||
73 | 400_word: 'Posso ler ~400 palavras por minuto' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | # label: 'Where do you want to be redirected to after marking an article as read?' | 74 | label: 'Para onde você deseja ser redirecionado após marcar um artigo como lido?' |
76 | # redirect_homepage: 'To the homepage' | 75 | redirect_homepage: 'Para a página inicial' |
77 | # redirect_current_page: 'To the current page' | 76 | redirect_current_page: 'Ficar na página atual' |
78 | pocket_consumer_key_label: 'Chave do consumidor do Pocket para importar conteúdo' | 77 | pocket_consumer_key_label: 'Chave do consumidor do Pocket para importar conteúdo' |
79 | # android_configuration: Configure your Android application | 78 | android_configuration: Configure seu aplicativo Android |
80 | # android_instruction: "Touch here to prefill your Android application" | 79 | android_instruction: "Toque aqui para preencher seu aplicativo Android" |
81 | # help_theme: "wallabag is customizable. You can choose your prefered theme here." | 80 | help_theme: "wallabag é personalizável. Você pode escolher o seu tema preferido aqui." |
82 | # help_items_per_page: "You can change the number of articles displayed on each page." | 81 | help_items_per_page: "Você pode alterar o número de artigos exibidos em cada página." |
83 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." | 82 | help_reading_speed: "wallabag calcula um tempo de leitura para cada artigo. Você pode definir aqui, graças a esta lista, se você é um leitor rápido ou lento. O wallabag recalcula o tempo de leitura de cada artigo." |
84 | # help_language: "You can change the language of wallabag interface." | 83 | help_language: "Você pode alterar o idioma da interface de wallabag." |
85 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." | 84 | help_pocket_consumer_key: "Necessário para importação desde Pocket. Você pode creá-lo na sua conta de Pocket." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'Feeds RSS providos pelo wallabag permitem que você leia seus artigos salvos em seu leitor de RSS favorito. Você precisa gerar um token primeiro.' | 86 | description: 'Feeds RSS providos pelo wallabag permitem que você leia seus artigos salvos em seu leitor de RSS favorito. Você precisa gerar um token primeiro.' |
88 | token_label: 'Token RSS' | 87 | token_label: 'Token RSS' |
89 | no_token: 'Nenhum Token' | 88 | no_token: 'Nenhum Token' |
90 | token_create: 'Criar seu token' | 89 | token_create: 'Criar seu token' |
91 | token_reset: 'Gerar novamente seu token' | 90 | token_reset: 'Gerar novamente seu token' |
92 | rss_links: 'Links RSS' | 91 | token_revoke: 'Revocar token' |
93 | rss_link: | 92 | feed_links: 'Links RSS' |
93 | feed_link: | ||
94 | unread: 'Não lido' | 94 | unread: 'Não lido' |
95 | starred: 'Destacado' | 95 | starred: 'Destacado' |
96 | archive: 'Arquivado' | 96 | archive: 'Arquivado' |
97 | # all: 'All' | 97 | all: 'Todos' |
98 | rss_limit: 'Número de itens no feed' | 98 | feed_limit: 'Número de itens no feed' |
99 | form_user: | 99 | 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.' | 100 | two_factor_description: "Ativar a autenticação de dois fatores significa que você vai receber um e-mail com um código OU que você vai precisar usar um aplicativo OTP (como Google Authenticator, Authy ou FreeOTP) para conseguir um código de utilização única em cada nova conexão não confiável. Você não pode escolher as duas opções." |
101 | login_label: 'Nome de usuário (não pode ser mudado)' | ||
101 | name_label: 'Nome' | 102 | name_label: 'Nome' |
102 | email_label: 'E-mail' | 103 | email_label: 'E-mail' |
103 | twoFactorAuthentication_label: 'Autenticação de dois passos' | 104 | two_factor: |
104 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 105 | emailTwoFactor_label: 'Usando e-mail (receber um código por e-mail)' |
106 | googleTwoFactor_label: 'Usando um aplicativo OTP (abra o aplicativo, como Google Authenticator, Authy ou FreeOTP, para conseguir um código de usagem único)' | ||
107 | table_method: Método | ||
108 | table_state: Estado | ||
109 | table_action: Ação | ||
110 | state_enabled: Ativado | ||
111 | state_disabled: Desativado | ||
112 | action_email: Usar e-mail | ||
113 | action_app: Usar aplicação OTP | ||
105 | delete: | 114 | delete: |
106 | # title: Delete my account (a.k.a danger zone) | 115 | title: Apagar minha conta (Zona de perigo) |
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: Se você apaga sua conta, TODOS os seus artigos, TODOS os seus tags, TODAS suas anotações e sua conta serão PERMANENTEMENTE removidos (NÃO pode ser DESFEITO). Depois da operação você será desconectado. |
108 | # confirm: Are you really sure? (THIS CAN'T BE UNDONE) | 117 | confirm: Tem certeza? (ISSO NÃO PODE SER DESFEITO) |
109 | # button: Delete my account | 118 | button: Apagar minha conta |
110 | reset: | 119 | reset: |
111 | # title: Reset area (a.k.a danger zone) | 120 | title: Reiniciar minha conta (Zona de perigo) |
112 | # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE. | 121 | description: Apertando os botões aqui em baixo você poderá remover informações da sua conta. Saiba que eessas ações sao IRREVERSIVEIS. |
113 | # annotations: Remove ALL annotations | 122 | annotations: Remover TODAS as anotações |
114 | # tags: Remove ALL tags | 123 | tags: Remover TODOS os tags |
115 | # entries: Remove ALL entries | 124 | entries: Remover TODOS os artigos |
116 | # archived: Remove ALL archived entries | 125 | archived: Remover TODOS os artigos arquivados |
117 | # confirm: Are you really really sure? (THIS CAN'T BE UNDONE) | 126 | confirm: Tem certeza? (ISSO NÃO PODE SER DESFEITO) |
118 | form_password: | 127 | form_password: |
119 | # description: "You can change your password here. Your new password should by at least 8 characters long." | 128 | description: "Você pode mudar a sua senha aqui. A nova senha deve ter pelo menos 8 caracteres." |
120 | old_password_label: 'Senha atual' | 129 | old_password_label: 'Senha atual' |
121 | new_password_label: 'Nova senha' | 130 | new_password_label: 'Nova senha' |
122 | repeat_new_password_label: 'Repita a nova senha' | 131 | repeat_new_password_label: 'Repita a nova senha' |
123 | form_rules: | 132 | form_rules: |
124 | if_label: 'if' | 133 | if_label: 'se' |
125 | then_tag_as_label: 'então coloque a tag' | 134 | then_tag_as_label: 'então coloque a tag' |
126 | delete_rule_label: 'apagar' | 135 | delete_rule_label: 'apagar' |
127 | edit_rule_label: 'editar' | 136 | edit_rule_label: 'editar' |
128 | rule_label: 'Regras' | 137 | rule_label: 'Regras' |
129 | tags_label: 'Tags' | 138 | tags_label: 'Tags' |
139 | card: | ||
140 | new_tagging_rule: Criar uma regra de tag | ||
141 | import_tagging_rules: Importar regras de tags | ||
142 | import_tagging_rules_detail: Você precisa selecionar o arquivo JSON exportado previamente. | ||
143 | export_tagging_rules: Exportar regras de tags | ||
144 | export_tagging_rules_detail: Isso vai baixar um arquivo JSON que você poderá usar para importar regras de marcação em outro local ou fazer uma cópia de segurança delas. | ||
145 | file_label: Arquivo JSON | ||
146 | import_submit: Importar | ||
147 | export: Exportar | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: 'O que as « regras de tags » significam?' | 150 | tagging_rules_definition_title: 'O que as « regras de tags » significam?' |
@@ -135,18 +153,18 @@ config: | |||
135 | how_to_use_them_description: 'Vamos dizer que você deseja adicionar a tag « <i>leitura rápida</i> » quando o tempo de leitura for menor que 3 minutos.<br />Neste caso, você deve « readingTime <= 3 » no campo <i>Regra</i> e « <i>leitura rápida</i> » no campo <i>Tags</i>.<br />Diversas tags podem ser adicionadas simultâneamente separando-as com vírgula: « <i>leitura rápida, precisa ser lido</i> »<br />Regras complexas podem ser escritas usando os seguintes operadores pré-definidos: if « <i>readingTime >= 5 AND domainName = "github.com"</i> » então adicione a tag « <i>leitura longa, github </i> »' | 153 | how_to_use_them_description: 'Vamos dizer que você deseja adicionar a tag « <i>leitura rápida</i> » quando o tempo de leitura for menor que 3 minutos.<br />Neste caso, você deve « readingTime <= 3 » no campo <i>Regra</i> e « <i>leitura rápida</i> » no campo <i>Tags</i>.<br />Diversas tags podem ser adicionadas simultâneamente separando-as com vírgula: « <i>leitura rápida, precisa ser lido</i> »<br />Regras complexas podem ser escritas usando os seguintes operadores pré-definidos: if « <i>readingTime >= 5 AND domainName = "github.com"</i> » então adicione a tag « <i>leitura longa, github </i> »' |
136 | variables_available_title: 'Quais variáveis e operadores eu posso usar para escrever regras?' | 154 | variables_available_title: 'Quais variáveis e operadores eu posso usar para escrever regras?' |
137 | variables_available_description: 'As seguintes variáveis e operadores podem ser usados para criar regras de tags:' | 155 | variables_available_description: 'As seguintes variáveis e operadores podem ser usados para criar regras de tags:' |
138 | meaning: 'Meaning' | 156 | meaning: 'Significado' |
139 | variable_description: | 157 | variable_description: |
140 | label: 'Variável' | 158 | label: 'Variável' |
141 | title: 'Título da entrada' | 159 | title: 'Título do artigo' |
142 | url: 'URL da entrada' | 160 | url: 'URL do artigo' |
143 | isArchived: 'Se a entrada está arquivada ou não' | 161 | isArchived: 'Se o artigo está arquivado ou não' |
144 | isDestacado: 'Se a entrada está destacada ou não' | 162 | isDestacado: 'Se o artigo está destacado ou não' |
145 | content: 'O conteúdo da entrada' | 163 | content: 'O conteúdo do artigo' |
146 | language: 'O idioma da entrada' | 164 | language: 'O idioma do artigo' |
147 | mimetype: 'O mime-type da entrada' | 165 | mimetype: 'O mime-type do artigo' |
148 | readingTime: 'O tempo estimado de leitura da entrada, em minutos' | 166 | readingTime: 'O tempo estimado de leitura do artigo, em minutos' |
149 | domainName: 'O domínio da entrada' | 167 | domainName: 'O domínio do artigo' |
150 | operator_description: | 168 | operator_description: |
151 | label: 'Operador' | 169 | label: 'Operador' |
152 | less_than: 'Menor que...' | 170 | less_than: 'Menor que...' |
@@ -157,22 +175,31 @@ config: | |||
157 | not_equal_to: 'Diferente de...' | 175 | not_equal_to: 'Diferente de...' |
158 | or: 'Uma regra OU outra' | 176 | or: 'Uma regra OU outra' |
159 | and: 'Uma regra E outra' | 177 | 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>' | 178 | matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>title matches "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>' | 179 | notmatches: 'Testa que um <i>assunto</i> não corresponde a uma <i>search</i> (maiúscula ou minúscula).<br />Exemplo: <code>title notmatches "futebol"</code>' |
180 | otp: | ||
181 | page_title: Autenticação de dois fatores | ||
182 | app: | ||
183 | two_factor_code_description_1: Você acaba de ativar a autenticação de dois fatores com aplicativo OTP, abra seu aplicativo OTP e consegua um código de usagem único. Vai desaparecer ao recargar a página. | ||
184 | two_factor_code_description_2: 'Você pode escanear este código QR com seu aplicativo:' | ||
185 | two_factor_code_description_3: 'Não esqueça de guardar os códigos de segurança em um lugar seguro, você poderá usá-los se você perder o acesso ao seu aplicativo OTP:' | ||
186 | two_factor_code_description_4: 'Teste um código gerado pelo seu aplicativo OTP:' | ||
187 | cancel: Cancelar | ||
188 | enable: Ativar | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'Título da entrada' | 191 | default_title: 'Título do artigo' |
165 | page_titles: | 192 | page_titles: |
166 | unread: 'Entradas não lidas' | 193 | unread: 'Artigos não lidos' |
167 | starred: 'Entradas destacadas' | 194 | starred: 'Artigos destacados' |
168 | archived: 'Entradas arquivadas' | 195 | archived: 'Artigos arquivados' |
169 | filtered: 'Entradas filtradas' | 196 | filtered: 'Artigos filtrados' |
170 | filtered_tags: 'Filtrar por tags:' | 197 | filtered_tags: 'Filtrar por tags:' |
171 | # filtered_search: 'Filtered by search:' | 198 | filtered_search: 'Filtrar por busca:' |
172 | untagged: 'Entradas sem tags' | 199 | untagged: 'Entradas sem tags' |
173 | # all: 'All entries' | 200 | all: 'Todos os artigos' |
174 | list: | 201 | list: |
175 | number_on_the_page: '{0} Não existem entradas.|{1} Existe uma entrada.|]1,Inf[ Existem %count% entradas.' | 202 | number_on_the_page: '{0} Não existem artigos.|{1} Existe um artigo.|]1,Inf[ Existem %count% artigos.' |
176 | reading_time: 'tempo estimado de leitura' | 203 | reading_time: 'tempo estimado de leitura' |
177 | reading_time_minutes: 'tempo estimado de leitura: %readingTime% min' | 204 | reading_time_minutes: 'tempo estimado de leitura: %readingTime% min' |
178 | reading_time_less_one_minute: 'tempo estimado de leitura: < 1 min' | 205 | reading_time_less_one_minute: 'tempo estimado de leitura: < 1 min' |
@@ -190,12 +217,12 @@ entry: | |||
190 | archived_label: 'Arquivado' | 217 | archived_label: 'Arquivado' |
191 | starred_label: 'Destacado' | 218 | starred_label: 'Destacado' |
192 | unread_label: 'Não Lido' | 219 | unread_label: 'Não Lido' |
193 | preview_picture_label: 'Possui uma imagem de preview' | 220 | preview_picture_label: 'Possui uma imagem de pré-visualização' |
194 | preview_picture_help: 'Imagem de preview' | 221 | preview_picture_help: 'Imagem de pré-visualização' |
195 | # is_public_label: 'Has a public link' | 222 | is_public_label: 'Tem um link público' |
196 | # is_public_help: 'Public link' | 223 | is_public_help: 'Link público' |
197 | language_label: 'Idioma' | 224 | language_label: 'Idioma' |
198 | # http_status_label: 'HTTP status' | 225 | http_status_label: 'Código de estado HTTP' |
199 | reading_time: | 226 | reading_time: |
200 | label: 'Tempo de leitura em minutos' | 227 | label: 'Tempo de leitura em minutos' |
201 | from: 'de' | 228 | from: 'de' |
@@ -214,11 +241,11 @@ entry: | |||
214 | back_to_homepage: 'Voltar' | 241 | back_to_homepage: 'Voltar' |
215 | set_as_read: 'Marcar como lido' | 242 | set_as_read: 'Marcar como lido' |
216 | set_as_unread: 'Marcar como não lido' | 243 | set_as_unread: 'Marcar como não lido' |
217 | set_as_starred: 'Alternar destaque' | 244 | set_as_starred: 'Marcar como destacado' |
218 | view_original_article: 'Artigo original' | 245 | view_original_article: 'Artigo original' |
219 | re_fetch_content: 'Recapturar o conteúdo' | 246 | re_fetch_content: 'Recapturar o conteúdo' |
220 | delete: 'Apagar' | 247 | delete: 'Apagar' |
221 | add_a_tag: 'Adicionar uma tag' | 248 | add_a_tag: 'Adicionar um tag' |
222 | share_content: 'Compartilhar' | 249 | share_content: 'Compartilhar' |
223 | share_email_label: 'E-mail' | 250 | share_email_label: 'E-mail' |
224 | public_link: 'link público' | 251 | public_link: 'link público' |
@@ -232,27 +259,32 @@ entry: | |||
232 | original_article: 'original' | 259 | original_article: 'original' |
233 | annotations_on_the_entry: '{0} Sem anotações|{1} Uma anotação|]1,Inf[ %nbAnnotations% anotações' | 260 | annotations_on_the_entry: '{0} Sem anotações|{1} Uma anotação|]1,Inf[ %nbAnnotations% anotações' |
234 | created_at: 'Data de criação' | 261 | created_at: 'Data de criação' |
235 | # published_at: 'Publication date' | 262 | published_at: 'Data de publicação' |
236 | # published_by: 'Published by' | 263 | published_by: 'Publicado por' |
237 | # provided_by: 'Provided by' | 264 | provided_by: 'Fornecido por' |
238 | new: | 265 | new: |
239 | page_title: 'Salvar nova entrada' | 266 | page_title: 'Salvar novo artigo' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.pt' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
244 | # placeholder: 'What are you looking for?' | 271 | placeholder: 'O que você está procurando?' |
245 | edit: | 272 | edit: |
246 | page_title: 'Editar uma entrada' | 273 | page_title: 'Editar um artigo' |
247 | title_label: 'Título' | 274 | title_label: 'Título' |
248 | url_label: 'Url' | 275 | url_label: 'Url' |
249 | # origin_url_label: 'Origin url (from where you found that entry)' | 276 | origin_url_label: 'URL de origem url (onde você encontrou este artigo)' |
250 | save_label: 'Salvar' | 277 | save_label: 'Salvar' |
251 | public: | 278 | public: |
252 | shared_by_wallabag: "Este artigo foi compartilhado pelo <a href='%wallabag_instance%'>wallabag</a>" | 279 | shared_by_wallabag: "Este artigo foi compartilhado pelo <a href='%wallabag_instance%'>wallabag</a>" |
253 | confirm: | 280 | confirm: |
254 | # delete: "Are you sure you want to remove that article?" | 281 | delete: Tem certeza de que deseja remover este artigo?" |
255 | # delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | delete_tag: "Tem certeza de que deseja remover este tag deste artigo?" |
283 | metadata: | ||
284 | reading_time: "Tempo estimado de leitura" | ||
285 | reading_time_minutes_short: "%readingTime% min" | ||
286 | address: "Endereço" | ||
287 | added_on: "Adicionado o" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'Sobre' | 290 | page_title: 'Sobre' |
@@ -274,7 +306,7 @@ about: | |||
274 | bug_reports: 'Informar bugs' | 306 | bug_reports: 'Informar bugs' |
275 | support: '<a href="https://github.com/wallabag/wallabag/issues">no GitHub</a>' | 307 | support: '<a href="https://github.com/wallabag/wallabag/issues">no GitHub</a>' |
276 | helping: | 308 | helping: |
277 | description: 'wallabag é livre e software livre. Você pode nos ajudar:' | 309 | description: 'wallabag é um software livre e gratuito. Você pode nos ajudar:' |
278 | by_contributing: 'contribuindo com o projeto:' | 310 | by_contributing: 'contribuindo com o projeto:' |
279 | by_contributing_2: 'uma lista de todas as nossas necessidades' | 311 | by_contributing_2: 'uma lista de todas as nossas necessidades' |
280 | by_paypal: 'via Paypal' | 312 | by_paypal: 'via Paypal' |
@@ -289,11 +321,11 @@ howto: | |||
289 | page_title: 'How to' | 321 | page_title: 'How to' |
290 | page_description: 'Existem diferentes formas de salvar um artigo:' | 322 | page_description: 'Existem diferentes formas de salvar um artigo:' |
291 | tab_menu: | 323 | tab_menu: |
292 | # add_link: "Add a link" | 324 | add_link: "Adicionar um link" |
293 | # shortcuts: "Use shortcuts" | 325 | shortcuts: "Usar atalhos" |
294 | top_menu: | 326 | top_menu: |
295 | browser_addons: 'Extensões de navegadores' | 327 | browser_addons: 'Extensões de navegadores' |
296 | mobile_apps: "App's móveis" | 328 | mobile_apps: "Aplicativos móveis" |
297 | bookmarklet: 'Bookmarklet' | 329 | bookmarklet: 'Bookmarklet' |
298 | form: | 330 | form: |
299 | description: 'Obrigado por este formulário' | 331 | description: 'Obrigado por este formulário' |
@@ -308,34 +340,34 @@ howto: | |||
308 | ios: 'na iTunes Store' | 340 | ios: 'na iTunes Store' |
309 | windows: 'na Microsoft Store' | 341 | windows: 'na Microsoft Store' |
310 | bookmarklet: | 342 | bookmarklet: |
311 | description: 'Arraste e solve este link na sua barra de favoritos:' | 343 | description: 'Arraste e solte este link na sua barra de favoritos:' |
312 | shortcuts: | 344 | shortcuts: |
313 | # page_description: Here are the shortcuts available in wallabag. | 345 | page_description: Aqui estão os atalhos disponíveis no wallabag. |
314 | # shortcut: Shortcut | 346 | shortcut: Atalho |
315 | # action: Action | 347 | action: Ação |
316 | # all_pages_title: Shortcuts available in all pages | 348 | all_pages_title: Atalhos disponíveis em todas as páginas |
317 | # go_unread: Go to unread | 349 | go_unread: Ir para não lidos |
318 | # go_starred: Go to starred | 350 | go_starred: Ir para favoritos |
319 | # go_archive: Go to archive | 351 | go_archive: Ir para arquivados |
320 | # go_all: Go to all entries | 352 | go_all: Ir a todos os artigos |
321 | # go_tags: Go to tags | 353 | go_tags: Ir para tags |
322 | # go_config: Go to config | 354 | go_config: Ir para configuração |
323 | # go_import: Go to import | 355 | go_import: Ir para importar |
324 | # go_developers: Go to developers | 356 | go_developers: Ir para desenvolvedores |
325 | # go_howto: Go to howto (this page!) | 357 | go_howto: Ir para ajuda (esta página) |
326 | # go_logout: Logout | 358 | go_logout: Ir para sair |
327 | # list_title: Shortcuts available in listing pages | 359 | list_title: Atalhos disponíveis em páginas de listagem |
328 | # search: Display the search form | 360 | search: Exibir o formulário de pesquisa |
329 | # article_title: Shortcuts available in entry view | 361 | article_title: Atalhos disponíveis no artigo |
330 | # open_original: Open original URL of the entry | 362 | open_original: Abrir URL original do artigo |
331 | # toggle_favorite: Toggle star status for the entry | 363 | toggle_favorite: Marcar o artigo como destacado / não destacado |
332 | # toggle_archive: Toggle read status for the entry | 364 | toggle_archive: Marcar artigo como lido / não lido |
333 | # delete: Delete the entry | 365 | delete: Apagar o artigo |
334 | # material_title: Shortcuts available with Material theme only | 366 | material_title: Atalhos disponíveis apenas com o tema Material |
335 | # add_link: Add a new link | 367 | add_link: Adicionar um novo artigo |
336 | # hide_form: Hide the current form (search or new link) | 368 | hide_form: Ocultar o formulário atual (pesquisa ou novo artigo) |
337 | # arrows_navigation: Navigate through articles | 369 | arrows_navigation: Navegar pelo artigos |
338 | # open_article: Display the selected entry | 370 | open_article: Exibir o artigo selecionado |
339 | 371 | ||
340 | quickstart: | 372 | quickstart: |
341 | page_title: 'Começo Rápido' | 373 | page_title: 'Começo Rápido' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | title: 'Configurar a aplicação' | 380 | title: 'Configurar a aplicação' |
349 | description: 'Para ter uma aplicação que atende você, dê uma olhada na configuração do wallabag.' | 381 | description: 'Para ter uma aplicação que atende você, dê uma olhada na configuração do wallabag.' |
350 | language: 'Alterar idioma e design' | 382 | language: 'Alterar idioma e design' |
351 | rss: 'Habilitar feeds RSS' | 383 | feed: 'Habilitar feeds RSS' |
352 | tagging_rules: 'Escrever regras para acrescentar tags automaticamente em seus artigos' | 384 | tagging_rules: 'Escrever regras para acrescentar tags automaticamente em seus artigos' |
353 | admin: | 385 | admin: |
354 | title: 'Administração' | 386 | title: 'Administração' |
@@ -369,8 +401,8 @@ quickstart: | |||
369 | pocket: 'Migrar do Pocket' | 401 | pocket: 'Migrar do Pocket' |
370 | wallabag_v1: 'Migrar do wallabag v1' | 402 | wallabag_v1: 'Migrar do wallabag v1' |
371 | wallabag_v2: 'Migrar do wallabag v2' | 403 | wallabag_v2: 'Migrar do wallabag v2' |
372 | readability: 'Migrate from Readability' | 404 | readability: 'Migrar do Readability' |
373 | instapaper: 'Migrate from Instapaper' | 405 | instapaper: 'Migrar do Instapaper' |
374 | developer: | 406 | developer: |
375 | title: 'Desenvolvedores' | 407 | title: 'Desenvolvedores' |
376 | description: 'Nós também agradecemos os desenvolvedores: Docker, API, traduções, etc.' | 408 | description: 'Nós também agradecemos os desenvolvedores: Docker, API, traduções, etc.' |
@@ -381,7 +413,7 @@ quickstart: | |||
381 | description: "Existem muitas funcionalidades no wallabag. Não hesite em ler o manual para conhecê-las e aprender como usá-las." | 413 | description: "Existem muitas funcionalidades no wallabag. Não hesite em ler o manual para conhecê-las e aprender como usá-las." |
382 | annotate: 'Anotar seu artigo' | 414 | annotate: 'Anotar seu artigo' |
383 | export: 'Converter seu artigo em ePUB ou PDF' | 415 | export: 'Converter seu artigo em ePUB ou PDF' |
384 | search_filters: 'veja coo você pode encontrar um artigo usanndo o motor de busca e filtros' | 416 | search_filters: 'veja como você pode encontrar um artigo usando o motor de busca e filtros' |
385 | fetching_errors: 'O que eu posso fazer quando um artigo encontra erros na recuperação?' | 417 | fetching_errors: 'O que eu posso fazer quando um artigo encontra erros na recuperação?' |
386 | all_docs: 'E outros muitos artigos!' | 418 | all_docs: 'E outros muitos artigos!' |
387 | support: | 419 | support: |
@@ -396,21 +428,25 @@ tag: | |||
396 | list: | 428 | list: |
397 | number_on_the_page: '{0} Não existem tags.|{1} Uma tag.|]1,Inf[ Existem %count% tags.' | 429 | number_on_the_page: '{0} Não existem tags.|{1} Uma tag.|]1,Inf[ Existem %count% tags.' |
398 | see_untagged_entries: 'Ver entradas sem tags' | 430 | see_untagged_entries: 'Ver entradas sem tags' |
431 | no_untagged_entries: 'Não há entradas sem tags.' | ||
399 | new: | 432 | new: |
400 | # add: 'Add' | 433 | add: 'Adicionar' |
401 | # placeholder: 'You can add several tags, separated by a comma.' | 434 | placeholder: 'Você pode adicionar varios tags, separados por vírgulas.' |
435 | rename: | ||
436 | placeholder: 'Você pode atualizar o nome do tag.' | ||
402 | 437 | ||
403 | # export: | 438 | export: |
404 | # 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>' | 439 | footer_template: '<div style="text-align:center;"><p>Producido por wallabag com %method%</p><p>Por favor abra <a href="https://github.com/wallabag/wallabag/issues">um bolheto</a> se você tiver problemas com a exibição deste E-Book no seu dispositivo.</p></div>' |
440 | unknown: 'Desconhecido' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | page_title: 'Importar' | 443 | page_title: 'Importar' |
408 | page_description: 'Bem-vindo ao importador do wallabag. Por favo selecione o serviço do qual deseja migrar.' | 444 | page_description: 'Bem-vindo ao importador do wallabag. Por favor selecione o serviço do qual deseja migrar.' |
409 | action: | 445 | action: |
410 | import_contents: 'Importar conteúdos' | 446 | import_contents: 'Importar conteúdos' |
411 | form: | 447 | form: |
412 | mark_as_read_title: 'Marcar todos como lidos?' | 448 | mark_as_read_title: 'Marcar todos como lidos?' |
413 | mark_as_read_label: 'Marcar todas as entradas importadas como lidas' | 449 | mark_as_read_label: 'Marcar todos os artigos importados como lidos' |
414 | file_label: 'Arquivo' | 450 | file_label: 'Arquivo' |
415 | save_label: 'Carregar arquivo' | 451 | save_label: 'Carregar arquivo' |
416 | pocket: | 452 | pocket: |
@@ -429,13 +465,16 @@ import: | |||
429 | wallabag_v2: | 465 | wallabag_v2: |
430 | page_title: 'Importar > Wallabag v2' | 466 | page_title: 'Importar > Wallabag v2' |
431 | description: 'Com este importador você importa todos os seus artigos do wallabag v2. Vá em Todos os artigos e então, na barra lateral de exportação, clique em "JSON". Você irá criar um arquivo "All articles.json".' | 467 | description: 'Com este importador você importa todos os seus artigos do wallabag v2. Vá em Todos os artigos e então, na barra lateral de exportação, clique em "JSON". Você irá criar um arquivo "All articles.json".' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | readability: | 471 | readability: |
433 | page_title: 'Importar > Readability' | 472 | page_title: 'Importar > Readability' |
434 | description: 'Este importador pode importar todos os artigos do Readability. Nas página ferramentas (https://www.readability.com/tools/), clique em "Export your data" na seção "Data Export". Você receberá um e-mail para fazer o download de um json (que de fato não termina com .json).' | 473 | description: 'Este importador pode importar todos os artigos do Readability. Nas página ferramentas (https://www.readability.com/tools/), clique em "Export your data" na seção "Data Export". Você receberá um e-mail para fazer o download de um json (que de fato não termina com .json).' |
435 | how_to: 'Por favor, selecione sua exportação do Readability e clique no botão abaixo para importá-la.' | 474 | how_to: 'Por favor, selecione sua exportação do Readability e clique no botão abaixo para importá-la.' |
436 | worker: | 475 | worker: |
437 | enabled: "A importação é feita assíncronamente. Uma vez que a tarefa de importação é iniciada, um trabalho externo pode executar tarefas uma por vez. O serviço atual é:" | 476 | enabled: "A importação é feita assíncronamente. Uma vez que a tarefa de importação é iniciada, um trabalho externo pode executar tarefas uma por vez. O serviço atual é:" |
438 | # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors." | 477 | download_images_warning: "Você ativou o donwload de imagens para os seus artigos. Combinado com a importação clásica isso pode demorar muito tempo (ou mesmo falhar). Nós <strong>recomendamos fortemente</strong> que você ative a importação assíncrona para evitar erros." |
439 | firefox: | 478 | firefox: |
440 | page_title: 'Importar > Firefox' | 479 | page_title: 'Importar > Firefox' |
441 | description: "Com este importador você importa todos os favoritos de seu Firefox. Somente vá até seus favoritos (Ctrl+Maj+O), e em \"Importar e Backup\" e escolha \"Backup...\". Você terá então um arquivo .json." | 480 | description: "Com este importador você importa todos os favoritos de seu Firefox. Somente vá até seus favoritos (Ctrl+Maj+O), e em \"Importar e Backup\" e escolha \"Backup...\". Você terá então um arquivo .json." |
@@ -449,12 +488,12 @@ import: | |||
449 | description: 'Este importador pode importar todos os artigos do seu Instapaper. Nas página de configurações (https://www.instapaper.com/user), clique em "Download .CSV file" na seção "Export". Um arquivo CSV será baixado (algo como "instapaper-export.csv").' | 488 | description: 'Este importador pode importar todos os artigos do seu Instapaper. Nas página de configurações (https://www.instapaper.com/user), clique em "Download .CSV file" na seção "Export". Um arquivo CSV será baixado (algo como "instapaper-export.csv").' |
450 | how_to: 'Por favor, selecione sua exportação do seu Instapaper e clique no botão abaixo para importá-la.' | 489 | how_to: 'Por favor, selecione sua exportação do seu Instapaper e clique no botão abaixo para importá-la.' |
451 | pinboard: | 490 | pinboard: |
452 | # page_title: "Import > Pinboard" | 491 | page_title: "Importar > Pinboard" |
453 | # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").' | 492 | description: 'Este importador pode importar todos os artigos do seu Pinboard. Na página de cópia de segurança (https://pinboard.in/settings/backup), clique em "JSON" na seção "Bookmarks". Um arquivo JSON será baixado (algo como "pinboard_export").' |
454 | # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.' | 493 | how_to: 'Por favor selecione a sua exportação Pinboard e clique no botão em baixo para carregá-lo e importá-lo.' |
455 | 494 | ||
456 | developer: | 495 | developer: |
457 | # page_title: 'API clients management' | 496 | page_title: 'Gestão dos clientes API' |
458 | welcome_message: 'Bem-vindo a API do wallabag' | 497 | welcome_message: 'Bem-vindo a API do wallabag' |
459 | documentation: 'Documentação' | 498 | documentation: 'Documentação' |
460 | how_to_first_app: 'Como criar minha primeira aplicação' | 499 | how_to_first_app: 'Como criar minha primeira aplicação' |
@@ -475,23 +514,24 @@ developer: | |||
475 | warn_message_2: 'Se você remover isso, todo o aplicativo configurado com este cliente não poderá se autenticar no seu wallabag.' | 514 | warn_message_2: 'Se você remover isso, todo o aplicativo configurado com este cliente não poderá se autenticar no seu wallabag.' |
476 | action: 'Remover este cliente' | 515 | action: 'Remover este cliente' |
477 | client: | 516 | client: |
478 | # page_title: 'API clients management > Novo cliente' | 517 | page_title: 'Gestão de clientes API > Novo cliente' |
479 | page_description: 'Você está prestes a criar um novo cliente. Por favor preencha o campo abaixo para a URI de redirecionamento de sua aplicação.' | 518 | page_description: 'Você está prestes a criar um novo cliente. Por favor preencha o campo abaixo para a URI de redirecionamento de sua aplicação.' |
480 | form: | 519 | form: |
481 | name_label: 'Nome do cliente' | 520 | name_label: 'Nome do cliente' |
482 | redirect_uris_label: 'URIs de redirecionamento' | 521 | redirect_uris_label: 'URIs de redirecionamento' |
483 | save_label: 'Criar um novo cliente' | 522 | save_label: 'Criar um novo cliente' |
484 | action_back: 'Voltar' | 523 | action_back: 'Voltar' |
524 | copy_to_clipboard: Copiar | ||
485 | client_parameter: | 525 | client_parameter: |
486 | # page_title: 'API clients management > Parâmetros de clientes' | 526 | page_title: 'Gestão de clientes API > Parâmetros de clientes' |
487 | page_description: 'Aqui estão os parâmetros de seus clientes.' | 527 | page_description: 'Aqui estão os parâmetros de seus clientes.' |
488 | field_name: 'Nome do cliente' | 528 | field_name: 'Nome do cliente' |
489 | field_id: 'ID do cliente' | 529 | field_id: 'ID do cliente' |
490 | field_secret: 'Chave do cliente' | 530 | field_secret: 'Chave do cliente' |
491 | back: 'Voltar' | 531 | back: 'Voltar' |
492 | read_howto: 'Leia o how-to "Criar minha primeira aplicação"' | 532 | read_howto: 'Leia o guia "Criar minha primeira aplicação"' |
493 | howto: | 533 | howto: |
494 | # page_title: 'API clients management > Criar minha primeira aplicação' | 534 | page_title: 'Gestão de clientes API > Criar minha primeira aplicação' |
495 | description: | 535 | description: |
496 | paragraph_1: 'Os seguintes comandos fazem uso da <a href="https://github.com/jkbrzt/httpie">biblioteca HTTPie</a>. Tenha certeza que ela está instalada em seu servidor antes de usá-la.' | 536 | paragraph_1: 'Os seguintes comandos fazem uso da <a href="https://github.com/jkbrzt/httpie">biblioteca HTTPie</a>. Tenha certeza que ela está instalada em seu servidor antes de usá-la.' |
497 | paragraph_2: 'Você precisa de um token para a comunicação entre sua aplicação terceira e a API do wallabag.' | 537 | paragraph_2: 'Você precisa de um token para a comunicação entre sua aplicação terceira e a API do wallabag.' |
@@ -523,36 +563,37 @@ user: | |||
523 | email_label: 'E-mail' | 563 | email_label: 'E-mail' |
524 | enabled_label: 'Habilitado' | 564 | enabled_label: 'Habilitado' |
525 | last_login_label: 'Último login' | 565 | last_login_label: 'Último login' |
526 | twofactor_label: 'Autenticação de dois passos' | 566 | twofactor_email_label: Autenticação de dois fatores por e-mail |
567 | twofactor_google_label: Autenticação de dois fatores por aplicativo OTP | ||
527 | save: 'Salvar' | 568 | save: 'Salvar' |
528 | delete: 'Apagar' | 569 | delete: 'Apagar' |
529 | delete_confirm: 'Tem certeza?' | 570 | delete_confirm: 'Tem certeza?' |
530 | back_to_list: 'Voltar para a lista' | 571 | back_to_list: 'Voltar para a lista' |
531 | search: | 572 | search: |
532 | # placeholder: Filter by username or email | 573 | placeholder: Filtrar por nome de usuário ou e-mail |
533 | 574 | ||
534 | site_credential: | 575 | site_credential: |
535 | # page_title: Site credentials management | 576 | page_title: Gerenciamento de credenciais do site |
536 | # new_site_credential: Create a credential | 577 | new_site_credential: Criar uma credencial |
537 | # edit_site_credential: Edit an existing credential | 578 | edit_site_credential: Editar uma credencial existente |
538 | # description: "Here you can manage all credentials for sites which required them (create, edit and delete), like a paywall, an authentication, etc." | 579 | description: "Aqui você pode gerenciar todas as credenciais para os sites que precisam delas (criar, editar e apagar), como um paywall, uma autenticação, etc." |
539 | list: | 580 | list: |
540 | actions: 'Ações' | 581 | actions: 'Ações' |
541 | edit_action: 'Editar' | 582 | edit_action: 'Editar' |
542 | yes: 'Sim' | 583 | yes: 'Sim' |
543 | no: 'Não' | 584 | no: 'Não' |
544 | # create_new_one: Create a new credential | 585 | create_new_one: Criar uma nova credencial |
545 | form: | 586 | form: |
546 | # username_label: 'Username' | 587 | username_label: 'Nome de usuário' |
547 | # host_label: 'Host' | 588 | host_label: 'Host (subdominio.exemplo.org, .exemplo.org, etc.)' |
548 | # password_label: 'Password' | 589 | password_label: 'Senha' |
549 | save: 'Salvar' | 590 | save: 'Salvar' |
550 | delete: 'Apagar' | 591 | delete: 'Apagar' |
551 | delete_confirm: 'Tem certeza?' | 592 | delete_confirm: 'Tem certeza?' |
552 | back_to_list: 'Voltar para a lista' | 593 | back_to_list: 'Voltar para a lista' |
553 | 594 | ||
554 | error: | 595 | error: |
555 | # page_title: An error occurred | 596 | page_title: Um erro ocorreu |
556 | 597 | ||
557 | flashes: | 598 | flashes: |
558 | config: | 599 | config: |
@@ -560,31 +601,37 @@ flashes: | |||
560 | config_saved: 'Configiração salva.' | 601 | config_saved: 'Configiração salva.' |
561 | password_updated: 'Senha atualizada' | 602 | password_updated: 'Senha atualizada' |
562 | password_not_updated_demo: 'Em modo de demonstração, você não pode alterar a senha deste usuário.' | 603 | password_not_updated_demo: 'Em modo de demonstração, você não pode alterar a senha deste usuário.' |
563 | # user_updated: 'Information updated' | 604 | user_updated: 'Informação atualizada' |
564 | rss_updated: 'Informação de RSS atualizada' | 605 | feed_updated: 'Informação de RSS atualizada' |
565 | tagging_rules_updated: 'Regras de tags atualizadas' | 606 | tagging_rules_updated: 'Regras de tags atualizadas' |
566 | tagging_rules_deleted: 'Regra de tag apagada' | 607 | tagging_rules_deleted: 'Regra de tag apagada' |
567 | rss_token_updated: 'Token RSS atualizado' | 608 | feed_token_updated: 'Token RSS atualizado' |
568 | # annotations_reset: Annotations reset | 609 | feed_token_revoked: 'Token RSS revogado' |
569 | # tags_reset: Tags reset | 610 | annotations_reset: Anotações reinicializadas |
570 | # entries_reset: Entries reset | 611 | tags_reset: Tags reinicializados |
571 | # archived_reset: Archived entries deleted | 612 | entries_reset: Artigos reinicializados |
613 | archived_reset: Artigos arquivados apagados | ||
614 | otp_enabled: Autenticação de dois fatores ativada | ||
615 | tagging_rules_imported: Regras de tags importadas | ||
616 | tagging_rules_not_imported: Erro ao importar regras de tags | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | entry_already_saved: 'Entrada já foi salva em %date%' | 619 | entry_already_saved: 'Artigo já foi salvo em %date%' |
575 | entry_saved: 'Entrada salva' | 620 | entry_saved: 'Artigo salvo' |
576 | entry_saved_failed: 'Failed to save entry' | 621 | entry_saved_failed: 'Artigo salvo mas falha na recuperação do conteúdo' |
577 | entry_updated: 'Entrada atualizada' | 622 | entry_updated: 'Artigo atualizado' |
578 | entry_reloaded: 'Entrada recarregada' | 623 | entry_reloaded: 'Artigo recarregado' |
579 | entry_reloaded_failed: 'Falha em recarregar a entrada' | 624 | entry_reloaded_failed: 'Artigo em recarregar o artigo' |
580 | entry_archived: 'Entrada arquivada' | 625 | entry_archived: 'Artigo arquivado' |
581 | entry_unarchived: 'Entrada desarquivada' | 626 | entry_unarchived: 'Artigo desarquivado' |
582 | entry_starred: 'Entrada destacada' | 627 | entry_starred: 'Artigo destacado' |
583 | entry_unstarred: 'Entrada não destacada' | 628 | entry_unstarred: 'Artigo não destacado' |
584 | entry_deleted: 'Entrada apagada' | 629 | entry_deleted: 'Artigo apagado' |
630 | no_random_entry: 'Nehum artigo com esses criterios foi encontrado' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | tag_added: 'Tag adicionada' | 633 | tag_added: 'Tag adicionada' |
634 | tag_renamed: 'Tag renomeado' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | failed: 'Importação falhou, por favor tente novamente.' | 637 | failed: 'Importação falhou, por favor tente novamente.' |
@@ -605,6 +652,6 @@ flashes: | |||
605 | deleted: 'Usuário "%username%" removido' | 652 | deleted: 'Usuário "%username%" removido' |
606 | site_credential: | 653 | site_credential: |
607 | notice: | 654 | notice: |
608 | # added: 'Site credential for "%host%" added' | 655 | added: 'Credencial do site para "%host%" foi adicionada' |
609 | # updated: 'Site credential for "%host%" updated' | 656 | updated: 'Credencial do site pa "%host%" atualizada' |
610 | # deleted: 'Site credential for "%host%" deleted' | 657 | deleted: 'Credencial do site pa "%host%" removida' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml index 564fed94..f671da8d 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Înapoi la articolele necitite' | 33 | back_to_unread: 'Înapoi la articolele necitite' |
34 | # users_management: 'Users management' | 34 | # users_management: 'Users management' |
35 | # site_credentials: 'Site credentials' | 35 | # site_credentials: 'Site credentials' |
36 | # quickstart: "Quickstart" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Introdu un nou articol' | 38 | add_new_entry: 'Introdu un nou articol' |
38 | search: 'Căutare' | 39 | search: 'Căutare' |
39 | filter_entries: 'Filtrează articolele' | 40 | filter_entries: 'Filtrează articolele' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | # export: 'Export' | 42 | # export: 'Export' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Introdu căutarea ta' | 44 | input_label: 'Introdu căutarea ta' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Configurație' | 55 | page_title: 'Configurație' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Setări' | 57 | settings: 'Setări' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Informații despre utilizator' | 59 | user_info: 'Informații despre utilizator' |
58 | password: 'Parolă' | 60 | password: 'Parolă' |
59 | # rules: 'Tagging rules' | 61 | # rules: 'Tagging rules' |
60 | new_user: 'Crează un utilizator' | 62 | new_user: 'Crează un utilizator' |
63 | # reset: 'Reset area' | ||
61 | form: | 64 | form: |
62 | save: 'Salvează' | 65 | save: 'Salvează' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Articole pe pagină' | 68 | items_per_page_label: 'Articole pe pagină' |
66 | language_label: 'Limbă' | 69 | language_label: 'Limbă' |
67 | reading_speed: | 70 | reading_speed: |
68 | # label: 'Reading speed' | 71 | # label: 'Reading speed (words per minute)' |
69 | # help_message: 'You can use online tools to estimate your reading speed:' | 72 | # help_message: 'You can use online tools to estimate your reading speed:' |
70 | # 100_word: 'I read ~100 words per minute' | ||
71 | # 200_word: 'I read ~200 words per minute' | ||
72 | # 300_word: 'I read ~300 words per minute' | ||
73 | # 400_word: 'I read ~400 words per minute' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | # label: 'Where do you want to be redirected to after marking an article as read?' | 74 | # label: 'Where do you want to be redirected to after marking an article as read?' |
76 | # redirect_homepage: 'To the homepage' | 75 | # redirect_homepage: 'To the homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." | 82 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." |
84 | # help_language: "You can change the language of wallabag interface." | 83 | # help_language: "You can change the language of wallabag interface." |
85 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." | 84 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'Feed-urile RSS oferite de wallabag îți permit să-ți citești articolele salvate în reader-ul tău preferat RSS.' | 86 | description: 'Feed-urile RSS oferite de wallabag îți permit să-ți citești articolele salvate în reader-ul tău preferat RSS.' |
88 | token_label: 'RSS-Token' | 87 | token_label: 'RSS-Token' |
89 | no_token: 'Fără token' | 88 | no_token: 'Fără token' |
90 | token_create: 'Crează-ți token' | 89 | token_create: 'Crează-ți token' |
91 | token_reset: 'Resetează-ți token-ul' | 90 | token_reset: 'Resetează-ți token-ul' |
92 | rss_links: 'Link-uri RSS' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'Link-uri RSS' |
93 | feed_link: | ||
94 | unread: 'Unread' | 94 | unread: 'Unread' |
95 | starred: 'Starred' | 95 | starred: 'Starred' |
96 | archive: 'Archived' | 96 | archive: 'Archived' |
97 | # all: 'All' | 97 | # all: 'All' |
98 | rss_limit: 'Limită RSS' | 98 | feed_limit: 'Limită RSS' |
99 | form_user: | 99 | form_user: |
100 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'Nume' | 102 | name_label: 'Nume' |
102 | email_label: 'E-mail' | 103 | email_label: 'E-mail' |
103 | # twoFactorAuthentication_label: 'Two factor authentication' | 104 | two_factor: |
104 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 105 | # emailTwoFactor_label: 'Using email (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. |
@@ -127,6 +136,15 @@ config: | |||
127 | # edit_rule_label: 'edit' | 136 | # edit_rule_label: 'edit' |
128 | # rule_label: 'Rule' | 137 | # rule_label: 'Rule' |
129 | # tags_label: 'Tags' | 138 | # tags_label: 'Tags' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | # faq: | 148 | # faq: |
131 | # title: 'FAQ' | 149 | # title: 'FAQ' |
132 | # tagging_rules_definition_title: 'What does « tagging rules » mean?' | 150 | # tagging_rules_definition_title: 'What does « tagging rules » mean?' |
@@ -159,6 +177,15 @@ config: | |||
159 | # and: 'One rule AND another' | 177 | # 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>' | 178 | # 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>' | 179 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | # default_title: 'Title of the entry' | 191 | # default_title: 'Title of the entry' |
@@ -237,7 +264,7 @@ entry: | |||
237 | # provided_by: 'Provided by' | 264 | # provided_by: 'Provided by' |
238 | new: | 265 | new: |
239 | page_title: 'Salvează un nou articol' | 266 | page_title: 'Salvează un nou articol' |
240 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.ro' |
241 | form_new: | 268 | form_new: |
242 | url_label: Url | 269 | url_label: Url |
243 | search: | 270 | search: |
@@ -253,6 +280,11 @@ entry: | |||
253 | confirm: | 280 | confirm: |
254 | # delete: "Are you sure you want to remove that article?" | 281 | # delete: "Are you sure you want to remove that article?" |
255 | # delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | # delete_tag: "Are you sure you want to remove that tag from that article?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
256 | 288 | ||
257 | about: | 289 | about: |
258 | page_title: 'Despre' | 290 | page_title: 'Despre' |
@@ -348,7 +380,7 @@ quickstart: | |||
348 | # title: 'Configure the application' | 380 | # title: 'Configure the application' |
349 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' | 381 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' |
350 | # language: 'Change language and design' | 382 | # language: 'Change language and design' |
351 | # rss: 'Enable RSS feeds' | 383 | # feed: 'Enable RSS feeds' |
352 | # tagging_rules: 'Write rules to automatically tag your articles' | 384 | # tagging_rules: 'Write rules to automatically tag your articles' |
353 | # admin: | 385 | # admin: |
354 | # title: 'Administration' | 386 | # title: 'Administration' |
@@ -396,12 +428,16 @@ tag: | |||
396 | list: | 428 | list: |
397 | # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' | 429 | # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' |
398 | # see_untagged_entries: 'See untagged entries' | 430 | # see_untagged_entries: 'See untagged entries' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
399 | new: | 432 | new: |
400 | # add: 'Add' | 433 | # add: 'Add' |
401 | # placeholder: 'You can add several tags, separated by a comma.' | 434 | # placeholder: 'You can add several tags, separated by a comma.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
402 | 437 | ||
403 | # export: | 438 | export: |
404 | # 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>' | 439 | # 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>' |
440 | # unknown: 'Unknown' | ||
405 | 441 | ||
406 | import: | 442 | import: |
407 | # page_title: 'Import' | 443 | # page_title: 'Import' |
@@ -429,6 +465,9 @@ import: | |||
429 | # wallabag_v2: | 465 | # wallabag_v2: |
430 | # page_title: 'Import > Wallabag v2' | 466 | # page_title: 'Import > Wallabag v2' |
431 | # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' | 467 | # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
432 | # readability: | 471 | # readability: |
433 | # page_title: 'Import > Readability' | 472 | # page_title: 'Import > Readability' |
434 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' | 473 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' |
@@ -482,6 +521,7 @@ developer: | |||
482 | # redirect_uris_label: 'Redirect URIs' | 521 | # redirect_uris_label: 'Redirect URIs' |
483 | # save_label: 'Create a new client' | 522 | # save_label: 'Create a new client' |
484 | # action_back: 'Back' | 523 | # action_back: 'Back' |
524 | # copy_to_clipboard: Copy | ||
485 | # client_parameter: | 525 | # client_parameter: |
486 | # page_title: 'API clients management > Client parameters' | 526 | # page_title: 'API clients management > Client parameters' |
487 | # page_description: 'Here are your client parameters.' | 527 | # page_description: 'Here are your client parameters.' |
@@ -523,7 +563,8 @@ user: | |||
523 | email_label: 'E-mail' | 563 | email_label: 'E-mail' |
524 | # enabled_label: 'Enabled' | 564 | # enabled_label: 'Enabled' |
525 | # last_login_label: 'Last login' | 565 | # last_login_label: 'Last login' |
526 | # twofactor_label: Two factor authentication | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
527 | # save: Save | 568 | # save: Save |
528 | # delete: Delete | 569 | # delete: Delete |
529 | # delete_confirm: Are you sure? | 570 | # delete_confirm: Are you sure? |
@@ -544,7 +585,7 @@ site_credential: | |||
544 | # create_new_one: Create a new credential | 585 | # create_new_one: Create a new credential |
545 | # form: | 586 | # form: |
546 | # username_label: 'Username' | 587 | # username_label: 'Username' |
547 | # host_label: 'Host' | 588 | # host_label: 'Host (subdomain.example.org, .example.org, etc.)' |
548 | # password_label: 'Password' | 589 | # password_label: 'Password' |
549 | # save: Save | 590 | # save: Save |
550 | # delete: Delete | 591 | # delete: Delete |
@@ -561,14 +602,18 @@ flashes: | |||
561 | password_updated: 'Parolă actualizată' | 602 | password_updated: 'Parolă actualizată' |
562 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." | 603 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." |
563 | user_updated: 'Informație actualizată' | 604 | user_updated: 'Informație actualizată' |
564 | rss_updated: 'Informație RSS actualizată' | 605 | feed_updated: 'Informație RSS actualizată' |
565 | # tagging_rules_updated: 'Tagging rules updated' | 606 | # tagging_rules_updated: 'Tagging rules updated' |
566 | # tagging_rules_deleted: 'Tagging rule deleted' | 607 | # tagging_rules_deleted: 'Tagging rule deleted' |
567 | # rss_token_updated: 'RSS token updated' | 608 | # feed_token_updated: 'RSS token updated' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
568 | # annotations_reset: Annotations reset | 610 | # annotations_reset: Annotations reset |
569 | # tags_reset: Tags reset | 611 | # tags_reset: Tags reset |
570 | # entries_reset: Entries reset | 612 | # entries_reset: Entries reset |
571 | # archived_reset: Archived entries deleted | 613 | # archived_reset: Archived entries deleted |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
572 | entry: | 617 | entry: |
573 | notice: | 618 | notice: |
574 | # entry_already_saved: 'Entry already saved on %date%' | 619 | # entry_already_saved: 'Entry already saved on %date%' |
@@ -582,9 +627,11 @@ flashes: | |||
582 | entry_starred: 'Articol adăugat la favorite' | 627 | entry_starred: 'Articol adăugat la favorite' |
583 | entry_unstarred: 'Articol șters de la favorite' | 628 | entry_unstarred: 'Articol șters de la favorite' |
584 | entry_deleted: 'Articol șters' | 629 | entry_deleted: 'Articol șters' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
585 | tag: | 631 | tag: |
586 | notice: | 632 | notice: |
587 | # tag_added: 'Tag added' | 633 | # tag_added: 'Tag added' |
634 | # tag_renamed: 'Tag renamed' | ||
588 | import: | 635 | import: |
589 | notice: | 636 | notice: |
590 | # failed: 'Import failed, please try again.' | 637 | # 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 5f210c93..7d45df1c 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml | |||
@@ -32,10 +32,13 @@ menu: | |||
32 | save_link: 'Сохранить ссылку' | 32 | save_link: 'Сохранить ссылку' |
33 | back_to_unread: 'Назад к непрочитанным записям' | 33 | back_to_unread: 'Назад к непрочитанным записям' |
34 | users_management: 'Управление пользователями' | 34 | users_management: 'Управление пользователями' |
35 | site_credentials: 'Site credentials' | ||
36 | quickstart: "Быстрый старт" | ||
35 | top: | 37 | top: |
36 | add_new_entry: 'Добавить новую запись' | 38 | add_new_entry: 'Добавить новую запись' |
37 | search: 'Поиск' | 39 | search: 'Поиск' |
38 | filter_entries: 'Фильтр записей' | 40 | filter_entries: 'Фильтр записей' |
41 | # random_entry: Jump to a random entry from that list | ||
39 | export: 'Экспорт' | 42 | export: 'Экспорт' |
40 | search_form: | 43 | search_form: |
41 | input_label: 'Введите текст для поиска' | 44 | input_label: 'Введите текст для поиска' |
@@ -52,11 +55,12 @@ config: | |||
52 | page_title: 'Настройки' | 55 | page_title: 'Настройки' |
53 | tab_menu: | 56 | tab_menu: |
54 | settings: 'Настройки' | 57 | settings: 'Настройки' |
55 | rss: 'RSS' | 58 | feed: 'RSS' |
56 | user_info: 'Информация о пользователе' | 59 | user_info: 'Информация о пользователе' |
57 | password: 'Пароль' | 60 | password: 'Пароль' |
58 | rules: 'Правила настройки простановки тегов' | 61 | rules: 'Правила настройки простановки тегов' |
59 | new_user: 'Добавить пользователя' | 62 | new_user: 'Добавить пользователя' |
63 | reset: 'Сброс данных' | ||
60 | form: | 64 | form: |
61 | save: 'Сохранить' | 65 | save: 'Сохранить' |
62 | form_settings: | 66 | form_settings: |
@@ -64,41 +68,49 @@ config: | |||
64 | items_per_page_label: 'Записей на странице' | 68 | items_per_page_label: 'Записей на странице' |
65 | language_label: 'Язык' | 69 | language_label: 'Язык' |
66 | reading_speed: | 70 | reading_speed: |
67 | label: 'Скорость чтения' | 71 | label: 'Скорость чтения (слов в минуту)' |
68 | help_message: 'Вы можете использовать онлайн-инструменты для оценки скорости чтения:' | 72 | help_message: 'Вы можете использовать онлайн-инструменты для оценки скорости чтения:' |
69 | 100_word: 'Я читаю ~100 слов в минуту' | ||
70 | 200_word: 'Я читаю ~200 слов в минуту' | ||
71 | 300_word: 'Я читаю ~300 слов в минуту' | ||
72 | 400_word: 'Я читаю ~400 слов в минуту' | ||
73 | action_mark_as_read: | 73 | action_mark_as_read: |
74 | label: 'Куда Вы хотите быть перенаправлены, после пометки записи, как прочитанная?' | 74 | label: 'Куда Вы хотите быть перенаправлены, после пометки записи, как прочитанная?' |
75 | redirect_homepage: 'На домашнюю страницу' | 75 | redirect_homepage: 'На домашнюю страницу' |
76 | redirect_current_page: 'На текущую страницу' | 76 | redirect_current_page: 'На текущую страницу' |
77 | pocket_consumer_key_label: "Ключ от Pocket для импорта контента" | 77 | pocket_consumer_key_label: "Ключ от Pocket для импорта контента" |
78 | android_configuration: "Настройте Ваше Android приложение" | 78 | android_configuration: "Настройте Ваше Android приложение" |
79 | # android_instruction: "Touch here to prefill your Android application" | ||
79 | help_theme: "wallabag настраиваемый, здесь Вы можете выбрать тему." | 80 | help_theme: "wallabag настраиваемый, здесь Вы можете выбрать тему." |
80 | help_items_per_page: "Вы можете выбрать количество отображаемых записей на странице." | 81 | help_items_per_page: "Вы можете выбрать количество отображаемых записей на странице." |
81 | help_reading_speed: "wallabag посчитает сколько времени занимает чтение каждой записи. Вы можете определить здесь, как быстро вы читаете. wallabag пересчитает время чтения для каждой записи." | 82 | help_reading_speed: "wallabag посчитает сколько времени занимает чтение каждой записи. Вы можете определить здесь, как быстро вы читаете. wallabag пересчитает время чтения для каждой записи." |
82 | help_language: "Вы можете изменить язык интерфейса wallabag." | 83 | help_language: "Вы можете изменить язык интерфейса wallabag." |
83 | help_pocket_consumer_key: "Обязательно для импорта из Pocket. Вы можете создать это в Вашем аккаунте на Pocket." | 84 | help_pocket_consumer_key: "Обязательно для импорта из Pocket. Вы можете создать это в Вашем аккаунте на Pocket." |
84 | form_rss: | 85 | form_feed: |
85 | description: 'RSS фид созданный с помощью wallabag позволяет читать Ваши записи через Ваш любимый RSS агрегатор. Для начала Вам потребуется создать ключ.' | 86 | description: 'RSS фид созданный с помощью wallabag позволяет читать Ваши записи через Ваш любимый RSS агрегатор. Для начала Вам потребуется создать ключ.' |
86 | token_label: 'RSS ключ' | 87 | token_label: 'RSS ключ' |
87 | no_token: 'Ключ не задан' | 88 | no_token: 'Ключ не задан' |
88 | token_create: 'Создать ключ' | 89 | token_create: 'Создать ключ' |
89 | token_reset: 'Пересоздать ключ' | 90 | token_reset: 'Пересоздать ключ' |
90 | rss_links: 'ссылка на RSS' | 91 | # token_revoke: 'Revoke the token' |
91 | rss_link: | 92 | feed_links: 'ссылка на RSS' |
93 | feed_link: | ||
92 | unread: 'непрочитанные' | 94 | unread: 'непрочитанные' |
93 | starred: 'помеченные' | 95 | starred: 'помеченные' |
94 | archive: 'архивные' | 96 | archive: 'архивные' |
95 | rss_limit: 'Количество записей в фиде' | 97 | # all: 'All' |
98 | feed_limit: 'Количество записей в фиде' | ||
96 | form_user: | 99 | form_user: |
97 | two_factor_description: "Включить двухфакторную аутентификацию, Вы получите сообщение на указанный email с кодом, при каждом новом непроверенном подключении." | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
98 | name_label: 'Имя' | 102 | name_label: 'Имя' |
99 | email_label: 'Email' | 103 | email_label: 'Email' |
100 | twoFactorAuthentication_label: 'Двухфакторная аутентификация' | 104 | two_factor: |
101 | help_twoFactorAuthentication: "Если Вы включите двухфакторную аутентификацию, то Вы будете получать код на указанный ранее email, каждый раз при входе в wallabag." | 105 | # emailTwoFactor_label: 'Using email (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 | ||
102 | delete: | 114 | delete: |
103 | title: "Удалить мой аккаунт (или опасная зона)" | 115 | title: "Удалить мой аккаунт (или опасная зона)" |
104 | description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы." | 116 | description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы." |
@@ -110,6 +122,7 @@ config: | |||
110 | annotations: "Удалить все аннотации" | 122 | annotations: "Удалить все аннотации" |
111 | tags: "Удалить все теги" | 123 | tags: "Удалить все теги" |
112 | entries: "Удалить все записи" | 124 | entries: "Удалить все записи" |
125 | # archived: Remove ALL archived entries | ||
113 | confirm: "Вы уверены? (Данные будут БЕЗВОЗВРАТНО удалены, эти действия необратимы)" | 126 | confirm: "Вы уверены? (Данные будут БЕЗВОЗВРАТНО удалены, эти действия необратимы)" |
114 | form_password: | 127 | form_password: |
115 | description: "Здесь Вы можете поменять своя пароль. Ваш пароль должен быть длиннее 8 символов." | 128 | description: "Здесь Вы можете поменять своя пароль. Ваш пароль должен быть длиннее 8 символов." |
@@ -123,6 +136,15 @@ config: | |||
123 | edit_rule_label: 'изменить' | 136 | edit_rule_label: 'изменить' |
124 | rule_label: 'Правило' | 137 | rule_label: 'Правило' |
125 | tags_label: 'теги' | 138 | tags_label: 'теги' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
126 | faq: | 148 | faq: |
127 | title: 'FAQ' | 149 | title: 'FAQ' |
128 | tagging_rules_definition_title: 'Что значит "правило тегирования"?' | 150 | tagging_rules_definition_title: 'Что значит "правило тегирования"?' |
@@ -154,6 +176,16 @@ config: | |||
154 | or: 'Одно правило ИЛИ другое' | 176 | or: 'Одно правило ИЛИ другое' |
155 | and: 'Одно правило И другое' | 177 | and: 'Одно правило И другое' |
156 | matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>' | 178 | matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>' |
179 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | ||
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
157 | 189 | ||
158 | entry: | 190 | entry: |
159 | default_title: 'Название записи' | 191 | default_title: 'Название записи' |
@@ -165,6 +197,7 @@ entry: | |||
165 | filtered_tags: 'Отфильтрованные по тегу:' | 197 | filtered_tags: 'Отфильтрованные по тегу:' |
166 | filtered_search: 'Отфильтрованные по поиску:' | 198 | filtered_search: 'Отфильтрованные по поиску:' |
167 | untagged: 'Записи без тегов' | 199 | untagged: 'Записи без тегов' |
200 | # all: 'All entries' | ||
168 | list: | 201 | list: |
169 | number_on_the_page: '{0} Записей не обнаружено.|{1} Одна запись.|]1,Inf[ Найдено %count% записей.' | 202 | number_on_the_page: '{0} Записей не обнаружено.|{1} Одна запись.|]1,Inf[ Найдено %count% записей.' |
170 | reading_time: 'расчетное время чтения' | 203 | reading_time: 'расчетное время чтения' |
@@ -186,6 +219,8 @@ entry: | |||
186 | unread_label: 'Непрочитанная' | 219 | unread_label: 'Непрочитанная' |
187 | preview_picture_label: 'Есть картинка предварительного просмотра' | 220 | preview_picture_label: 'Есть картинка предварительного просмотра' |
188 | preview_picture_help: 'Картинка предварительного просмотра' | 221 | preview_picture_help: 'Картинка предварительного просмотра' |
222 | # is_public_label: 'Has a public link' | ||
223 | # is_public_help: 'Public link' | ||
189 | language_label: 'Язык' | 224 | language_label: 'Язык' |
190 | http_status_label: 'статус HTTP' | 225 | http_status_label: 'статус HTTP' |
191 | reading_time: | 226 | reading_time: |
@@ -224,10 +259,12 @@ entry: | |||
224 | original_article: 'оригинал' | 259 | original_article: 'оригинал' |
225 | annotations_on_the_entry: '{0} Нет аннотации|{1} Одна аннотация|]1,Inf[ %count% аннотаций' | 260 | annotations_on_the_entry: '{0} Нет аннотации|{1} Одна аннотация|]1,Inf[ %count% аннотаций' |
226 | created_at: 'Дата создания' | 261 | created_at: 'Дата создания' |
262 | # published_at: 'Publication date' | ||
263 | # published_by: 'Published by' | ||
227 | # provided_by: 'Provided by' | 264 | # provided_by: 'Provided by' |
228 | new: | 265 | new: |
229 | page_title: 'Сохранить новую запись' | 266 | page_title: 'Сохранить новую запись' |
230 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.ru' |
231 | form_new: | 268 | form_new: |
232 | url_label: Ссылка | 269 | url_label: Ссылка |
233 | search: | 270 | search: |
@@ -237,10 +274,17 @@ entry: | |||
237 | title_label: 'Название' | 274 | title_label: 'Название' |
238 | url_label: 'Ссылка' | 275 | url_label: 'Ссылка' |
239 | # origin_url_label: 'Origin url (from where you found that entry)' | 276 | # origin_url_label: 'Origin url (from where you found that entry)' |
240 | is_public_label: 'Публичная' | ||
241 | save_label: 'Сохранить' | 277 | save_label: 'Сохранить' |
242 | public: | 278 | public: |
243 | shared_by_wallabag: "Запись была опубликована <a href='%wallabag_instance%'>wallabag</a>" | 279 | shared_by_wallabag: "Запись была опубликована <a href='%wallabag_instance%'>wallabag</a>" |
280 | confirm: | ||
281 | # delete: "Are you sure you want to remove that article?" | ||
282 | # delete_tag: "Are you sure you want to remove that tag from that article?" | ||
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
244 | 288 | ||
245 | about: | 289 | about: |
246 | page_title: 'О' | 290 | page_title: 'О' |
@@ -336,7 +380,7 @@ quickstart: | |||
336 | title: 'Настроить приложение' | 380 | title: 'Настроить приложение' |
337 | description: 'Чтобы иметь приложение, которое вам подходит, ознакомьтесь с конфигурацией wallabag.' | 381 | description: 'Чтобы иметь приложение, которое вам подходит, ознакомьтесь с конфигурацией wallabag.' |
338 | language: 'Выбрать язык и дизайн' | 382 | language: 'Выбрать язык и дизайн' |
339 | rss: 'Включить RSS фид' | 383 | feed: 'Включить RSS фид' |
340 | tagging_rules: 'Создать правило для автоматической установки тегов' | 384 | tagging_rules: 'Создать правило для автоматической установки тегов' |
341 | admin: | 385 | admin: |
342 | title: 'Администрирование' | 386 | title: 'Администрирование' |
@@ -384,9 +428,16 @@ tag: | |||
384 | list: | 428 | list: |
385 | number_on_the_page: '{0} Теги не найдены.|{1} Найден один тег.|]1,Inf[ Найдено %count% тегов.' | 429 | number_on_the_page: '{0} Теги не найдены.|{1} Найден один тег.|]1,Inf[ Найдено %count% тегов.' |
386 | see_untagged_entries: 'Просмотреть записи без тегов' | 430 | see_untagged_entries: 'Просмотреть записи без тегов' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
387 | new: | 432 | new: |
388 | add: 'Добавить' | 433 | add: 'Добавить' |
389 | placeholder: 'Вы можете добавить несколько тегов, разделенных запятой.' | 434 | placeholder: 'Вы можете добавить несколько тегов, разделенных запятой.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
437 | |||
438 | export: | ||
439 | # 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>' | ||
440 | # unknown: 'Unknown' | ||
390 | 441 | ||
391 | import: | 442 | import: |
392 | page_title: 'Импорт' | 443 | page_title: 'Импорт' |
@@ -414,6 +465,9 @@ import: | |||
414 | wallabag_v2: | 465 | wallabag_v2: |
415 | page_title: 'Импорт > Wallabag v2' | 466 | page_title: 'Импорт > Wallabag v2' |
416 | description: 'Функция импорта добавит все ваши записи wallabag v2. Перейдите ко всем статьям, затем на боковой панели экспорта нажмите "JSON". У вас появится файл со всеми записями "All articles.json".' | 467 | description: 'Функция импорта добавит все ваши записи wallabag v2. Перейдите ко всем статьям, затем на боковой панели экспорта нажмите "JSON". У вас появится файл со всеми записями "All articles.json".' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
417 | readability: | 471 | readability: |
418 | page_title: 'Импорт > Readability' | 472 | page_title: 'Импорт > Readability' |
419 | description: 'Функция импорта добавит все ваши записи для чтения. На странице инструментов (https://www.readability.com/tools/) нажмите "Экспорт ваших данных" в разделе "Экспорт данных". Вы получите электронное письмо для загрузки json (что не заканчивается только .json файлом).' | 473 | description: 'Функция импорта добавит все ваши записи для чтения. На странице инструментов (https://www.readability.com/tools/) нажмите "Экспорт ваших данных" в разделе "Экспорт данных". Вы получите электронное письмо для загрузки json (что не заканчивается только .json файлом).' |
@@ -467,6 +521,7 @@ developer: | |||
467 | redirect_uris_label: 'Ссылка перенаправления (опционально)' | 521 | redirect_uris_label: 'Ссылка перенаправления (опционально)' |
468 | save_label: 'Создать нового клиента' | 522 | save_label: 'Создать нового клиента' |
469 | action_back: 'Назад' | 523 | action_back: 'Назад' |
524 | # copy_to_clipboard: Copy | ||
470 | client_parameter: | 525 | client_parameter: |
471 | page_title: 'Управление клиентским API > Параметры клиента' | 526 | page_title: 'Управление клиентским API > Параметры клиента' |
472 | page_description: 'Здесь ваши параметры клиента.' | 527 | page_description: 'Здесь ваши параметры клиента.' |
@@ -508,11 +563,34 @@ user: | |||
508 | email_label: 'Email' | 563 | email_label: 'Email' |
509 | enabled_label: 'Включить' | 564 | enabled_label: 'Включить' |
510 | last_login_label: 'Последний вход' | 565 | last_login_label: 'Последний вход' |
511 | twofactor_label: "Двухфакторная аутентификация" | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
512 | save: "Сохранить" | 568 | save: "Сохранить" |
513 | delete: "Удалить" | 569 | delete: "Удалить" |
514 | delete_confirm: "Вы уверены?" | 570 | delete_confirm: "Вы уверены?" |
515 | back_to_list: "Назад к списку" | 571 | back_to_list: "Назад к списку" |
572 | search: | ||
573 | # placeholder: Filter by login or email | ||
574 | |||
575 | site_credential: | ||
576 | # page_title: Site credentials management | ||
577 | # new_site_credential: Create a credential | ||
578 | # edit_site_credential: Edit an existing credential | ||
579 | # description: "Here you can manage all credentials for sites which required them (create, edit and delete), like a paywall, an authentication, etc." | ||
580 | # list: | ||
581 | # actions: Actions | ||
582 | # edit_action: Edit | ||
583 | # yes: Yes | ||
584 | # no: No | ||
585 | # create_new_one: Create a new credential | ||
586 | # form: | ||
587 | # username_label: 'Login' | ||
588 | # host_label: 'Host (subdomain.example.org, .example.org, etc.)' | ||
589 | # password_label: 'Password' | ||
590 | # save: Save | ||
591 | # delete: Delete | ||
592 | # delete_confirm: Are you sure? | ||
593 | # back_to_list: Back to list | ||
516 | 594 | ||
517 | error: | 595 | error: |
518 | page_title: "Произошла ошибка" | 596 | page_title: "Произошла ошибка" |
@@ -524,13 +602,18 @@ flashes: | |||
524 | password_updated: 'Пароль обновлен' | 602 | password_updated: 'Пароль обновлен' |
525 | password_not_updated_demo: "В режиме демонстрации нельзя изменять пароль для этого пользователя." | 603 | password_not_updated_demo: "В режиме демонстрации нельзя изменять пароль для этого пользователя." |
526 | user_updated: 'Информация обновлена' | 604 | user_updated: 'Информация обновлена' |
527 | rss_updated: 'RSS информация обновлена' | 605 | feed_updated: 'RSS информация обновлена' |
528 | tagging_rules_updated: 'Правила тегировния обновлены' | 606 | tagging_rules_updated: 'Правила тегировния обновлены' |
529 | tagging_rules_deleted: 'Правила тегировния удалены' | 607 | tagging_rules_deleted: 'Правила тегировния удалены' |
530 | rss_token_updated: 'RSS ключ обновлен' | 608 | feed_token_updated: 'RSS ключ обновлен' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
531 | annotations_reset: "Аннотации сброшены" | 610 | annotations_reset: "Аннотации сброшены" |
532 | tags_reset: "Теги сброшены" | 611 | tags_reset: "Теги сброшены" |
533 | entries_reset: "Записи сброшены" | 612 | entries_reset: "Записи сброшены" |
613 | # archived_reset: Archived entries deleted | ||
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
534 | entry: | 617 | entry: |
535 | notice: | 618 | notice: |
536 | entry_already_saved: 'Запись была сохранена ранее %date%' | 619 | entry_already_saved: 'Запись была сохранена ранее %date%' |
@@ -544,9 +627,11 @@ flashes: | |||
544 | entry_starred: 'Запись помечена звездочкой' | 627 | entry_starred: 'Запись помечена звездочкой' |
545 | entry_unstarred: 'Пометка звездочкой у записи убрана' | 628 | entry_unstarred: 'Пометка звездочкой у записи убрана' |
546 | entry_deleted: 'Запись удалена' | 629 | entry_deleted: 'Запись удалена' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
547 | tag: | 631 | tag: |
548 | notice: | 632 | notice: |
549 | tag_added: 'Тег добавлен' | 633 | tag_added: 'Тег добавлен' |
634 | # tag_renamed: 'Tag renamed' | ||
550 | import: | 635 | import: |
551 | notice: | 636 | notice: |
552 | failed: 'Во время импорта произошла ошибка, повторите попытку.' | 637 | failed: 'Во время импорта произошла ошибка, повторите попытку.' |
@@ -564,4 +649,9 @@ flashes: | |||
564 | notice: | 649 | notice: |
565 | added: 'Пользователь "%username%" добавлен' | 650 | added: 'Пользователь "%username%" добавлен' |
566 | updated: 'Пользователь "%username%" обновлен' | 651 | updated: 'Пользователь "%username%" обновлен' |
567 | deleted: 'Пользователь "%username%" удален' \ No newline at end of file | 652 | deleted: 'Пользователь "%username%" удален' |
653 | site_credential: | ||
654 | notice: | ||
655 | # added: 'Site credential for "%host%" added' | ||
656 | # updated: 'Site credential for "%host%" updated' | ||
657 | # deleted: 'Site credential for "%host%" deleted' | ||
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml index 9d22f90d..03f8fa9a 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'กลับไปยังรายการที่ไม่ได้อ่าน' | 33 | back_to_unread: 'กลับไปยังรายการที่ไม่ได้อ่าน' |
34 | users_management: 'การจัดการผู้ใช้' | 34 | users_management: 'การจัดการผู้ใช้' |
35 | site_credentials: 'การรับรองไซต์' | 35 | site_credentials: 'การรับรองไซต์' |
36 | quickstart: "เริ่มแบบด่วน" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'เพิ่มรายการใหม่' | 38 | add_new_entry: 'เพิ่มรายการใหม่' |
38 | search: 'ค้นหา' | 39 | search: 'ค้นหา' |
39 | filter_entries: 'ตัวกรองรายการ' | 40 | filter_entries: 'ตัวกรองรายการ' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | export: 'นำข้อมูลออก' | 42 | export: 'นำข้อมูลออก' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'ค้นหาที่นี้' | 44 | input_label: 'ค้นหาที่นี้' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'กำหนดค่า' | 55 | page_title: 'กำหนดค่า' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'ตั้งค่า' | 57 | settings: 'ตั้งค่า' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'ข้อมูลผู้ใช้' | 59 | user_info: 'ข้อมูลผู้ใช้' |
58 | password: 'รหัสผ่าน' | 60 | password: 'รหัสผ่าน' |
59 | rules: 'การแท็กข้อบังคับ' | 61 | rules: 'การแท็กข้อบังคับ' |
60 | new_user: 'เพิ่มผู้ใช้' | 62 | new_user: 'เพิ่มผู้ใช้' |
63 | reset: 'รีเซ็ตพื้นที่ ' | ||
61 | form: | 64 | form: |
62 | save: 'บันทึก' | 65 | save: 'บันทึก' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'ไอเทมต่อหน้า' | 68 | items_per_page_label: 'ไอเทมต่อหน้า' |
66 | language_label: 'ภาษา' | 69 | language_label: 'ภาษา' |
67 | reading_speed: | 70 | reading_speed: |
68 | label: 'การอ่านแบบด่วน' | 71 | label: 'การอ่านแบบด่วน (คำต่อนาที)' |
69 | help_message: 'คุณสามารถใช้เครื่องมือออนไลน์เพื่อประเมินการอ่านแบบด่วน:' | 72 | help_message: 'คุณสามารถใช้เครื่องมือออนไลน์เพื่อประเมินการอ่านแบบด่วน:' |
70 | 100_word: 'ฉันอ่าน ~100 คำต่อนาที' | ||
71 | 200_word: 'ฉันอ่าน ~200 คำต่อนาท' | ||
72 | 300_word: 'ฉันอ่าน ~300 คำต่อนาท' | ||
73 | 400_word: 'ฉันอ่าน ~400 คำต่อนาท' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | label: 'คุณต้องการเปลี่ยนทิศทางหลังจากระบุเครื่องหมายรายการอ่านที่ไหน?' | 74 | label: 'คุณต้องการเปลี่ยนทิศทางหลังจากระบุเครื่องหมายรายการอ่านที่ไหน?' |
76 | redirect_homepage: 'ไปยังโฮมเพจ' | 75 | redirect_homepage: 'ไปยังโฮมเพจ' |
@@ -83,25 +82,35 @@ config: | |||
83 | help_reading_speed: "wallabag จะคำนวณเวลาการอ่านในแต่ละรายการซึ่งคุณสามารถกำหนดได้ที่นี้,ต้องขอบคุณรายการนี้,หากคุณเป็นนักอ่านที่เร็วหรือช้า wallabag จะทำการคำนวณเวลาที่อ่านใหม่ในแต่ละรายการ" | 82 | help_reading_speed: "wallabag จะคำนวณเวลาการอ่านในแต่ละรายการซึ่งคุณสามารถกำหนดได้ที่นี้,ต้องขอบคุณรายการนี้,หากคุณเป็นนักอ่านที่เร็วหรือช้า wallabag จะทำการคำนวณเวลาที่อ่านใหม่ในแต่ละรายการ" |
84 | help_language: "คุณสามารถเปลี่ยภาษาของ wallabag interface ได้" | 83 | help_language: "คุณสามารถเปลี่ยภาษาของ wallabag interface ได้" |
85 | help_pocket_consumer_key: "การ้องขอการเก็บการนำข้อมูลเข้า คุณสามารถสร้างบัญชีการเก็บของคุณ" | 84 | help_pocket_consumer_key: "การ้องขอการเก็บการนำข้อมูลเข้า คุณสามารถสร้างบัญชีการเก็บของคุณ" |
86 | form_rss: | 85 | form_feed: |
87 | description: 'RSS จะเก็บเงื่อนไขโดย wallabag ต้องยอมรับการอ่านรายการของคุณกับผู้อ่านที่ชอบ RSS คุณต้องทำเครื่องหมายก่อน' | 86 | description: 'RSS จะเก็บเงื่อนไขโดย wallabag ต้องยอมรับการอ่านรายการของคุณกับผู้อ่านที่ชอบ RSS คุณต้องทำเครื่องหมายก่อน' |
88 | token_label: 'เครื่องหมาย RSS' | 87 | token_label: 'เครื่องหมาย RSS' |
89 | no_token: 'ไม่มีเครื่องหมาย' | 88 | no_token: 'ไม่มีเครื่องหมาย' |
90 | token_create: 'สร้างเครื่องหมาย' | 89 | token_create: 'สร้างเครื่องหมาย' |
91 | token_reset: 'ทำเครื่องหมาย' | 90 | token_reset: 'ทำเครื่องหมาย' |
92 | rss_links: 'ลิงค์ RSS' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'ลิงค์ RSS' |
93 | feed_link: | ||
94 | unread: 'ยังไมได้่อ่าน' | 94 | unread: 'ยังไมได้่อ่าน' |
95 | starred: 'ทำการแสดง' | 95 | starred: 'ทำการแสดง' |
96 | archive: 'เอกสาร' | 96 | archive: 'เอกสาร' |
97 | all: 'ทั้งหมด' | 97 | all: 'ทั้งหมด' |
98 | rss_limit: 'จำนวนไอเทมที่เก็บ' | 98 | feed_limit: 'จำนวนไอเทมที่เก็บ' |
99 | form_user: | 99 | form_user: |
100 | two_factor_description: "การเปิดใช้งาน two factor authentication คือคุณจะต้องได้รับอีเมลกับ code ที่ยังไม่ตรวจสอบในการเชื่อมต่อ" | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'ชื่อ' | 102 | name_label: 'ชื่อ' |
102 | email_label: 'อีเมล' | 103 | email_label: 'อีเมล' |
103 | twoFactorAuthentication_label: 'Two factor authentication' | 104 | two_factor: |
104 | help_twoFactorAuthentication: "ถ้าคุณเปิด 2FA, ในแต่ละช่วงเวลาที่คุณต้องการลงชื่อเข้าใช wallabag, คุณจะต้องได้รับ code จากอีเมล" | 105 | # emailTwoFactor_label: 'Using email (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: ลบบัญชีของฉัน (โซนที่เป็นภัย!) | 115 | title: ลบบัญชีของฉัน (โซนที่เป็นภัย!) |
107 | description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก | 116 | description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก |
@@ -127,6 +136,15 @@ config: | |||
127 | edit_rule_label: 'ปรับแก้' | 136 | edit_rule_label: 'ปรับแก้' |
128 | rule_label: 'ข้อบังคับ' | 137 | rule_label: 'ข้อบังคับ' |
129 | tags_label: 'แท็ก' | 138 | tags_label: 'แท็ก' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'FAQ' | 149 | title: 'FAQ' |
132 | tagging_rules_definition_title: 'ข้อบังคับการแท็กคืออะไร?' | 150 | tagging_rules_definition_title: 'ข้อบังคับการแท็กคืออะไร?' |
@@ -159,6 +177,15 @@ config: | |||
159 | and: 'หนึ่งข้อบังคับและอื่นๆ' | 177 | and: 'หนึ่งข้อบังคับและอื่นๆ' |
160 | matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>' | 178 | matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>' |
161 | notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>' | 179 | notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'หัวข้อรายการ' | 191 | default_title: 'หัวข้อรายการ' |
@@ -234,9 +261,10 @@ entry: | |||
234 | created_at: 'วันที่สร้าง' | 261 | created_at: 'วันที่สร้าง' |
235 | published_at: 'วันที่ประกาศ' | 262 | published_at: 'วันที่ประกาศ' |
236 | published_by: 'ประกาศโดย' | 263 | published_by: 'ประกาศโดย' |
264 | # provided_by: 'Provided by' | ||
237 | new: | 265 | new: |
238 | page_title: 'บันทึกรายการใหม่' | 266 | page_title: 'บันทึกรายการใหม่' |
239 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.th' |
240 | form_new: | 268 | form_new: |
241 | url_label: Url | 269 | url_label: Url |
242 | search: | 270 | search: |
@@ -245,12 +273,18 @@ entry: | |||
245 | page_title: 'แก้ไขรายการ' | 273 | page_title: 'แก้ไขรายการ' |
246 | title_label: 'หัวข้อ' | 274 | title_label: 'หัวข้อ' |
247 | url_label: 'Url' | 275 | url_label: 'Url' |
276 | # origin_url_label: 'Origin url (from where you found that entry)' | ||
248 | save_label: 'บันทึก' | 277 | save_label: 'บันทึก' |
249 | public: | 278 | public: |
250 | shared_by_wallabag: "บทความนี้จะมีการแชร์โดย %username% กับ <a href='%wallabag_instance%'>wallabag</a>" | 279 | shared_by_wallabag: "บทความนี้จะมีการแชร์โดย %username% กับ <a href='%wallabag_instance%'>wallabag</a>" |
251 | confirm: | 280 | confirm: |
252 | delete: "คุณแน่ใจหรือไม่ว่าคุณต้องการลบบทความนี้?" | 281 | delete: "คุณแน่ใจหรือไม่ว่าคุณต้องการลบบทความนี้?" |
253 | delete_tag: "คุณแน่ใจหรือไม่ว่าคุณต้องการลบแท็กจากบทความนี้?" | 282 | delete_tag: "คุณแน่ใจหรือไม่ว่าคุณต้องการลบแท็กจากบทความนี้?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
254 | 288 | ||
255 | about: | 289 | about: |
256 | page_title: 'เกี่ยวกับ' | 290 | page_title: 'เกี่ยวกับ' |
@@ -346,7 +380,7 @@ quickstart: | |||
346 | title: 'กำหนดค่าแอพพลิเคชั่น' | 380 | title: 'กำหนดค่าแอพพลิเคชั่น' |
347 | description: 'ภายใน order จะมี application suit ของคุณ, จะมองหาองค์ประกอบของ wallabag' | 381 | description: 'ภายใน order จะมี application suit ของคุณ, จะมองหาองค์ประกอบของ wallabag' |
348 | language: 'เปลี่ยนภาษาและออกแบบ' | 382 | language: 'เปลี่ยนภาษาและออกแบบ' |
349 | rss: 'เปิดใช้ RSS' | 383 | feed: 'เปิดใช้ RSS' |
350 | tagging_rules: 'เขียนข้อบังคับการแท็กอัตโนมัติของบทความของคุณ' | 384 | tagging_rules: 'เขียนข้อบังคับการแท็กอัตโนมัติของบทความของคุณ' |
351 | admin: | 385 | admin: |
352 | title: 'ผู้ดูแลระบบ' | 386 | title: 'ผู้ดูแลระบบ' |
@@ -394,12 +428,16 @@ tag: | |||
394 | list: | 428 | list: |
395 | number_on_the_page: '{0} ไม่มีการแท็ก|{1} มีหนึ่งแท็ก|]1,Inf[ มี %count% แท็ก' | 429 | number_on_the_page: '{0} ไม่มีการแท็ก|{1} มีหนึ่งแท็ก|]1,Inf[ มี %count% แท็ก' |
396 | see_untagged_entries: 'พบรายการที่ไม่ได้แท็ก' | 430 | see_untagged_entries: 'พบรายการที่ไม่ได้แท็ก' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
397 | new: | 432 | new: |
398 | add: 'เพิ่ม' | 433 | add: 'เพิ่ม' |
399 | placeholder: 'คุณสามารถเพิ่มได้หลายแท็ก, จากการแบ่งโดย comma' | 434 | placeholder: 'คุณสามารถเพิ่มได้หลายแท็ก, จากการแบ่งโดย comma' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
400 | 437 | ||
401 | export: | 438 | export: |
402 | 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>' | 439 | 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>' |
440 | # unknown: 'Unknown' | ||
403 | 441 | ||
404 | import: | 442 | import: |
405 | page_title: 'นำข้อมูลเช้า' | 443 | page_title: 'นำข้อมูลเช้า' |
@@ -427,6 +465,9 @@ import: | |||
427 | wallabag_v2: | 465 | wallabag_v2: |
428 | page_title: 'นำเข้าข้อมูล > Wallabag v2' | 466 | page_title: 'นำเข้าข้อมูล > Wallabag v2' |
429 | description: 'สำหรับผู้นำเข้าข้อมูลจะ import บทความ wallabag v2 ทั้งหมดของคุณ ไปยังบทความทั้งหมด, ดังนั้น, บน export sidebar, click ที่ "JSON" คุณจะมีไฟล์ "All articles.json"' | 467 | description: 'สำหรับผู้นำเข้าข้อมูลจะ import บทความ wallabag v2 ทั้งหมดของคุณ ไปยังบทความทั้งหมด, ดังนั้น, บน export sidebar, click ที่ "JSON" คุณจะมีไฟล์ "All articles.json"' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
430 | readability: | 471 | readability: |
431 | page_title: 'นำเข้าข้อมูล > Readability' | 472 | page_title: 'นำเข้าข้อมูล > Readability' |
432 | description: 'สำหรับผู้นำเข้าข้อมูลจะ import บทความ Readability ทั้งหมดของคุณ ไปที่เครื่องมือ (https://www.readability.com/tools/) ของหน้านั้น, click ที่ "Export your data" ในส่วน "Data Export" คุณจะได้รับ email ไป download json (which does not end with .json in fact).' | 473 | description: 'สำหรับผู้นำเข้าข้อมูลจะ import บทความ Readability ทั้งหมดของคุณ ไปที่เครื่องมือ (https://www.readability.com/tools/) ของหน้านั้น, click ที่ "Export your data" ในส่วน "Data Export" คุณจะได้รับ email ไป download json (which does not end with .json in fact).' |
@@ -480,6 +521,7 @@ developer: | |||
480 | redirect_uris_label: 'เส้นทางใหม่ของ URIs (ให้เลือกได้)' | 521 | redirect_uris_label: 'เส้นทางใหม่ของ URIs (ให้เลือกได้)' |
481 | save_label: 'สร่้างลูกข่ายใหม' | 522 | save_label: 'สร่้างลูกข่ายใหม' |
482 | action_back: 'กลับ' | 523 | action_back: 'กลับ' |
524 | # copy_to_clipboard: Copy | ||
483 | client_parameter: | 525 | client_parameter: |
484 | page_title: 'การจัดการลูกข่ายของ API > พารามิเตอร์ของลูกข่าย' | 526 | page_title: 'การจัดการลูกข่ายของ API > พารามิเตอร์ของลูกข่าย' |
485 | page_description: 'ที่นี้เป็นพารามิเตอร์ของลูกข่ายของคุณ' | 527 | page_description: 'ที่นี้เป็นพารามิเตอร์ของลูกข่ายของคุณ' |
@@ -521,7 +563,8 @@ user: | |||
521 | email_label: 'อีเมล' | 563 | email_label: 'อีเมล' |
522 | enabled_label: 'เปิดใช้งาน' | 564 | enabled_label: 'เปิดใช้งาน' |
523 | last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย' | 565 | last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย' |
524 | twofactor_label: Two factor authentication | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
525 | save: บันทึก | 568 | save: บันทึก |
526 | delete: ลบ | 569 | delete: ลบ |
527 | delete_confirm: ตุณแน่ใจหรือไม่? | 570 | delete_confirm: ตุณแน่ใจหรือไม่? |
@@ -542,7 +585,7 @@ site_credential: | |||
542 | create_new_one: สร้างข้อมูลส่วนตัวใหม่ | 585 | create_new_one: สร้างข้อมูลส่วนตัวใหม่ |
543 | form: | 586 | form: |
544 | username_label: 'ชื่อผู้ใช้' | 587 | username_label: 'ชื่อผู้ใช้' |
545 | host_label: 'โฮส' | 588 | host_label: 'โฮส (subdomain.example.org, .example.org, etc.)' |
546 | password_label: 'รหัสผ่าน' | 589 | password_label: 'รหัสผ่าน' |
547 | save: บันทึก | 590 | save: บันทึก |
548 | delete: ลบ | 591 | delete: ลบ |
@@ -559,14 +602,18 @@ flashes: | |||
559 | password_updated: 'อัปเดตรหัสผ่าน' | 602 | password_updated: 'อัปเดตรหัสผ่าน' |
560 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." | 603 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." |
561 | user_updated: 'อัปเดตข้อมูล' | 604 | user_updated: 'อัปเดตข้อมูล' |
562 | rss_updated: 'อัปเดตข้อมูล RSS' | 605 | feed_updated: 'อัปเดตข้อมูล RSS' |
563 | tagging_rules_updated: 'อัปเดตการแท็กข้อบังคับ' | 606 | tagging_rules_updated: 'อัปเดตการแท็กข้อบังคับ' |
564 | tagging_rules_deleted: 'การลบข้อบังคับของแท็ก' | 607 | tagging_rules_deleted: 'การลบข้อบังคับของแท็ก' |
565 | rss_token_updated: 'อัปเดตเครื่องหมาย RSS ' | 608 | feed_token_updated: 'อัปเดตเครื่องหมาย RSS ' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
566 | annotations_reset: รีเซ็ตหมายเหตุ | 610 | annotations_reset: รีเซ็ตหมายเหตุ |
567 | tags_reset: รีเซ็ตแท็ก | 611 | tags_reset: รีเซ็ตแท็ก |
568 | entries_reset: รีเซ็ตรายการ | 612 | entries_reset: รีเซ็ตรายการ |
569 | archived_reset: การลบเอกสารของรายการ | 613 | archived_reset: การลบเอกสารของรายการ |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
570 | entry: | 617 | entry: |
571 | notice: | 618 | notice: |
572 | entry_already_saved: 'รายการพร้อมบันทึกที่ %date%' | 619 | entry_already_saved: 'รายการพร้อมบันทึกที่ %date%' |
@@ -580,9 +627,11 @@ flashes: | |||
580 | entry_starred: 'รายการที่แสดง' | 627 | entry_starred: 'รายการที่แสดง' |
581 | entry_unstarred: 'รายการที่ไม่ได้แสดง' | 628 | entry_unstarred: 'รายการที่ไม่ได้แสดง' |
582 | entry_deleted: 'รายการที่ถูกลบ' | 629 | entry_deleted: 'รายการที่ถูกลบ' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
583 | tag: | 631 | tag: |
584 | notice: | 632 | notice: |
585 | tag_added: 'แท็กที่เพิ่ม' | 633 | tag_added: 'แท็กที่เพิ่ม' |
634 | # tag_renamed: 'Tag renamed' | ||
586 | import: | 635 | import: |
587 | notice: | 636 | notice: |
588 | failed: 'นำข้อมูลเข้าล้มเหลว, ลองใหม่อีกครั้ง' | 637 | failed: 'นำข้อมูลเข้าล้มเหลว, ลองใหม่อีกครั้ง' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml index 4c71f0b9..05cfbbfc 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml | |||
@@ -33,10 +33,12 @@ menu: | |||
33 | back_to_unread: 'Okunmayan makalelere geri dön' | 33 | back_to_unread: 'Okunmayan makalelere geri dön' |
34 | # users_management: 'Users management' | 34 | # users_management: 'Users management' |
35 | # site_credentials: 'Site credentials' | 35 | # site_credentials: 'Site credentials' |
36 | quickstart: "Hızlı başlangıç" | ||
36 | top: | 37 | top: |
37 | add_new_entry: 'Yeni bir makale ekle' | 38 | add_new_entry: 'Yeni bir makale ekle' |
38 | search: 'Ara' | 39 | search: 'Ara' |
39 | filter_entries: 'Filtrele' | 40 | filter_entries: 'Filtrele' |
41 | # random_entry: Jump to a random entry from that list | ||
40 | export: 'Dışa Aktar' | 42 | export: 'Dışa Aktar' |
41 | search_form: | 43 | search_form: |
42 | input_label: 'Aramak istediğiniz herhangi bir şey yazın' | 44 | input_label: 'Aramak istediğiniz herhangi bir şey yazın' |
@@ -53,11 +55,12 @@ config: | |||
53 | page_title: 'Yapılandırma' | 55 | page_title: 'Yapılandırma' |
54 | tab_menu: | 56 | tab_menu: |
55 | settings: 'Ayarlar' | 57 | settings: 'Ayarlar' |
56 | rss: 'RSS' | 58 | feed: 'RSS' |
57 | user_info: 'Kullanıcı bilgileri' | 59 | user_info: 'Kullanıcı bilgileri' |
58 | password: 'Şifre' | 60 | password: 'Şifre' |
59 | rules: 'Etiketleme kuralları' | 61 | rules: 'Etiketleme kuralları' |
60 | new_user: 'Bir kullanıcı ekle' | 62 | new_user: 'Bir kullanıcı ekle' |
63 | # reset: 'Reset area' | ||
61 | form: | 64 | form: |
62 | save: 'Kaydet' | 65 | save: 'Kaydet' |
63 | form_settings: | 66 | form_settings: |
@@ -65,12 +68,8 @@ config: | |||
65 | items_per_page_label: 'Sayfa başına makale sayısı' | 68 | items_per_page_label: 'Sayfa başına makale sayısı' |
66 | language_label: 'Dil' | 69 | language_label: 'Dil' |
67 | reading_speed: | 70 | reading_speed: |
68 | # label: 'Reading speed' | 71 | # label: 'Reading speed (words per minute)' |
69 | # help_message: 'You can use online tools to estimate your reading speed:' | 72 | # help_message: 'You can use online tools to estimate your reading speed:' |
70 | # 100_word: 'I read ~100 words per minute' | ||
71 | # 200_word: 'I read ~200 words per minute' | ||
72 | # 300_word: 'I read ~300 words per minute' | ||
73 | # 400_word: 'I read ~400 words per minute' | ||
74 | action_mark_as_read: | 73 | action_mark_as_read: |
75 | # label: 'Where do you want to be redirected to after marking an article as read?' | 74 | # label: 'Where do you want to be redirected to after marking an article as read?' |
76 | # redirect_homepage: 'To the homepage' | 75 | # redirect_homepage: 'To the homepage' |
@@ -83,25 +82,35 @@ config: | |||
83 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." | 82 | # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." |
84 | # help_language: "You can change the language of wallabag interface." | 83 | # help_language: "You can change the language of wallabag interface." |
85 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." | 84 | # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." |
86 | form_rss: | 85 | form_feed: |
87 | description: 'wallabag RSS akışı kaydetmiş olduğunuz makalelerini favori RSS okuyucunuzda görüntülemenizi sağlar. Bunu yapabilmek için öncelikle belirteç (token) oluşturmalısınız.' | 86 | description: 'wallabag RSS akışı kaydetmiş olduğunuz makalelerini favori RSS okuyucunuzda görüntülemenizi sağlar. Bunu yapabilmek için öncelikle belirteç (token) oluşturmalısınız.' |
88 | token_label: 'RSS belirteci (token)' | 87 | token_label: 'RSS belirteci (token)' |
89 | no_token: 'Belirteç (token) yok' | 88 | no_token: 'Belirteç (token) yok' |
90 | token_create: 'Yeni belirteç (token) oluştur' | 89 | token_create: 'Yeni belirteç (token) oluştur' |
91 | token_reset: 'Belirteci (token) sıfırla' | 90 | token_reset: 'Belirteci (token) sıfırla' |
92 | rss_links: 'RSS akış bağlantıları' | 91 | # token_revoke: 'Revoke the token' |
93 | rss_link: | 92 | feed_links: 'RSS akış bağlantıları' |
93 | feed_link: | ||
94 | unread: 'Okunmayan' | 94 | unread: 'Okunmayan' |
95 | starred: 'Favoriler' | 95 | starred: 'Favoriler' |
96 | archive: 'Arşiv' | 96 | archive: 'Arşiv' |
97 | # all: 'All' | 97 | # all: 'All' |
98 | rss_limit: 'RSS içeriğinden talep edilecek makale limiti' | 98 | feed_limit: 'RSS içeriğinden talep edilecek makale limiti' |
99 | form_user: | 99 | 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." | 100 | # 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 | # login_label: 'Login (can not be changed)' | ||
101 | name_label: 'İsim' | 102 | name_label: 'İsim' |
102 | email_label: 'E-posta' | 103 | email_label: 'E-posta' |
103 | twoFactorAuthentication_label: 'İki adımlı doğrulama' | 104 | two_factor: |
104 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 105 | # emailTwoFactor_label: 'Using email (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. |
@@ -127,6 +136,15 @@ config: | |||
127 | # edit_rule_label: 'edit' | 136 | # edit_rule_label: 'edit' |
128 | rule_label: 'Kural' | 137 | rule_label: 'Kural' |
129 | tags_label: 'Etiketler' | 138 | tags_label: 'Etiketler' |
139 | # card: | ||
140 | # new_tagging_rule: Create a tagging rule | ||
141 | # import_tagging_rules: Import tagging rules | ||
142 | # import_tagging_rules_detail: You have to select the JSON file you previously exported. | ||
143 | # export_tagging_rules: Export tagging rules | ||
144 | # export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them. | ||
145 | # file_label: JSON file | ||
146 | # import_submit: Import | ||
147 | # export: Export | ||
130 | faq: | 148 | faq: |
131 | title: 'S.S.S.' | 149 | title: 'S.S.S.' |
132 | tagging_rules_definition_title: '« etiketleme kuralları » ne anlama geliyor?' | 150 | tagging_rules_definition_title: '« etiketleme kuralları » ne anlama geliyor?' |
@@ -159,6 +177,15 @@ config: | |||
159 | and: 'Bir kural ve diğeri' | 177 | 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>' | 178 | # 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>' | 179 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
180 | otp: | ||
181 | # page_title: Two-factor authentication | ||
182 | # app: | ||
183 | # 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. | ||
184 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
185 | # 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:' | ||
186 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
187 | # cancel: Cancel | ||
188 | # enable: Enable | ||
162 | 189 | ||
163 | entry: | 190 | entry: |
164 | default_title: 'Makalenin başlığı' | 191 | default_title: 'Makalenin başlığı' |
@@ -192,6 +219,8 @@ entry: | |||
192 | unread_label: 'Okunmayan' | 219 | unread_label: 'Okunmayan' |
193 | preview_picture_label: 'Resim önizlemesi varsa' | 220 | preview_picture_label: 'Resim önizlemesi varsa' |
194 | preview_picture_help: 'Resim önizlemesi' | 221 | preview_picture_help: 'Resim önizlemesi' |
222 | # is_public_label: 'Has a public link' | ||
223 | # is_public_help: 'Public link' | ||
195 | language_label: 'Dil' | 224 | language_label: 'Dil' |
196 | # http_status_label: 'HTTP status' | 225 | # http_status_label: 'HTTP status' |
197 | reading_time: | 226 | reading_time: |
@@ -235,7 +264,7 @@ entry: | |||
235 | # provided_by: 'Provided by' | 264 | # provided_by: 'Provided by' |
236 | new: | 265 | new: |
237 | page_title: 'Yeni makaleyi kaydet' | 266 | page_title: 'Yeni makaleyi kaydet' |
238 | placeholder: 'http://website.com' | 267 | placeholder: 'https://website.tr' |
239 | form_new: | 268 | form_new: |
240 | url_label: Url | 269 | url_label: Url |
241 | search: | 270 | search: |
@@ -251,6 +280,11 @@ entry: | |||
251 | confirm: | 280 | confirm: |
252 | # delete: "Are you sure you want to remove that article?" | 281 | # delete: "Are you sure you want to remove that article?" |
253 | # delete_tag: "Are you sure you want to remove that tag from that article?" | 282 | # delete_tag: "Are you sure you want to remove that tag from that article?" |
283 | metadata: | ||
284 | # reading_time: "Estimated reading time" | ||
285 | # reading_time_minutes_short: "%readingTime% min" | ||
286 | # address: "Address" | ||
287 | # added_on: "Added on" | ||
254 | 288 | ||
255 | about: | 289 | about: |
256 | page_title: 'Hakkımızda' | 290 | page_title: 'Hakkımızda' |
@@ -346,7 +380,7 @@ quickstart: | |||
346 | title: 'Uygulamayı Yapılandırma' | 380 | title: 'Uygulamayı Yapılandırma' |
347 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' | 381 | # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' |
348 | language: 'Dili ve tasarımı değiştirme' | 382 | language: 'Dili ve tasarımı değiştirme' |
349 | rss: 'RSS akışını aktifleştirme' | 383 | feed: 'RSS akışını aktifleştirme' |
350 | # tagging_rules: 'Write rules to automatically tag your articles' | 384 | # tagging_rules: 'Write rules to automatically tag your articles' |
351 | admin: | 385 | admin: |
352 | # title: 'Administration' | 386 | # title: 'Administration' |
@@ -394,12 +428,16 @@ tag: | |||
394 | list: | 428 | list: |
395 | number_on_the_page: '{0} Herhangi bir etiket yok.|{1} Burada bir adet etiket var.|]1,Inf[ Burada %count% adet etiket var.' | 429 | number_on_the_page: '{0} Herhangi bir etiket yok.|{1} Burada bir adet etiket var.|]1,Inf[ Burada %count% adet etiket var.' |
396 | # see_untagged_entries: 'See untagged entries' | 430 | # see_untagged_entries: 'See untagged entries' |
431 | # no_untagged_entries: 'There are no untagged entries.' | ||
397 | new: | 432 | new: |
398 | # add: 'Add' | 433 | # add: 'Add' |
399 | # placeholder: 'You can add several tags, separated by a comma.' | 434 | # placeholder: 'You can add several tags, separated by a comma.' |
435 | rename: | ||
436 | # placeholder: 'You can update tag name.' | ||
400 | 437 | ||
401 | # export: | 438 | export: |
402 | # 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>' | 439 | # 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>' |
440 | # unknown: 'Unknown' | ||
403 | 441 | ||
404 | import: | 442 | import: |
405 | page_title: 'İçe Aktar' | 443 | page_title: 'İçe Aktar' |
@@ -427,6 +465,9 @@ import: | |||
427 | wallabag_v2: | 465 | wallabag_v2: |
428 | page_title: 'İçe Aktar > Wallabag v2' | 466 | page_title: 'İçe Aktar > Wallabag v2' |
429 | # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' | 467 | # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' |
468 | # elcurator: | ||
469 | # page_title: 'Import > elCurator' | ||
470 | # description: 'This importer will import all your elCurator articles. Go to your preferences in your elCurator account and then, export your content. You will have a JSON file.' | ||
430 | readability: | 471 | readability: |
431 | page_title: 'İçe Aktar > Readability' | 472 | page_title: 'İçe Aktar > Readability' |
432 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' | 473 | # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).' |
@@ -480,6 +521,7 @@ developer: | |||
480 | # redirect_uris_label: 'Redirect URIs' | 521 | # redirect_uris_label: 'Redirect URIs' |
481 | # save_label: 'Create a new client' | 522 | # save_label: 'Create a new client' |
482 | # action_back: 'Back' | 523 | # action_back: 'Back' |
524 | # copy_to_clipboard: Copy | ||
483 | # client_parameter: | 525 | # client_parameter: |
484 | # page_title: 'API clients management > Client parameters' | 526 | # page_title: 'API clients management > Client parameters' |
485 | # page_description: 'Here are your client parameters.' | 527 | # page_description: 'Here are your client parameters.' |
@@ -521,7 +563,8 @@ user: | |||
521 | email_label: 'E-posta' | 563 | email_label: 'E-posta' |
522 | # enabled_label: 'Enabled' | 564 | # enabled_label: 'Enabled' |
523 | # last_login_label: 'Last login' | 565 | # last_login_label: 'Last login' |
524 | # twofactor_label: Two factor authentication | 566 | # twofactor_email_label: Two factor authentication by email |
567 | # twofactor_google_label: Two factor authentication by OTP app | ||
525 | # save: Save | 568 | # save: Save |
526 | # delete: Delete | 569 | # delete: Delete |
527 | # delete_confirm: Are you sure? | 570 | # delete_confirm: Are you sure? |
@@ -529,6 +572,26 @@ user: | |||
529 | search: | 572 | search: |
530 | # placeholder: Filter by username or email | 573 | # placeholder: Filter by username or email |
531 | 574 | ||
575 | site_credential: | ||
576 | # page_title: Site credentials management | ||
577 | # new_site_credential: Create a credential | ||
578 | # edit_site_credential: Edit an existing credential | ||
579 | # description: "Here you can manage all credentials for sites which required them (create, edit and delete), like a paywall, an authentication, etc." | ||
580 | # list: | ||
581 | # actions: Actions | ||
582 | # edit_action: Edit | ||
583 | # yes: Yes | ||
584 | # no: No | ||
585 | # create_new_one: Create a new credential | ||
586 | # form: | ||
587 | # username_label: 'Login' | ||
588 | # host_label: 'Host (subdomain.example.org, .example.org, etc.)' | ||
589 | # password_label: 'Password' | ||
590 | # save: Save | ||
591 | # delete: Delete | ||
592 | # delete_confirm: Are you sure? | ||
593 | # back_to_list: Back to list | ||
594 | |||
532 | error: | 595 | error: |
533 | # page_title: An error occurred | 596 | # page_title: An error occurred |
534 | 597 | ||
@@ -539,14 +602,18 @@ flashes: | |||
539 | password_updated: 'Şifre güncellendi' | 602 | password_updated: 'Şifre güncellendi' |
540 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." | 603 | password_not_updated_demo: "In demonstration mode, you can't change password for this user." |
541 | user_updated: 'Bilgiler güncellendi' | 604 | user_updated: 'Bilgiler güncellendi' |
542 | rss_updated: 'RSS bilgiler güncellendi' | 605 | feed_updated: 'RSS bilgiler güncellendi' |
543 | tagging_rules_updated: 'Tagging rules updated' | 606 | # tagging_rules_updated: 'Tagging rules updated' |
544 | tagging_rules_deleted: 'Tagging rule deleted' | 607 | # tagging_rules_deleted: 'Tagging rule deleted' |
545 | rss_token_updated: 'RSS token updated' | 608 | # feed_token_updated: 'RSS token updated' |
609 | # feed_token_revoked: 'RSS token revoked' | ||
546 | # annotations_reset: Annotations reset | 610 | # annotations_reset: Annotations reset |
547 | # tags_reset: Tags reset | 611 | # tags_reset: Tags reset |
548 | # entries_reset: Entries reset | 612 | # entries_reset: Entries reset |
549 | # archived_reset: Archived entries deleted | 613 | # archived_reset: Archived entries deleted |
614 | # otp_enabled: Two-factor authentication enabled | ||
615 | # tagging_rules_imported: Tagging rules imported | ||
616 | # tagging_rules_not_imported: Error while importing tagging rules | ||
550 | entry: | 617 | entry: |
551 | notice: | 618 | notice: |
552 | entry_already_saved: 'Entry already saved on %date%' | 619 | entry_already_saved: 'Entry already saved on %date%' |
@@ -560,9 +627,11 @@ flashes: | |||
560 | entry_starred: 'Makale favorilere eklendi' | 627 | entry_starred: 'Makale favorilere eklendi' |
561 | entry_unstarred: 'Makale favorilerden çıkartıldı' | 628 | entry_unstarred: 'Makale favorilerden çıkartıldı' |
562 | entry_deleted: 'Makale silindi' | 629 | entry_deleted: 'Makale silindi' |
630 | # no_random_entry: 'No article with these criterias was found' | ||
563 | tag: | 631 | tag: |
564 | notice: | 632 | notice: |
565 | tag_added: 'Etiket eklendi' | 633 | tag_added: 'Etiket eklendi' |
634 | # tag_renamed: 'Tag renamed' | ||
566 | import: | 635 | import: |
567 | notice: | 636 | notice: |
568 | # failed: 'Import failed, please try again.' | 637 | # failed: 'Import failed, please try again.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.da.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.da.yml index c6a84209..c0438978 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.da.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.da.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'Adgangskoden skal være mindst 8 tegn' | 3 | password_too_short: 'Adgangskoden skal være mindst 8 tegn' |
4 | # password_wrong_value: 'Wrong value for your current password' | 4 | # password_wrong_value: 'Wrong value for your current password' |
5 | # item_per_page_too_high: 'This will certainly kill the app' | 5 | # item_per_page_too_high: 'This will certainly kill the app' |
6 | # rss_limit_too_high: 'This will certainly kill the app' | 6 | # feed_limit_too_high: 'This will certainly kill the app' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.de.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.de.yml index 907b67a5..4c675ef4 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.de.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.de.yml | |||
@@ -3,6 +3,5 @@ validator: | |||
3 | password_too_short: 'Kennwort-Mindestlänge von acht Zeichen nicht erfüllt' | 3 | password_too_short: 'Kennwort-Mindestlänge von acht Zeichen nicht erfüllt' |
4 | password_wrong_value: 'Falscher Wert für dein aktuelles Kennwort' | 4 | password_wrong_value: 'Falscher Wert für dein aktuelles Kennwort' |
5 | item_per_page_too_high: 'Dies wird die Anwendung möglicherweise beenden' | 5 | item_per_page_too_high: 'Dies wird die Anwendung möglicherweise beenden' |
6 | rss_limit_too_high: 'Dies wird die Anwendung möglicherweise beenden' | 6 | feed_limit_too_high: 'Dies wird die Anwendung möglicherweise beenden' |
7 | quote_length_too_high: 'Das Zitat ist zu lang. Es sollte nicht mehr als {{ limit }} Zeichen enthalten.' | 7 | quote_length_too_high: 'Das Zitat ist zu lang. Es sollte nicht mehr als {{ limit }} Zeichen enthalten.' |
8 | |||
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.en.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.en.yml index 8cc117fe..89d4c68a 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.en.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.en.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'Password should by at least 8 chars long' | 3 | password_too_short: 'Password should by at least 8 chars long' |
4 | password_wrong_value: 'Wrong value for your current password' | 4 | password_wrong_value: 'Wrong value for your current password' |
5 | item_per_page_too_high: 'This will certainly kill the app' | 5 | item_per_page_too_high: 'This will certainly kill the app' |
6 | rss_limit_too_high: 'This will certainly kill the app' | 6 | feed_limit_too_high: 'This will certainly kill the app' |
7 | quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.es.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.es.yml index 97a8edfa..ea6575eb 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.es.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.es.yml | |||
@@ -1,7 +1,7 @@ | |||
1 | validator: | 1 | validator: |
2 | password_must_match: 'Las contraseñas no coinciden' | 2 | password_must_match: 'Las contraseñas no coinciden' |
3 | password_too_short: 'La contraseña debe tener al menos 8 carácteres' | 3 | password_too_short: 'La contraseña debe tener al menos 8 caracteres' |
4 | password_wrong_value: 'Entrada equivocada para su contraseña actual' | 4 | password_wrong_value: 'La contraseña actual es incorrecta' |
5 | item_per_page_too_high: 'Esto matará la aplicación' | 5 | item_per_page_too_high: 'Esto matará la aplicación' |
6 | rss_limit_too_high: 'Esto matará la aplicación' | 6 | feed_limit_too_high: 'Esto matará la aplicación' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | quote_length_too_high: 'La cita es demasiado larga. Debe tener {{ limit }} caracteres o menos.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.fa.yml index ef677525..9b1a4af2 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.fa.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.fa.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'رمز شما باید ۸ حرف یا بیشتر باشد' | 3 | password_too_short: 'رمز شما باید ۸ حرف یا بیشتر باشد' |
4 | password_wrong_value: 'رمز فعلی را اشتباه وارد کردهاید' | 4 | password_wrong_value: 'رمز فعلی را اشتباه وارد کردهاید' |
5 | item_per_page_too_high: 'با این تعداد برنامه به فنا میرود' | 5 | item_per_page_too_high: 'با این تعداد برنامه به فنا میرود' |
6 | rss_limit_too_high: 'با این تعداد برنامه به فنا میرود' | 6 | feed_limit_too_high: 'با این تعداد برنامه به فنا میرود' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.fr.yml index f31b4ed2..92f69aa0 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.fr.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: "Le mot de passe doit contenir au moins 8 caractères" | 3 | password_too_short: "Le mot de passe doit contenir au moins 8 caractères" |
4 | password_wrong_value: "Votre mot de passe actuel est faux" | 4 | password_wrong_value: "Votre mot de passe actuel est faux" |
5 | item_per_page_too_high: "Ça ne va pas plaire à l’application" | 5 | item_per_page_too_high: "Ça ne va pas plaire à l’application" |
6 | rss_limit_too_high: "Ça ne va pas plaire à l’application" | 6 | feed_limit_too_high: "Ça ne va pas plaire à l’application" |
7 | quote_length_too_high: "La citation est trop longue. Elle doit avoir au maximum {{ limit }} caractères." | 7 | quote_length_too_high: "La citation est trop longue. Elle doit avoir au maximum {{ limit }} caractères." |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.it.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.it.yml index d949cc3b..b20d6f51 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.it.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.it.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'La password deve essere lunga almeno 8 caratteri' | 3 | password_too_short: 'La password deve essere lunga almeno 8 caratteri' |
4 | password_wrong_value: 'Valore inserito per la password corrente errato' | 4 | password_wrong_value: 'Valore inserito per la password corrente errato' |
5 | item_per_page_too_high: 'Questo valore è troppo alto' | 5 | item_per_page_too_high: 'Questo valore è troppo alto' |
6 | rss_limit_too_high: 'Questo valore è troppo alto' | 6 | feed_limit_too_high: 'Questo valore è troppo alto' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.oc.yml index 87f00f10..cb57844f 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.oc.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.oc.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'Lo senhal deu aver almens 8 caractèrs' | 3 | password_too_short: 'Lo senhal deu aver almens 8 caractèrs' |
4 | password_wrong_value: 'Vòstre senhal actual es pas bon' | 4 | password_wrong_value: 'Vòstre senhal actual es pas bon' |
5 | item_per_page_too_high: "Aquò li agradarà pas a l'aplicacion" | 5 | item_per_page_too_high: "Aquò li agradarà pas a l'aplicacion" |
6 | rss_limit_too_high: "Aquò li agradarà pas a l'aplicacion" | 6 | feed_limit_too_high: "Aquò li agradarà pas a l'aplicacion" |
7 | quote_length_too_high: 'Aquesta citacion es tròpa longa. Cal que faga {{ limit }} caractèrs o mens.' | 7 | quote_length_too_high: 'Aquesta citacion es tròpa longa. Cal que faga {{ limit }} caractèrs o mens.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.pl.yml index e4165c14..94757cc5 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.pl.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.pl.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'Hasło powinno mieć minimum 8 znaków długości' | 3 | password_too_short: 'Hasło powinno mieć minimum 8 znaków długości' |
4 | password_wrong_value: 'Twoje obecne hasło jest błędne' | 4 | password_wrong_value: 'Twoje obecne hasło jest błędne' |
5 | item_per_page_too_high: 'To może spowodować problemy z aplikacją' | 5 | item_per_page_too_high: 'To może spowodować problemy z aplikacją' |
6 | rss_limit_too_high: 'To może spowodować problemy z aplikacją' | 6 | feed_limit_too_high: 'To może spowodować problemy z aplikacją' |
7 | quote_length_too_high: 'Cytat jest zbyt długi. powinien mieć {{ limit }} znaków lub mniej.' | 7 | quote_length_too_high: 'Cytat jest zbyt długi. powinien mieć {{ limit }} znaków lub mniej.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.pt.yml index a8c1f9de..1d69af97 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.pt.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.pt.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'A senha deve ter pelo menos 8 caracteres' | 3 | password_too_short: 'A senha deve ter pelo menos 8 caracteres' |
4 | password_wrong_value: 'A senha atual informada está errada' | 4 | password_wrong_value: 'A senha atual informada está errada' |
5 | item_per_page_too_high: 'Certamente isso pode matar a aplicação' | 5 | item_per_page_too_high: 'Certamente isso pode matar a aplicação' |
6 | rss_limit_too_high: 'Certamente isso pode matar a aplicação' | 6 | feed_limit_too_high: 'Certamente isso pode matar a aplicação' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | quote_length_too_high: 'A citaçãpo é muito longa. Ela deve ter {{ limit }} caracteres ou menos.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.ro.yml index 6840cf11..e5c8a72f 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.ro.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.ro.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | password_too_short: 'Parola ar trebui să conțină cel puțin 8 caractere' | 3 | password_too_short: 'Parola ar trebui să conțină cel puțin 8 caractere' |
4 | # password_wrong_value: 'Wrong value for your current password' | 4 | # password_wrong_value: 'Wrong value for your current password' |
5 | # item_per_page_too_high: 'This will certainly kill the app' | 5 | # item_per_page_too_high: 'This will certainly kill the app' |
6 | # rss_limit_too_high: 'This will certainly kill the app' | 6 | # feed_limit_too_high: 'This will certainly kill the app' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/validators.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/validators.tr.yml index e1e7317f..881ffd3b 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/validators.tr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/validators.tr.yml | |||
@@ -3,5 +3,5 @@ validator: | |||
3 | # password_too_short: 'Password should by at least 8 chars long' | 3 | # password_too_short: 'Password should by at least 8 chars long' |
4 | # password_wrong_value: 'Wrong value for your current password' | 4 | # password_wrong_value: 'Wrong value for your current password' |
5 | # item_per_page_too_high: 'This will certainly kill the app' | 5 | # item_per_page_too_high: 'This will certainly kill the app' |
6 | # rss_limit_too_high: 'This will certainly kill the app' | 6 | # feed_limit_too_high: 'This will certainly kill the app' |
7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' | 7 | # quote_length_too_high: 'The quote is too long. It should have {{ limit }} characters or less.' |
diff --git a/src/Wallabag/CoreBundle/Resources/views/base.html.twig b/src/Wallabag/CoreBundle/Resources/views/base.html.twig index aa388bcb..496b3fb6 100644 --- a/src/Wallabag/CoreBundle/Resources/views/base.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/base.html.twig | |||
@@ -1,13 +1,15 @@ | |||
1 | <!DOCTYPE html> | 1 | <!DOCTYPE html> |
2 | <!--[if lte IE 6]><html class="no-js ie6 ie67 ie678" lang="en"><![endif]--> | 2 | {% set lang = app.request.locale|default('') -%} |
3 | <!--[if lte IE 7]><html class="no-js ie7 ie67 ie678" lang="en"><![endif]--> | 3 | <!--[if lte IE 6]><html class="no-js ie6 ie67 ie678"{% if lang is not empty %} lang="{{ lang }}"{% endif %}><![endif]--> |
4 | <!--[if IE 8]><html class="no-js ie8 ie678" lang="en"><![endif]--> | 4 | <!--[if lte IE 7]><html class="no-js ie7 ie67 ie678"{% if lang is not empty %} lang="{{ lang }}"{% endif %}><![endif]--> |
5 | <!--[if gt IE 8]><html class="no-js" lang="en"><![endif]--> | 5 | <!--[if IE 8]><html class="no-js ie8 ie678"{% if lang is not empty %} lang="{{ lang }}"{% endif %}><![endif]--> |
6 | <html> | 6 | <!--[if gt IE 8]><html class="no-js"{% if lang is not empty %} lang="{{ lang }}"{% endif %}><![endif]--> |
7 | <html{% if lang is not empty %} lang="{{ lang }}"{% endif %}> | ||
7 | <head> | 8 | <head> |
8 | {% block head %} | 9 | {% block head %} |
9 | <meta name="viewport" content="initial-scale=1.0"> | 10 | <meta name="viewport" content="initial-scale=1.0"> |
10 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | 11 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
12 | <meta name="referrer" content="strict-origin-when-cross-origin"> | ||
11 | <!--[if IE]> | 13 | <!--[if IE]> |
12 | <meta http-equiv="X-UA-Compatible" content="IE=10"> | 14 | <meta http-equiv="X-UA-Compatible" content="IE=10"> |
13 | <![endif]--> | 15 | <![endif]--> |
@@ -42,6 +44,7 @@ | |||
42 | 44 | ||
43 | {% block css %} | 45 | {% block css %} |
44 | {% endblock %} | 46 | {% endblock %} |
47 | <link rel="stylesheet" href="{{ asset('custom.css') }}"> | ||
45 | {% block scripts %} | 48 | {% block scripts %} |
46 | <script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script> | 49 | <script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script> |
47 | <script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script> | 50 | <script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script> |
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..f719bea2 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> |
@@ -95,43 +94,42 @@ | |||
95 | {{ form_rest(form.config) }} | 94 | {{ form_rest(form.config) }} |
96 | </form> | 95 | </form> |
97 | 96 | ||
98 | <h2>{{ 'config.tab_menu.rss'|trans }}</h2> | 97 | <h2>{{ 'config.tab_menu.feed'|trans }}</h2> |
99 | 98 | ||
100 | {{ form_start(form.rss) }} | 99 | {{ form_start(form.feed) }} |
101 | {{ form_errors(form.rss) }} | 100 | {{ form_errors(form.feed) }} |
102 | 101 | ||
103 | <div class="row"> | 102 | <div class="row"> |
104 | {{ 'config.form_rss.description'|trans }} | 103 | {{ 'config.form_feed.description'|trans }} |
105 | </div> | 104 | </div> |
106 | 105 | ||
107 | <fieldset class="w500p inline"> | 106 | <fieldset class="w500p inline"> |
108 | <div class="row"> | 107 | <div class="row"> |
109 | <label>{{ 'config.form_rss.token_label'|trans }}</label> | 108 | <label>{{ 'config.form_feed.token_label'|trans }}</label> |
110 | {% if rss.token %} | 109 | {% if feed.token %} |
111 | {{ rss.token }} | 110 | {{ feed.token }} |
112 | {% else %} | 111 | {% else %} |
113 | <em>{{ 'config.form_rss.no_token'|trans }}</em> | 112 | <em>{{ 'config.form_feed.no_token'|trans }}</em> |
113 | {% endif %} | ||
114 | |||
115 | {% if feed.token %} | ||
116 | – <a href="{{ path('generate_token') }}">{{ 'config.form_feed.token_reset'|trans }}</a> | ||
117 | – <a href="{{ path('revoke_token') }}">{{ 'config.form_feed.token_revoke'|trans }}</a> | ||
118 | {% else %} | ||
119 | – <a href="{{ path('generate_token') }}">{{ 'config.form_feed.token_create'|trans }}</a> | ||
114 | {% endif %} | 120 | {% endif %} |
115 | – | ||
116 | <a href="{{ path('generate_token') }}"> | ||
117 | {% if rss.token %} | ||
118 | {{ 'config.form_rss.token_reset'|trans }} | ||
119 | {% else %} | ||
120 | {{ 'config.form_rss.token_create'|trans }} | ||
121 | {% endif %} | ||
122 | </a> | ||
123 | </div> | 121 | </div> |
124 | </fieldset> | 122 | </fieldset> |
125 | 123 | ||
126 | {% if rss.token %} | 124 | {% if feed.token %} |
127 | <fieldset class="w500p inline"> | 125 | <fieldset class="w500p inline"> |
128 | <div class="row"> | 126 | <div class="row"> |
129 | <label>{{ 'config.form_rss.rss_links'|trans }}</label> | 127 | <label>{{ 'config.form_feed.feed_links'|trans }}</label> |
130 | <ul> | 128 | <ul> |
131 | <li><a href="{{ path('unread_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.unread'|trans }}</a></li> | 129 | <li><a href="{{ path('unread_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.unread'|trans }}</a></li> |
132 | <li><a href="{{ path('starred_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.starred'|trans }}</a></li> | 130 | <li><a href="{{ path('starred_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.starred'|trans }}</a></li> |
133 | <li><a href="{{ path('archive_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.archive'|trans }}</a></li> | 131 | <li><a href="{{ path('archive_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.archive'|trans }}</a></li> |
134 | <li><a href="{{ path('all_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.all'|trans }}</a></li> | 132 | <li><a href="{{ path('all_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.all'|trans }}</a></li> |
135 | </ul> | 133 | </ul> |
136 | </div> | 134 | </div> |
137 | </fieldset> | 135 | </fieldset> |
@@ -139,19 +137,25 @@ | |||
139 | 137 | ||
140 | <fieldset class="w500p inline"> | 138 | <fieldset class="w500p inline"> |
141 | <div class="row"> | 139 | <div class="row"> |
142 | {{ form_label(form.rss.rss_limit) }} | 140 | {{ form_label(form.feed.feed_limit) }} |
143 | {{ form_errors(form.rss.rss_limit) }} | 141 | {{ form_errors(form.feed.feed_limit) }} |
144 | {{ form_widget(form.rss.rss_limit) }} | 142 | {{ form_widget(form.feed.feed_limit) }} |
145 | </div> | 143 | </div> |
146 | </fieldset> | 144 | </fieldset> |
147 | 145 | ||
148 | {{ form_rest(form.rss) }} | 146 | {{ form_rest(form.feed) }} |
149 | </form> | 147 | </form> |
150 | 148 | ||
151 | <h2>{{ 'config.tab_menu.user_info'|trans }}</h2> | 149 | <h2>{{ 'config.tab_menu.user_info'|trans }}</h2> |
152 | 150 | ||
153 | {{ form_start(form.user) }} | 151 | {{ form_start(form.user) }} |
154 | {{ form_errors(form.user) }} | 152 | {{ form_errors(form.user) }} |
153 | <fieldset class="w500p inline"> | ||
154 | <div class="row"> | ||
155 | <label>{{ 'config.form_user.login_label'|trans }}</label> | ||
156 | {{ app.user.username }} | ||
157 | </div> | ||
158 | </fieldset> | ||
155 | 159 | ||
156 | <fieldset class="w500p inline"> | 160 | <fieldset class="w500p inline"> |
157 | <div class="row"> | 161 | <div class="row"> |
@@ -169,52 +173,41 @@ | |||
169 | </div> | 173 | </div> |
170 | </fieldset> | 174 | </fieldset> |
171 | 175 | ||
176 | {{ form_widget(form.user.save) }} | ||
177 | |||
172 | {% if twofactor_auth %} | 178 | {% if twofactor_auth %} |
179 | <h5>{{ 'config.otp.page_title'|trans }}</h5> | ||
180 | |||
173 | <div class="row"> | 181 | <div class="row"> |
174 | {{ 'config.form_user.two_factor_description'|trans }} | 182 | {{ 'config.form_user.two_factor_description'|trans }} |
175 | </div> | 183 | </div> |
176 | 184 | ||
177 | <fieldset class="w500p inline"> | 185 | <table> |
178 | <div class="row"> | 186 | <thead> |
179 | {{ form_label(form.user.twoFactorAuthentication) }} | 187 | <tr> |
180 | {{ form_errors(form.user.twoFactorAuthentication) }} | 188 | <th>{{ 'config.form_user.two_factor.table_method'|trans }}</th> |
181 | {{ form_widget(form.user.twoFactorAuthentication) }} | 189 | <th>{{ 'config.form_user.two_factor.table_state'|trans }}</th> |
182 | </div> | 190 | <th>{{ 'config.form_user.two_factor.table_action'|trans }}</th> |
183 | <a href="#" title="{{ 'config.form_user.help_twoFactorAuthentication'|trans }}"> | 191 | </tr> |
184 | <i class="material-icons">live_help</i> | 192 | </thead> |
185 | </a> | ||
186 | </fieldset> | ||
187 | {% endif %} | ||
188 | 193 | ||
189 | <h2>{{ 'config.reset.title'|trans }}</h2> | 194 | <tbody> |
190 | <fieldset class="w500p inline"> | 195 | <tr> |
191 | <p>{{ 'config.reset.description'|trans }}</p> | 196 | <td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td> |
192 | <ul> | 197 | <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> | 198 | <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"> | 199 | </tr> |
195 | {{ 'config.reset.annotations'|trans }} | 200 | <tr> |
196 | </a> | 201 | <td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td> |
197 | </li> | 202 | <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> | 203 | <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"> | 204 | </tr> |
200 | {{ 'config.reset.tags'|trans }} | 205 | </tbody> |
201 | </a> | 206 | </table> |
202 | </li> | 207 | |
203 | <li> | 208 | {% 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 | 209 | ||
216 | {{ form_widget(form.user._token) }} | 210 | {{ form_widget(form.user._token) }} |
217 | {{ form_widget(form.user.save) }} | ||
218 | </form> | 211 | </form> |
219 | 212 | ||
220 | {% if enabled_users > 1 %} | 213 | {% if enabled_users > 1 %} |
@@ -277,7 +270,7 @@ | |||
277 | {% endfor %} | 270 | {% endfor %} |
278 | </ul> | 271 | </ul> |
279 | 272 | ||
280 | {{ form_start(form.new_tagging_rule) }} | 273 | {{ form_start(form.new_tagging_rule) }} |
281 | {{ form_errors(form.new_tagging_rule) }} | 274 | {{ form_errors(form.new_tagging_rule) }} |
282 | 275 | ||
283 | <fieldset class="w500p inline"> | 276 | <fieldset class="w500p inline"> |
@@ -298,6 +291,34 @@ | |||
298 | 291 | ||
299 | {{ form_rest(form.new_tagging_rule) }} | 292 | {{ form_rest(form.new_tagging_rule) }} |
300 | </form> | 293 | </form> |
294 | |||
295 | <div class="row"> | ||
296 | <h3>{{ 'config.form_rules.card.import_tagging_rules'|trans }}</h3> | ||
297 | <p>{{ 'config.form_rules.card.import_tagging_rules_detail'|trans }}</p> | ||
298 | </div> | ||
299 | |||
300 | {{ form_start(form.import_tagging_rule) }} | ||
301 | {{ form_errors(form.import_tagging_rule) }} | ||
302 | |||
303 | <fieldset class="w500p inline"> | ||
304 | <div class="row"> | ||
305 | {{ form_label(form.import_tagging_rule.file) }} | ||
306 | {{ form_errors(form.import_tagging_rule.file) }} | ||
307 | {{ form_widget(form.import_tagging_rule.file) }} | ||
308 | </div> | ||
309 | </fieldset> | ||
310 | |||
311 | {{ form_rest(form.import_tagging_rule) }} | ||
312 | </form> | ||
313 | |||
314 | {% if app.user.config.taggingRules is not empty %} | ||
315 | <div class="row"> | ||
316 | <h3>{{ 'config.form_rules.card.export_tagging_rules'|trans }}</h3> | ||
317 | <p>{{ 'config.form_rules.card.export_tagging_rules_detail'|trans }}</p> | ||
318 | <p><a href="{{ path('export_tagging_rule') }}" class="waves-effect waves-light btn">{{ 'config.form_rules.export'|trans }}</a></p> | ||
319 | </div> | ||
320 | {% endif %} | ||
321 | |||
301 | <div class="row"> | 322 | <div class="row"> |
302 | <div class="input-field col s12"> | 323 | <div class="input-field col s12"> |
303 | <h3>{{ 'config.form_rules.faq.title'|trans }}</h3> | 324 | <h3>{{ 'config.form_rules.faq.title'|trans }}</h3> |
@@ -382,4 +403,31 @@ | |||
382 | </table> | 403 | </table> |
383 | </div> | 404 | </div> |
384 | </div> | 405 | </div> |
406 | |||
407 | <h2>{{ 'config.reset.title'|trans }}</h2> | ||
408 | <fieldset class="w500p inline"> | ||
409 | <p>{{ 'config.reset.description'|trans }}</p> | ||
410 | <ul> | ||
411 | <li> | ||
412 | <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
413 | {{ 'config.reset.annotations'|trans }} | ||
414 | </a> | ||
415 | </li> | ||
416 | <li> | ||
417 | <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
418 | {{ 'config.reset.tags'|trans }} | ||
419 | </a> | ||
420 | </li> | ||
421 | <li> | ||
422 | <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
423 | {{ 'config.reset.archived'|trans }} | ||
424 | </a> | ||
425 | </li> | ||
426 | <li> | ||
427 | <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
428 | {{ 'config.reset.entries'|trans }} | ||
429 | </a> | ||
430 | </li> | ||
431 | </ul> | ||
432 | </fieldset> | ||
385 | {% endblock %} | 433 | {% 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..1d3685ae --- /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">{{ "auth_code"|trans({}, 'SchebTwoFactorBundle') }}</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 cfc6644b..b747ed84 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 | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | {% block head %} | 3 | {% block head %} |
4 | {{ parent() }} | 4 | {{ parent() }} |
5 | {% if tag is defined and app.user.config.rssToken %} | 5 | {% if tag is defined and app.user.config.feedToken %} |
6 | <link rel="alternate" type="application/rss+xml" href="{{ path('tag_rss', {'username': app.user.username, 'token': app.user.config.rssToken, 'slug': tag.slug}) }}" /> | 6 | <link rel="alternate" type="application/atom+xml" href="{{ path('tag_feed', {'username': app.user.username, 'token': app.user.config.feedToken, 'slug': tag.slug}) }}" /> |
7 | {% endif %} | 7 | {% endif %} |
8 | {% endblock %} | 8 | {% endblock %} |
9 | 9 | ||
@@ -20,13 +20,19 @@ | |||
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> |
26 | <div class="pagination"> | 29 | <div class="pagination"> |
27 | <a href="{{ path('switch_view_mode') }}"><i class="listMode-btn material-icons md-24">{% if listMode == 0 %}list{% else %}view_module{% endif %}</i></a> | 30 | <a href="{{ path('switch_view_mode') }}"><i class="listMode-btn material-icons md-24">{% if listMode == 0 %}list{% else %}view_module{% endif %}</i></a> |
28 | {% if app.user.config.rssToken %} | 31 | {% if app.user.config.feedToken %} |
29 | {% include "@WallabagCore/themes/common/Entry/_rss_link.html.twig" %} | 32 | {% include "@WallabagCore/themes/common/Entry/_feed_link.html.twig" %} |
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> | ||
30 | {% endif %} | 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> |
@@ -40,7 +46,7 @@ | |||
40 | <div id="entry-{{ entry.id|e }}" class="{% if listMode == 0 %}entry{% else %}listmode entry{% endif %}"> | 46 | <div id="entry-{{ entry.id|e }}" class="{% if listMode == 0 %}entry{% else %}listmode entry{% endif %}"> |
41 | <h2><a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title|e|raw }}">{{ entry.title | striptags | truncate(80, true, '…') | default('entry.default_title'|trans) | raw }}</a></h2> | 47 | <h2><a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title|e|raw }}">{{ entry.title | striptags | truncate(80, true, '…') | default('entry.default_title'|trans) | raw }}</a></h2> |
42 | 48 | ||
43 | {% set readingTime = entry.readingTime / app.user.config.readingSpeed %} | 49 | {% set readingTime = entry.readingTime / app.user.config.readingSpeed * 200 %} |
44 | <div class="estimatedTime"> | 50 | <div class="estimatedTime"> |
45 | <span class="tool reading-time"> | 51 | <span class="tool reading-time"> |
46 | {% if readingTime > 0 %} | 52 | {% if readingTime > 0 %} |
@@ -90,17 +96,14 @@ | |||
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">×</a> | 100 | <a href="javascript: void(null);" id="download-form-close" class="close-button--popup close-button">×</a> |
98 | <ul> | 101 | <ul> |
99 | {% 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 %} | 102 | {% 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 %} |
100 | {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %} | 103 | {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %} |
101 | {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %} | 104 | {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %} |
102 | {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %} | 105 | {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %} |
103 | {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %} | 106 | {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %} |
104 | {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %} | 107 | {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %} |
105 | {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %} | 108 | {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %} |
106 | </ul> | 109 | </ul> |
@@ -114,6 +117,12 @@ | |||
114 | <a href="javascript: void(null);" id="filter-form-close" class="close-button--popup close-button">×</a> | 117 | <a href="javascript: void(null);" id="filter-form-close" class="close-button--popup close-button">×</a> |
115 | 118 | ||
116 | <div id="filter-status" class="filter-group"> | 119 | <div id="filter-status" class="filter-group"> |
120 | {% if currentRoute != 'untagged' and nbEntriesUntagged != 0 %} | ||
121 | <div class=""> | ||
122 | <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }} ({{nbEntriesUntagged}})</a> | ||
123 | </div> | ||
124 | {% endif %} | ||
125 | |||
117 | <div class=""> | 126 | <div class=""> |
118 | <label>{{ 'entry.filters.status_label'|trans }}</label> | 127 | <label>{{ 'entry.filters.status_label'|trans }}</label> |
119 | </div> | 128 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig index e7d42b3d..c2e69a27 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig | |||
@@ -5,7 +5,7 @@ | |||
5 | {% block content %} | 5 | {% block content %} |
6 | <div id="article"> | 6 | <div id="article"> |
7 | <header class="mbm"> | 7 | <header class="mbm"> |
8 | <h1>{{ entry.title|e|default('entry.default_title'|trans)|raw }} <a href="{{ path('edit', { 'id': entry.id }) }}" class="nostyle" title="{{ 'entry.view.edit_title'|trans }}">✎</a></h1> | 8 | <h1><span{% if entry.language is defined and entry.language is not null %} lang="{{ entry.getHTMLLanguage() }}"{% endif %}>{{ entry.title|e|default('entry.default_title'|trans)|raw }}</span> <a href="{{ path('edit', { 'id': entry.id }) }}" class="nostyle" title="{{ 'entry.view.edit_title'|trans }}">✎</a></h1> |
9 | </header> | 9 | </header> |
10 | 10 | ||
11 | <div id="article_toolbar"> | 11 | <div id="article_toolbar"> |
@@ -27,7 +27,7 @@ | |||
27 | <li><a href="{{ path('share', {'id': entry.id }) }}" target="_blank" class="tool icon icon-eye" title="{{ 'entry.view.left_menu.public_link'|trans }}"><span>{{ 'entry.view.left_menu.public_link'|trans }}</span></a></li> | 27 | <li><a href="{{ path('share', {'id': entry.id }) }}" target="_blank" class="tool icon icon-eye" title="{{ 'entry.view.left_menu.public_link'|trans }}"><span>{{ 'entry.view.left_menu.public_link'|trans }}</span></a></li> |
28 | <li><a href="{{ path('delete_share', {'id': entry.id }) }}" class="tool icon icon-no-eye" title="{{ 'entry.view.left_menu.delete_public_link'|trans }}"><span>{{ 'entry.view.left_menu.delete_public_link'|trans }}</span></a></li> | 28 | <li><a href="{{ path('delete_share', {'id': entry.id }) }}" class="tool icon icon-no-eye" title="{{ 'entry.view.left_menu.delete_public_link'|trans }}"><span>{{ 'entry.view.left_menu.delete_public_link'|trans }}</span></a></li> |
29 | {% endif %} | 29 | {% endif %} |
30 | {% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" rel="noopener" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %} | 30 | {% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/share?text={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" rel="noopener" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %} |
31 | {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %} | 31 | {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %} |
32 | {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&tags={{ entry.tags|join(',')|url_encode }}{% if craue_setting('shaarli_share_origin_url') %}&original_url={{ entry.originUrl|url_encode }}{% endif %}" target="_blank" rel="noopener" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %} | 32 | {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&tags={{ entry.tags|join(',')|url_encode }}{% if craue_setting('shaarli_share_origin_url') %}&original_url={{ entry.originUrl|url_encode }}{% endif %}" target="_blank" rel="noopener" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %} |
33 | {% if craue_setting('share_scuttle') %}<li><a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&address={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&tags={{ entry.tags|join(',')|url_encode }}" target="_blank" rel="noopener" class="tool icon-image icon-image--scuttle" title="scuttle"><span>scuttle</span></a></li>{% endif %} | 33 | {% if craue_setting('share_scuttle') %}<li><a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&address={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&tags={{ entry.tags|join(',')|url_encode }}" target="_blank" rel="noopener" class="tool icon-image icon-image--scuttle" title="scuttle"><span>scuttle</span></a></li>{% endif %} |
@@ -38,7 +38,7 @@ | |||
38 | {% if craue_setting('export_epub') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'epub' }) }}" title="Generate ePub file">EPUB</a></li>{% endif %} | 38 | {% if craue_setting('export_epub') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'epub' }) }}" title="Generate ePub file">EPUB</a></li>{% endif %} |
39 | {% if craue_setting('export_mobi') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'mobi' }) }}" title="Generate Mobi file">MOBI</a></li>{% endif %} | 39 | {% if craue_setting('export_mobi') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'mobi' }) }}" title="Generate Mobi file">MOBI</a></li>{% endif %} |
40 | {% if craue_setting('export_pdf') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'pdf' }) }}" title="Generate PDF file">PDF</a></li>{% endif %} | 40 | {% if craue_setting('export_pdf') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'pdf' }) }}" title="Generate PDF file">PDF</a></li>{% endif %} |
41 | <li><a href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.label'|trans }}" class="tool bad-display icon icon-delete"><span>{{ 'entry.view.left_menu.problem.label'|trans }}</span></a></li> | 41 | <li><a href="mailto:siteconfig@wallabag.org?subject=Wrong%20display%20in%20wallabag&body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.label'|trans }}" class="tool bad-display icon icon-delete"><span>{{ 'entry.view.left_menu.problem.label'|trans }}</span></a></li> |
42 | </ul> | 42 | </ul> |
43 | </div> | 43 | </div> |
44 | 44 | ||
@@ -62,7 +62,7 @@ | |||
62 | {% endif %} | 62 | {% endif %} |
63 | 63 | ||
64 | <i class="tool icon icon-time"> | 64 | <i class="tool icon icon-time"> |
65 | {% set readingTime = entry.readingTime / app.user.config.readingSpeed %} | 65 | {% set readingTime = entry.readingTime / app.user.config.readingSpeed * 200 %} |
66 | {% if readingTime > 0 %} | 66 | {% if readingTime > 0 %} |
67 | {{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }} | 67 | {{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }} |
68 | {% else %} | 68 | {% else %} |
@@ -70,7 +70,7 @@ | |||
70 | {% endif %} | 70 | {% endif %} |
71 | </i> | 71 | </i> |
72 | 72 | ||
73 | <span class="tool link"><i class="material-icons link">comment</i> {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span> | 73 | <span class="tool link"><i class="material-icons">comment</i> {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span> |
74 | 74 | ||
75 | {% if entry.originUrl is not empty %} | 75 | {% if entry.originUrl is not empty %} |
76 | <i class="material-icons" title="{{ 'entry.view.provided_by'|trans }}">launch</i> | 76 | <i class="material-icons" title="{{ 'entry.view.provided_by'|trans }}">launch</i> |
@@ -96,7 +96,7 @@ | |||
96 | </div> | 96 | </div> |
97 | </aside> | 97 | </aside> |
98 | </div> | 98 | </div> |
99 | <article> | 99 | <article{% if entry.language is defined and entry.language is not null %} lang="{{ entry.getHTMLLanguage() }}"{% endif %}> |
100 | {{ entry.content | raw }} | 100 | {{ entry.content | raw }} |
101 | </article> | 101 | </article> |
102 | </div> | 102 | </div> |
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..aa17b842 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,15 +10,31 @@ | |||
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 }} ({{ 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.feedToken %} | ||
25 | <a rel="alternate" type="application/atom+xml" href="{{ path('tag_feed', {'username': app.user.username, 'token': app.user.config.feedToken, '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> |
20 | 32 | ||
21 | <div> | 33 | <div> |
22 | <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }}</a> | 34 | {% if nbEntriesUntagged == 0 %} |
35 | {{ 'tag.list.no_untagged_entries'|trans }} | ||
36 | {% else %} | ||
37 | <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }} ({{nbEntriesUntagged}})</a> | ||
38 | {% endif %} | ||
23 | </div> | 39 | </div> |
24 | {% endblock %} | 40 | {% endblock %} |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig index 35a54daf..6b1e2bd7 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig | |||
@@ -50,6 +50,7 @@ | |||
50 | <li class="menu howto"><a href="{{ path('howto') }}">{{ 'menu.left.howto'|trans }}</a></li> | 50 | <li class="menu howto"><a href="{{ path('howto') }}">{{ 'menu.left.howto'|trans }}</a></li> |
51 | <li class="menu developer"><a href="{{ path('developer') }}">{{ 'menu.left.developer'|trans }}</a></li> | 51 | <li class="menu developer"><a href="{{ path('developer') }}">{{ 'menu.left.developer'|trans }}</a></li> |
52 | <li class="menu about"><a href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans }}</a></li> | 52 | <li class="menu about"><a href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans }}</a></li> |
53 | <li class="menu quickstart"><a href="{{ path('quickstart') }}">{{ 'menu.left.quickstart'|trans }}</a></li> | ||
53 | <li class="menu logout"><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}">{{ 'menu.left.logout'|trans }}</a></li> | 54 | <li class="menu logout"><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}">{{ 'menu.left.logout'|trans }}</a></li> |
54 | </ul> | 55 | </ul> |
55 | {% endblock %} | 56 | {% endblock %} |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client_parameters.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client_parameters.html.twig index b498cceb..3a3ba0c9 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client_parameters.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client_parameters.html.twig | |||
@@ -8,11 +8,29 @@ | |||
8 | <div class="card-panel settings"> | 8 | <div class="card-panel settings"> |
9 | <div class="row"> | 9 | <div class="row"> |
10 | <p>{{ 'developer.client_parameter.page_description'|trans }}</p> | 10 | <p>{{ 'developer.client_parameter.page_description'|trans }}</p> |
11 | <ul> | 11 | |
12 | <li>{{ 'developer.client_parameter.field_name'|trans }}: <strong><pre>{{ client_name }}</pre></strong></li> | 12 | <table class="striped"> |
13 | <li>{{ 'developer.client_parameter.field_id'|trans }}: <strong><pre>{{ client_id }}</pre></strong></li> | 13 | <tr> |
14 | <li>{{ 'developer.client_parameter.field_secret'|trans }}: <strong><pre>{{ client_secret }}</pre></strong></li> | 14 | <td>{{ 'developer.client_parameter.field_name'|trans }}</td> |
15 | </ul> | 15 | <td><strong><code>{{ client_name }}</code></strong></td> |
16 | </tr> | ||
17 | <tr> | ||
18 | <td>{{ 'developer.client_parameter.field_id'|trans }}</td> | ||
19 | <td> | ||
20 | <strong><code>{{ client_id }}</code></strong> | ||
21 | <button class="btn" data-clipboard-text="{{ client_id }}">{{ 'developer.client.copy_to_clipboard'|trans }}</button> | ||
22 | </td> | ||
23 | </tr> | ||
24 | <tr> | ||
25 | <td>{{ 'developer.client_parameter.field_secret'|trans }}</td> | ||
26 | <td> | ||
27 | <strong><code>{{ client_secret }}</code></strong> | ||
28 | <button class="btn" data-clipboard-text="{{ client_secret }}">{{ 'developer.client.copy_to_clipboard'|trans }}</button> | ||
29 | </td> | ||
30 | </tr> | ||
31 | </table> | ||
32 | |||
33 | <br/> | ||
16 | 34 | ||
17 | <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{{ 'developer.client_parameter.back'|trans }}</a> | 35 | <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{{ 'developer.client_parameter.back'|trans }}</a> |
18 | <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{{ 'developer.client_parameter.read_howto'|trans }}</a> | 36 | <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{{ 'developer.client_parameter.read_howto'|trans }}</a> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/howto_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/howto_app.html.twig index acbc2c88..dcadfa49 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/howto_app.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/howto_app.html.twig | |||
@@ -18,7 +18,7 @@ | |||
18 | <p>{{ 'developer.howto.description.paragraph_3'|trans({'%link%': path('developer_create_client')})|raw }}</p> | 18 | <p>{{ 'developer.howto.description.paragraph_3'|trans({'%link%': path('developer_create_client')})|raw }}</p> |
19 | <p>{{ 'developer.howto.description.paragraph_4'|trans }}</p> | 19 | <p>{{ 'developer.howto.description.paragraph_4'|trans }}</p> |
20 | <p> | 20 | <p> |
21 | <pre><code class="language-bash">http POST http://v2.wallabag.org/oauth/v2/token \ | 21 | <pre><code class="language-bash">http POST https://app.wallabag.it/oauth/v2/token \ |
22 | grant_type=password \ | 22 | grant_type=password \ |
23 | client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \ | 23 | client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \ |
24 | client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \ | 24 | client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \ |
@@ -47,7 +47,7 @@ X-Powered-By: PHP/5.5.9-1ubuntu4.13 | |||
47 | </p> | 47 | </p> |
48 | <p>{{ 'developer.howto.description.paragraph_6'|trans }}</p> | 48 | <p>{{ 'developer.howto.description.paragraph_6'|trans }}</p> |
49 | <p> | 49 | <p> |
50 | <pre><code class="language-bash">http GET http://v2.wallabag.org/api/entries.json \ | 50 | <pre><code class="language-bash">http GET https://app.wallabag.it/api/entries.json \ |
51 | "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre> | 51 | "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre> |
52 | </p> | 52 | </p> |
53 | <p>{{ 'developer.howto.description.paragraph_7'|trans }}</p> | 53 | <p>{{ 'developer.howto.description.paragraph_7'|trans }}</p> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig index be04cddb..b83bf96f 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig | |||
@@ -33,11 +33,17 @@ | |||
33 | <table class="striped"> | 33 | <table class="striped"> |
34 | <tr> | 34 | <tr> |
35 | <td>{{ 'developer.existing_clients.field_id'|trans }}</td> | 35 | <td>{{ 'developer.existing_clients.field_id'|trans }}</td> |
36 | <td><strong><code>{{ client.clientId }}</code></strong></td> | 36 | <td> |
37 | <strong><code>{{ client.clientId }}</code></strong> | ||
38 | <button class="btn" data-clipboard-text="{{ client.clientId }}">{{ 'developer.client.copy_to_clipboard'|trans }}</button> | ||
39 | </td> | ||
37 | </tr> | 40 | </tr> |
38 | <tr> | 41 | <tr> |
39 | <td>{{ 'developer.existing_clients.field_secret'|trans }}</td> | 42 | <td>{{ 'developer.existing_clients.field_secret'|trans }}</td> |
40 | <td><strong><code>{{ client.secret }}</code></strong></td> | 43 | <td> |
44 | <strong><code>{{ client.secret }}</code></strong> | ||
45 | <button class="btn" data-clipboard-text="{{ client.secret }}">{{ 'developer.client.copy_to_clipboard'|trans }}</button> | ||
46 | </td> | ||
41 | </tr> | 47 | </tr> |
42 | <tr> | 48 | <tr> |
43 | <td>{{ 'developer.existing_clients.field_uris'|trans }}</td> | 49 | <td>{{ 'developer.existing_clients.field_uris'|trans }}</td> |
@@ -48,9 +54,10 @@ | |||
48 | <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td> | 54 | <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td> |
49 | </tr> | 55 | </tr> |
50 | </table> | 56 | </table> |
57 | |||
58 | <p>{{ 'developer.remove.warn_message_1'|trans({'%name%': client.name }) }}</p> | ||
59 | <p>{{ 'developer.remove.warn_message_2'|trans({'%name%': client.name }) }}</p> | ||
51 | <p> | 60 | <p> |
52 | {{ 'developer.remove.warn_message_1'|trans({'%name%': client.name }) }}<br/> | ||
53 | {{ 'developer.remove.warn_message_2'|trans({'%name%': client.name }) }}<br/> | ||
54 | <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{{ 'developer.remove.action'|trans({'%name%': client.name }) }}</a> | 61 | <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{{ 'developer.remove.action'|trans({'%name%': client.name }) }}</a> |
55 | </p> | 62 | </p> |
56 | </div> | 63 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_feed_link.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_feed_link.html.twig new file mode 100644 index 00000000..6df4c160 --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_feed_link.html.twig | |||
@@ -0,0 +1,11 @@ | |||
1 | {% if tag is defined %} | ||
2 | <a rel="alternate" type="application/atom+xml" href="{{ path('tag_feed', {'username': app.user.username, 'token': app.user.config.feedToken, 'slug': tag.slug}) }}" class="right"><i class="material-icons md-24">rss_feed</i></a> | ||
3 | {% elseif currentRoute in ['homepage', 'unread', 'starred', 'archive', 'all'] %} | ||
4 | {% set feedRoute = currentRoute %} | ||
5 | {% if currentRoute == 'homepage' %} | ||
6 | {% set feedRoute = 'unread' %} | ||
7 | {% endif %} | ||
8 | {% set feedRoute = feedRoute ~ '_feed' %} | ||
9 | |||
10 | <a rel="alternate" type="application/atom+xml" href="{{ path(feedRoute, {'username': app.user.username, 'token': app.user.config.feedToken}) }}" class="right"><i class="material-icons">rss_feed</i></a> | ||
11 | {% endif %} | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_rss_link.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_rss_link.html.twig deleted file mode 100644 index eb26054c..00000000 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_rss_link.html.twig +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | {% if tag is defined %} | ||
2 | <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"><i class="material-icons md-24">rss_feed</i></a> | ||
3 | {% elseif currentRoute in ['homepage', 'unread', 'starred', 'archive', 'all'] %} | ||
4 | {% set rssRoute = currentRoute %} | ||
5 | {% if currentRoute == 'homepage' %} | ||
6 | {% set rssRoute = 'unread' %} | ||
7 | {% endif %} | ||
8 | {% set rssRoute = rssRoute ~ '_rss' %} | ||
9 | |||
10 | <a rel="alternate" type="application/rss+xml" href="{{ path(rssRoute, {'username': app.user.username, 'token': app.user.config.rssToken}) }}" class="right"><i class="material-icons">rss_feed</i></a> | ||
11 | {% endif %} | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig index 25d09ec3..cf6f6571 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig | |||
@@ -1,34 +1,53 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
2 | <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"> | 2 | <feed xmlns="http://www.w3.org/2005/Atom"> |
3 | <channel> | 3 | {% if type != 'tag' %} |
4 | <title>wallabag - {{ type }} feed</title> | 4 | <title>wallabag — {{type}} feed</title> |
5 | <link>{{ url_html }}</link> | 5 | <subtitle type="html">Atom feed for {{ type }} entries</subtitle> |
6 | <link rel="self" href="{{ app.request.uri }}"/> | 6 | <id>wallabag:{{ domainName | removeScheme | removeWww }}:{{ user }}:{{ type }}</id> |
7 | {% if entries.hasPreviousPage -%} | 7 | <link rel="alternate" type="text/html" href="{{ url(type) }}"/> |
8 | <link rel="previous" href="{{ url }}?page={{ entries.previousPage }}"/> | 8 | {% else %} |
9 | {% endif -%} | 9 | <id>wallabag:{{ domainName | removeScheme | removeWww }}:{{ user }}:{{ type }}:{{ tag }}</id> |
10 | {% if entries.hasNextPage -%} | 10 | <link rel="alternate" type="text/html" href="{{ url('tag_entries', {'slug': tag}) }}"/> |
11 | <link rel="next" href="{{ url }}?page={{ entries.nextPage }}"/> | 11 | <title>wallabag — {{type}} {{ tag }} feed</title> |
12 | {% endif -%} | 12 | <subtitle type="html">Atom feed for entries tagged with {{ tag }}</subtitle> |
13 | <link rel="last" href="{{ url }}?page={{ entries.nbPages }}"/> | 13 | {% endif %} |
14 | <pubDate>{{ "now"|date(constant('DATE_RSS')) }}</pubDate> | 14 | {% if entries | length > 0 %} |
15 | <generator>wallabag</generator> | 15 | <updated>{{ (entries | first).createdAt | date('c') }}</updated> {# Indicates the last time the feed was modified in a significant way. #} |
16 | <description>wallabag {{ type }} elements</description> | 16 | {% endif %} |
17 | 17 | <link rel="self" type="application/atom+xml" href="{{ app.request.uri }}"/> | |
18 | {% for entry in entries %} | 18 | {% if entries.hasPreviousPage %} |
19 | 19 | <link rel="previous" href="{{ url }}/{{ entries.previousPage }}"/> | |
20 | <item> | 20 | {% endif -%} |
21 | <title><![CDATA[{{ entry.title|e }}]]></title> | 21 | {% if entries.hasNextPage %} |
22 | <source url="{{ url('view', { 'id': entry.id }) }}">wallabag</source> | 22 | <link rel="next" href="{{ url }}/{{ entries.nextPage }}"/> |
23 | <link>{{ entry.url }}</link> | 23 | {% endif -%} |
24 | <guid>{{ entry.url }}</guid> | 24 | <link rel="last" href="{{ url }}/{{ entries.nbPages }}"/> |
25 | <pubDate>{{ entry.createdAt|date(constant('DATE_RSS')) }}</pubDate> | 25 | <generator uri="https://wallabag.org" version="{{ version }}">wallabag</generator> |
26 | <description> | 26 | <author> |
27 | <![CDATA[{%- if entry.readingTime > 0 -%}{{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': entry.readingTime}) }}{%- else -%}{{ 'entry.list.reading_time_less_one_minute'|trans|raw }}{%- endif %}{{ entry.content|raw -}}]]> | 27 | <name>{{ user }}</name> |
28 | </description> | 28 | </author> |
29 | </item> | 29 | <icon>{{ asset('favicon.ico') }}</icon> |
30 | 30 | <logo>{{ asset('bundles/wallabagcore/themes/_global/img/logo-square.png') }}</logo> | |
31 | {% for entry in entries %} | ||
32 | <entry> | ||
33 | <title><![CDATA[{{ entry.title|e }}]]></title> | ||
34 | <link rel="alternate" type="text/html" | ||
35 | href="{{ url('view', {'id': entry.id}) }}"/> | ||
36 | <link rel="via">{{ entry.url }}</link> | ||
37 | <id>wallabag:{{ domainName | removeScheme | removeWww }}:{{ user }}:entry:{{ entry.id }}</id> | ||
38 | <updated>{{ entry.updatedAt|date('c') }}</updated> | ||
39 | <published>{{ entry.createdAt|date('c') }}</published> | ||
40 | {% for tag in entry.tags %} | ||
41 | <category term="{{ tag.slug }}" label="{{ tag.label }}" /> | ||
31 | {% endfor %} | 42 | {% endfor %} |
32 | 43 | {% for author in entry.publishedBy %} | |
33 | </channel> | 44 | <author> |
34 | </rss> | 45 | <name>{{ author }}</name> |
46 | </author> | ||
47 | {% endfor %} | ||
48 | <content type="html" {% if entry.language %}xml:lang="{{ entry.language[:2] }}"{% endif %}> | ||
49 | <![CDATA[{%- if entry.readingTime > 0 -%}{{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': entry.readingTime}) }}{%- else -%}{{ 'entry.list.reading_time_less_one_minute'|trans|raw }}{%- endif %}{{ entry.content|raw -}}]]> | ||
50 | </content> | ||
51 | </entry> | ||
52 | {% endfor %} | ||
53 | </feed> | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/share.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/share.html.twig index e1c7aad9..4294a60d 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/share.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/share.html.twig | |||
@@ -29,9 +29,6 @@ | |||
29 | <h1>{{ entry.title|e|raw }}</h1> | 29 | <h1>{{ entry.title|e|raw }}</h1> |
30 | <a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e|raw }}" class="tool">{{ entry.domainName|removeWww }}</a> | 30 | <a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e|raw }}" class="tool">{{ entry.domainName|removeWww }}</a> |
31 | <p class="shared-by">{{ "entry.public.shared_by_wallabag"|trans({'%wallabag_instance%': url('homepage'), '%username%': entry.user.username})|raw }}.</p> | 31 | <p class="shared-by">{{ "entry.public.shared_by_wallabag"|trans({'%wallabag_instance%': url('homepage'), '%username%': entry.user.username})|raw }}.</p> |
32 | {% if entry.previewPicture is not null %} | ||
33 | <img class="preview" src="{{ entry.previewPicture }}" alt="{{ entry.title|striptags|e('html_attr') }}" /> | ||
34 | {% endif %} | ||
35 | </header> | 32 | </header> |
36 | <article class="block"> | 33 | <article class="block"> |
37 | {{ entry.content | raw }} | 34 | {{ entry.content | raw }} |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig index 4580813c..521b3eea 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig | |||
@@ -21,7 +21,7 @@ | |||
21 | <div class="card-action"> | 21 | <div class="card-action"> |
22 | <ul> | 22 | <ul> |
23 | <li><a href="{{ path('config') }}">{{ 'quickstart.configure.language'|trans }}</a></li> | 23 | <li><a href="{{ path('config') }}">{{ 'quickstart.configure.language'|trans }}</a></li> |
24 | <li><a href="{{ path('config') }}#set2">{{ 'quickstart.configure.rss'|trans }}</a></li> | 24 | <li><a href="{{ path('config') }}#set2">{{ 'quickstart.configure.feed'|trans }}</a></li> |
25 | <li><a href="{{ path('config') }}#set5">{{ 'quickstart.more'|trans }}</a></li> | 25 | <li><a href="{{ path('config') }}#set5">{{ 'quickstart.more'|trans }}</a></li> |
26 | </ul> | 26 | </ul> |
27 | </div> | 27 | </div> |
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..d8e9694d 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 | |||
@@ -12,10 +12,11 @@ | |||
12 | <div class="div_tabs col s12"> | 12 | <div class="div_tabs col s12"> |
13 | <ul class="tabs"> | 13 | <ul class="tabs"> |
14 | <li class="tab col s12 m6 l3"><a class="active" href="#set1">{{ 'config.tab_menu.settings'|trans }}</a></li> | 14 | <li class="tab col s12 m6 l3"><a class="active" href="#set1">{{ 'config.tab_menu.settings'|trans }}</a></li> |
15 | <li class="tab col s12 m6 l3"><a href="#set2">{{ 'config.tab_menu.rss'|trans }}</a></li> | 15 | <li class="tab col s12 m6 l3"><a href="#set2">{{ 'config.tab_menu.feed'|trans }}</a></li> |
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 | ||
@@ -122,42 +122,43 @@ | |||
122 | </div> | 122 | </div> |
123 | 123 | ||
124 | <div id="set2" class="col s12"> | 124 | <div id="set2" class="col s12"> |
125 | {{ form_start(form.rss) }} | 125 | {{ form_start(form.feed) }} |
126 | {{ form_errors(form.rss) }} | 126 | {{ form_errors(form.feed) }} |
127 | 127 | ||
128 | <div class="row"> | 128 | <div class="row"> |
129 | <div class="input-field col s12"> | 129 | <div class="input-field col s12"> |
130 | {{ 'config.form_rss.description'|trans }} | 130 | {{ 'config.form_feed.description'|trans }} |
131 | </div> | 131 | </div> |
132 | </div> | 132 | </div> |
133 | 133 | ||
134 | <div class="row"> | 134 | <div class="row"> |
135 | <div class="col s12"> | 135 | <div class="col s12"> |
136 | <h6 class="grey-text">{{ 'config.form_rss.token_label'|trans }}</h6> | 136 | <h6 class="grey-text">{{ 'config.form_feed.token_label'|trans }}</h6> |
137 | <div> | 137 | <div> |
138 | {% if rss.token %} | 138 | {% if feed.token %} |
139 | {{ rss.token }} | 139 | {{ feed.token }} |
140 | {% else %} | 140 | {% else %} |
141 | <em>{{ 'config.form_rss.no_token'|trans }}</em> | 141 | <em>{{ 'config.form_feed.no_token'|trans }}</em> |
142 | {% endif %} | 142 | {% endif %} |
143 | – <a href="{{ path('generate_token') }}"> | 143 | |
144 | {% if rss.token %} | 144 | {% if feed.token %} |
145 | {{ 'config.form_rss.token_reset'|trans }} | 145 | – <a href="{{ path('generate_token') }}">{{ 'config.form_feed.token_reset'|trans }}</a> |
146 | – <a href="{{ path('revoke_token') }}">{{ 'config.form_feed.token_revoke'|trans }}</a> | ||
146 | {% else %} | 147 | {% else %} |
147 | {{ 'config.form_rss.token_create'|trans }} | 148 | – <a href="{{ path('generate_token') }}">{{ 'config.form_feed.token_create'|trans }}</a> |
148 | {% endif %}</a> | 149 | {% endif %} |
149 | </div> | 150 | </div> |
150 | </div> | 151 | </div> |
151 | </div> | 152 | </div> |
152 | {% if rss.token %} | 153 | {% if feed.token %} |
153 | <div class="row"> | 154 | <div class="row"> |
154 | <div class="col s12"> | 155 | <div class="col s12"> |
155 | <h6 class="grey-text">{{ 'config.form_rss.rss_links'|trans }}</h6> | 156 | <h6 class="grey-text">{{ 'config.form_feed.feed_links'|trans }}</h6> |
156 | <ul> | 157 | <ul> |
157 | <li><a href="{{ path('unread_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.unread'|trans }}</a></li> | 158 | <li><a href="{{ path('unread_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.unread'|trans }}</a></li> |
158 | <li><a href="{{ path('starred_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.starred'|trans }}</a></li> | 159 | <li><a href="{{ path('starred_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.starred'|trans }}</a></li> |
159 | <li><a href="{{ path('archive_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.archive'|trans }}</a></li> | 160 | <li><a href="{{ path('archive_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.archive'|trans }}</a></li> |
160 | <li><a href="{{ path('all_rss', {'username': rss.username, 'token': rss.token}) }}">{{ 'config.form_rss.rss_link.all'|trans }}</a></li> | 161 | <li><a href="{{ path('all_feed', {'username': feed.username, 'token': feed.token}) }}">{{ 'config.form_feed.feed_link.all'|trans }}</a></li> |
161 | </ul> | 162 | </ul> |
162 | </div> | 163 | </div> |
163 | </div> | 164 | </div> |
@@ -165,14 +166,14 @@ | |||
165 | 166 | ||
166 | <div class="row"> | 167 | <div class="row"> |
167 | <div class="input-field col s12"> | 168 | <div class="input-field col s12"> |
168 | {{ form_label(form.rss.rss_limit) }} | 169 | {{ form_label(form.feed.feed_limit) }} |
169 | {{ form_errors(form.rss.rss_limit) }} | 170 | {{ form_errors(form.feed.feed_limit) }} |
170 | {{ form_widget(form.rss.rss_limit) }} | 171 | {{ form_widget(form.feed.feed_limit) }} |
171 | </div> | 172 | </div> |
172 | </div> | 173 | </div> |
173 | 174 | ||
174 | {{ form_widget(form.rss.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} | 175 | {{ form_widget(form.feed.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} |
175 | {{ form_rest(form.rss) }} | 176 | {{ form_rest(form.feed) }} |
176 | </form> | 177 | </form> |
177 | </div> | 178 | </div> |
178 | 179 | ||
@@ -181,6 +182,15 @@ | |||
181 | {{ form_errors(form.user) }} | 182 | {{ form_errors(form.user) }} |
182 | 183 | ||
183 | <div class="row"> | 184 | <div class="row"> |
185 | <div class="col s12"> | ||
186 | <h6 class="grey-text">{{ 'config.form_user.login_label'|trans }}</h6> | ||
187 | <div> | ||
188 | {{ app.user.username }} | ||
189 | </div> | ||
190 | </div> | ||
191 | </div> | ||
192 | |||
193 | <div class="row"> | ||
184 | <div class="input-field col s12"> | 194 | <div class="input-field col s12"> |
185 | {{ form_label(form.user.name) }} | 195 | {{ form_label(form.user.name) }} |
186 | {{ form_errors(form.user.name) }} | 196 | {{ form_errors(form.user.name) }} |
@@ -196,59 +206,42 @@ | |||
196 | </div> | 206 | </div> |
197 | </div> | 207 | </div> |
198 | 208 | ||
199 | {% if twofactor_auth %} | 209 | {{ 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 | 210 | ||
206 | {{ form_widget(form.user.twoFactorAuthentication) }} | 211 | {% if twofactor_auth %} |
207 | {{ form_label(form.user.twoFactorAuthentication) }} | 212 | <br/> |
208 | {{ form_errors(form.user.twoFactorAuthentication) }} | 213 | <br/> |
209 | </div> | 214 | <div class="row"> |
210 | <div class="input-field col s1"> | 215 | <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 }}"> | 216 | |
212 | <i class="material-icons">live_help</i> | 217 | <p>{{ 'config.form_user.two_factor_description'|trans }}</p> |
213 | </a> | 218 | |
219 | <table> | ||
220 | <thead> | ||
221 | <tr> | ||
222 | <th>{{ 'config.form_user.two_factor.table_method'|trans }}</th> | ||
223 | <th>{{ 'config.form_user.two_factor.table_state'|trans }}</th> | ||
224 | <th>{{ 'config.form_user.two_factor.table_action'|trans }}</th> | ||
225 | </tr> | ||
226 | </thead> | ||
227 | |||
228 | <tbody> | ||
229 | <tr> | ||
230 | <td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td> | ||
231 | <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> | ||
232 | <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> | ||
233 | </tr> | ||
234 | <tr> | ||
235 | <td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td> | ||
236 | <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> | ||
237 | <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> | ||
238 | </tr> | ||
239 | </tbody> | ||
240 | </table> | ||
214 | </div> | 241 | </div> |
215 | </div> | ||
216 | {% endif %} | 242 | {% endif %} |
217 | |||
218 | {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} | ||
219 | {{ form_widget(form.user._token) }} | 243 | {{ form_widget(form.user._token) }} |
220 | </form> | 244 | </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> | 245 | </div> |
253 | 246 | ||
254 | <div id="set4" class="col s12"> | 247 | <div id="set4" class="col s12"> |
@@ -314,28 +307,77 @@ | |||
314 | </div> | 307 | </div> |
315 | {% endif %} | 308 | {% endif %} |
316 | 309 | ||
317 | {{ form_start(form.new_tagging_rule) }} | 310 | <ul class="row"> |
318 | {{ form_errors(form.new_tagging_rule) }} | 311 | <li class="col l6 m6 s12"> |
319 | 312 | <div class="card"> | |
320 | <div class="row"> | 313 | <div class="card-content"> |
321 | <div class="input-field col s12"> | 314 | <span class="card-title">{{ 'config.form_rules.card.new_tagging_rule'|trans }}</span> |
322 | {{ form_label(form.new_tagging_rule.rule) }} | 315 | |
323 | {{ form_errors(form.new_tagging_rule.rule) }} | 316 | {{ form_start(form.new_tagging_rule) }} |
324 | {{ form_widget(form.new_tagging_rule.rule) }} | 317 | {{ form_errors(form.new_tagging_rule) }} |
318 | |||
319 | <div class="row"> | ||
320 | <div class="input-field col s12"> | ||
321 | {{ form_label(form.new_tagging_rule.rule) }} | ||
322 | {{ form_errors(form.new_tagging_rule.rule) }} | ||
323 | {{ form_widget(form.new_tagging_rule.rule) }} | ||
324 | </div> | ||
325 | </div> | ||
326 | |||
327 | <div class="row"> | ||
328 | <div class="input-field col s12"> | ||
329 | {{ form_label(form.new_tagging_rule.tags) }} | ||
330 | {{ form_errors(form.new_tagging_rule.tags) }} | ||
331 | {{ form_widget(form.new_tagging_rule.tags) }} | ||
332 | </div> | ||
333 | </div> | ||
334 | |||
335 | {{ form_widget(form.new_tagging_rule.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} | ||
336 | {{ form_rest(form.new_tagging_rule) }} | ||
337 | </form> | ||
338 | </div> | ||
325 | </div> | 339 | </div> |
326 | </div> | 340 | </li> |
327 | 341 | <li class="col l6 m6 s12"> | |
328 | <div class="row"> | 342 | <div class="card z-depth-1"> |
329 | <div class="input-field col s12"> | 343 | <div class="card-content"> |
330 | {{ form_label(form.new_tagging_rule.tags) }} | 344 | <span class="card-title">{{ 'config.form_rules.card.import_tagging_rules'|trans }}</span> |
331 | {{ form_errors(form.new_tagging_rule.tags) }} | 345 | <p>{{ 'config.form_rules.card.import_tagging_rules_detail'|trans }}</p> |
332 | {{ form_widget(form.new_tagging_rule.tags) }} | 346 | {{ form_start(form.import_tagging_rule) }} |
347 | {{ form_errors(form.import_tagging_rule) }} | ||
348 | <div class="row"> | ||
349 | <div class="file-field input-field col s12"> | ||
350 | {{ form_errors(form.import_tagging_rule.file) }} | ||
351 | <div class="btn"> | ||
352 | <span>{{ form.import_tagging_rule.file.vars.label|trans }}</span> | ||
353 | {{ form_widget(form.import_tagging_rule.file) }} | ||
354 | </div> | ||
355 | <div class="file-path-wrapper"> | ||
356 | <input class="file-path validate" type="text"> | ||
357 | </div> | ||
358 | </div> | ||
359 | </div> | ||
360 | |||
361 | {{ form_widget(form.import_tagging_rule.import, { 'attr': {'class': 'btn waves-effect waves-light'} }) }} | ||
362 | |||
363 | {{ form_rest(form.import_tagging_rule) }} | ||
364 | </form> | ||
365 | </div> | ||
333 | </div> | 366 | </div> |
334 | </div> | 367 | </li> |
335 | 368 | {% if app.user.config.taggingRules is not empty %} | |
336 | {{ form_widget(form.new_tagging_rule.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} | 369 | <li class="col l6 m6 s12"> |
337 | {{ form_rest(form.new_tagging_rule) }} | 370 | <div class="card z-depth-1"> |
338 | </form> | 371 | <div class="card-content"> |
372 | <span class="card-title">{{ 'config.form_rules.card.export_tagging_rules'|trans }}</span> | ||
373 | <p>{{ 'config.form_rules.card.export_tagging_rules_detail'|trans }}</p> | ||
374 | <br/> | ||
375 | <p><a href="{{ path('export_tagging_rule') }}" class="waves-effect waves-light btn">{{ 'config.form_rules.export'|trans }}</a></p> | ||
376 | </div> | ||
377 | </div> | ||
378 | </li> | ||
379 | {% endif %} | ||
380 | </ul> | ||
339 | 381 | ||
340 | <div class="row"> | 382 | <div class="row"> |
341 | <div class="input-field col s12"> | 383 | <div class="input-field col s12"> |
@@ -422,6 +464,37 @@ | |||
422 | </div> | 464 | </div> |
423 | </div> | 465 | </div> |
424 | </div> | 466 | </div> |
467 | |||
468 | <div id="set6" class="col s12"> | ||
469 | <div class="row"> | ||
470 | <h5>{{ 'config.reset.title'|trans }}</h5> | ||
471 | <p>{{ 'config.reset.description'|trans }}</p> | ||
472 | <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
473 | {{ 'config.reset.annotations'|trans }} | ||
474 | </a> | ||
475 | <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
476 | {{ 'config.reset.tags'|trans }} | ||
477 | </a> | ||
478 | <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
479 | {{ 'config.reset.archived'|trans }} | ||
480 | </a> | ||
481 | <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
482 | {{ 'config.reset.entries'|trans }} | ||
483 | </a> | ||
484 | </div> | ||
485 | |||
486 | {% if enabled_users > 1 %} | ||
487 | <br /><hr /><br /> | ||
488 | |||
489 | <div class="row"> | ||
490 | <h5>{{ 'config.form_user.delete.title'|trans }}</h5> | ||
491 | <p>{{ 'config.form_user.delete.description'|trans }}</p> | ||
492 | <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"> | ||
493 | {{ 'config.form_user.delete.button'|trans }} | ||
494 | </a> | ||
495 | </div> | ||
496 | {% endif %} | ||
497 | </div> | ||
425 | </div> | 498 | </div> |
426 | 499 | ||
427 | </div> | 500 | </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..6f405d7f --- /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">{{ "auth_code"|trans({}, 'SchebTwoFactorBundle') }}</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/Card/_content.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/Card/_content.html.twig index 1f3cd1a7..1102a0bd 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/Card/_content.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/Card/_content.html.twig | |||
@@ -8,8 +8,11 @@ | |||
8 | 8 | ||
9 | <div class="{{ subClass|default('original grey-text') }}"> | 9 | <div class="{{ subClass|default('original grey-text') }}"> |
10 | <a href="{{ entry.url|e }}" target="_blank" title="{{ entry.domainName|removeWww }}" class="tool grey-text">{{ entry.domainName|removeWww }}</a> | 10 | <a href="{{ entry.url|e }}" target="_blank" title="{{ entry.domainName|removeWww }}" class="tool grey-text">{{ entry.domainName|removeWww }}</a> |
11 | {% if withTags is defined %} | 11 | {% if withMetadata is defined %} |
12 | {% include "@WallabagCore/themes/material/Entry/_tags.html.twig" with {'tags': entry.tags | slice(0, 3), 'entryId': entry.id, 'listClass': ' hide-on-med-and-down'} only %} | 12 | {% include "@WallabagCore/themes/material/Entry/_tags.html.twig" with {'tags': entry.tags | slice(0, 3), 'entryId': entry.id, 'listClass': ' hide-on-med-and-down'} only %} |
13 | <div class="reading-time grey-text"> | ||
14 | <div class="card-reading-time">{% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %}</div> | ||
15 | </div> | ||
13 | {% endif %} | 16 | {% endif %} |
14 | </div> | 17 | </div> |
15 | </div> | 18 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_actions.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_actions.html.twig index 827f09d9..be764e10 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_actions.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_actions.html.twig | |||
@@ -1,9 +1,11 @@ | |||
1 | <div class="card-action"> | 1 | <div class="card-action"> |
2 | <span class="reading-time grey-text"> | 2 | <div class="reading-time grey-text"> |
3 | {% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %} | 3 | <div class="card-reading-time">{% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %}</div> |
4 | <i class="material-icons hide-on-med-and-down" title="{{ 'entry.view.created_at'|trans }}">today</i> | 4 | <div class="card-created-at"> |
5 | <span class="hide-on-med-and-down"> {{ entry.createdAt|date('Y-m-d') }}</span> | 5 | <i class="material-icons" title="{{ 'entry.view.created_at'|trans }}">today</i> |
6 | </span> | 6 | <span> {{ entry.createdAt|date('Y-m-d') }}</span> |
7 | </div> | ||
8 | </div> | ||
7 | 9 | ||
8 | <ul class="tools right"> | 10 | <ul class="tools right"> |
9 | <li> | 11 | <li> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig index 1c00f2fa..6a095035 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_card_list.html.twig | |||
@@ -5,7 +5,7 @@ | |||
5 | <span class="preview{{ previewClassModifier }}" style="background-image: url({{ entry.previewPicture | default(asset('wallassets/themes/_global/img/logo-square.svg')) }})"></span> | 5 | <span class="preview{{ previewClassModifier }}" style="background-image: url({{ entry.previewPicture | default(asset('wallassets/themes/_global/img/logo-square.svg')) }})"></span> |
6 | </a> | 6 | </a> |
7 | </div> | 7 | </div> |
8 | {% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry, 'withTags': true, 'subClass': 'metadata'} only %} | 8 | {% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry, 'withMetadata': true, 'subClass': 'metadata'} only %} |
9 | <ul class="tools-list hide-on-small-only"> | 9 | <ul class="tools-list hide-on-small-only"> |
10 | <li> | 10 | <li> |
11 | <a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i></a> | 11 | <a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i></a> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig index 6ba18768..b7167e95 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_reading_time.html.twig | |||
@@ -1,4 +1,4 @@ | |||
1 | {% set readingTime = entry.readingTime / app.user.config.readingSpeed %} | 1 | {% set readingTime = entry.readingTime / app.user.config.readingSpeed * 200 %} |
2 | <i class="material-icons">timer</i> | 2 | <i class="material-icons">timer</i> |
3 | {% if readingTime > 0 %} | 3 | {% if readingTime > 0 %} |
4 | <span>{{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }}</span> | 4 | <span>{{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }}</span> |
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 a137f3c3..3906e1e0 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 | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | {% block head %} | 3 | {% block head %} |
4 | {{ parent() }} | 4 | {{ parent() }} |
5 | {% if tag is defined and app.user.config.rssToken %} | 5 | {% if tag is defined and app.user.config.feedToken %} |
6 | <link rel="alternate" type="application/rss+xml" href="{{ path('tag_rss', {'username': app.user.username, 'token': app.user.config.rssToken, 'slug': tag.slug}) }}" /> | 6 | <link rel="alternate" type="application/atom+xml" href="{{ path('tag_feed', {'username': app.user.username, 'token': app.user.config.feedToken, 'slug': tag.slug}) }}" /> |
7 | {% endif %} | 7 | {% endif %} |
8 | {% endblock %} | 8 | {% endblock %} |
9 | 9 | ||
@@ -21,12 +21,15 @@ | |||
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) }} |
27 | <a href="{{ path('switch_view_mode') }}"><i class="material-icons">{% if listMode == 0 %}view_list{% else %}view_module{% endif %}</i></a> | 30 | <a href="{{ path('switch_view_mode') }}"><i class="material-icons">{% if listMode == 0 %}view_list{% else %}view_module{% endif %}</i></a> |
28 | {% if app.user.config.rssToken %} | 31 | {% if app.user.config.feedToken %} |
29 | {% include "@WallabagCore/themes/common/Entry/_rss_link.html.twig" %} | 32 | {% include "@WallabagCore/themes/common/Entry/_feed_link.html.twig" %} |
30 | {% endif %} | 33 | {% endif %} |
31 | </div> | 34 | </div> |
32 | {% if entries.getNbPages > 1 %} | 35 | {% if entries.getNbPages > 1 %} |
@@ -60,16 +63,13 @@ | |||
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 %} |
69 | {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %} | 69 | {% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %} |
70 | {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %} | 70 | {% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %} |
71 | {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %} | 71 | {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %} |
72 | {% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %} | 72 | {% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %} |
73 | {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %} | 73 | {% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %} |
74 | {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %} | 74 | {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %} |
75 | </ul> | 75 | </ul> |
@@ -83,6 +83,12 @@ | |||
83 | <h4 class="center">{{ 'entry.filters.title'|trans }}</h4> | 83 | <h4 class="center">{{ 'entry.filters.title'|trans }}</h4> |
84 | 84 | ||
85 | <div class="row"> | 85 | <div class="row"> |
86 | {% if currentRoute != 'untagged' and nbEntriesUntagged != 0 %} | ||
87 | <div class="col s12 center-align"> | ||
88 | <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }} ({{nbEntriesUntagged}})</a> | ||
89 | </div> | ||
90 | {% endif %} | ||
91 | |||
86 | <div class="col s12"> | 92 | <div class="col s12"> |
87 | <label>{{ 'entry.filters.status_label'|trans }}</label> | 93 | <label>{{ 'entry.filters.status_label'|trans }}</label> |
88 | </div> | 94 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig index c6c19de6..e23fa0e1 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig | |||
@@ -8,7 +8,7 @@ | |||
8 | <div class="progress"> | 8 | <div class="progress"> |
9 | <div class="determinate"></div> | 9 | <div class="determinate"></div> |
10 | </div> | 10 | </div> |
11 | <nav class="hide-on-large-only"> | 11 | <nav class="hide-on-large-only js-entry-nav-top"> |
12 | <div class="nav-panel-item cyan darken-1"> | 12 | <div class="nav-panel-item cyan darken-1"> |
13 | <ul> | 13 | <ul> |
14 | <li> | 14 | <li> |
@@ -127,7 +127,7 @@ | |||
127 | {% endif %} | 127 | {% endif %} |
128 | {% if craue_setting('share_twitter') %} | 128 | {% if craue_setting('share_twitter') %} |
129 | <li> | 129 | <li> |
130 | <a href="https://twitter.com/home?status={{entry.title|striptags|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" rel="noopener" class="tool icon-twitter" title="twitter"> | 130 | <a href="https://twitter.com/share?text={{entry.title|striptags|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" rel="noopener" class="tool icon-twitter" title="twitter"> |
131 | <span>twitter</span> | 131 | <span>twitter</span> |
132 | </a> | 132 | </a> |
133 | </li> | 133 | </li> |
@@ -209,7 +209,7 @@ | |||
209 | </li> | 209 | </li> |
210 | 210 | ||
211 | <li class="bold"> | 211 | <li class="bold"> |
212 | <a class="waves-effect collapsible-header" href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.description'|trans }}"> | 212 | <a class="waves-effect collapsible-header" href="mailto:siteconfig@wallabag.org?subject=Wrong%20display%20in%20wallabag&body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.description'|trans }}"> |
213 | <i class="material-icons small">error</i> | 213 | <i class="material-icons small">error</i> |
214 | <span>{{ 'entry.view.left_menu.problem.label'|trans }}</span> | 214 | <span>{{ 'entry.view.left_menu.problem.label'|trans }}</span> |
215 | </a> | 215 | </a> |
@@ -223,7 +223,7 @@ | |||
223 | {% block content %} | 223 | {% block content %} |
224 | <div id="article"> | 224 | <div id="article"> |
225 | <header class="mbm"> | 225 | <header class="mbm"> |
226 | <h1>{{ entry.title|striptags|default('entry.default_title'|trans)|raw }} <a href="{{ path('edit', { 'id': entry.id }) }}" title="{{ 'entry.view.edit_title'|trans }}">✎</a></h1> | 226 | <h1><span{% if entry.language is defined and entry.language is not null %} lang="{{ entry.getHTMLLanguage() }}"{% endif %}>{{ entry.title|striptags|default('entry.default_title'|trans)|raw }}</span> <a href="{{ path('edit', { 'id': entry.id }) }}" title="{{ 'entry.view.edit_title'|trans }}">✎</a></h1> |
227 | </header> | 227 | </header> |
228 | <aside> | 228 | <aside> |
229 | <div class="tools"> | 229 | <div class="tools"> |
@@ -250,13 +250,13 @@ | |||
250 | </li> | 250 | </li> |
251 | {% endif %} | 251 | {% endif %} |
252 | <li> | 252 | <li> |
253 | <i class="material-icons link">link</i> | 253 | <i class="material-icons">link</i> |
254 | <a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|striptags }}" class="tool"> | 254 | <a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|striptags }}" class="tool"> |
255 | {{ entry.domainName|removeWww }} | 255 | {{ entry.domainName|removeWww }} |
256 | </a> | 256 | </a> |
257 | </li> | 257 | </li> |
258 | <li> | 258 | <li> |
259 | <i class="material-icons link">comment</i> | 259 | <i class="material-icons">comment</i> |
260 | {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }} | 260 | {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }} |
261 | </li> | 261 | </li> |
262 | {% if entry.originUrl is not empty %} | 262 | {% if entry.originUrl is not empty %} |
@@ -276,12 +276,12 @@ | |||
276 | </div> | 276 | </div> |
277 | 277 | ||
278 | </aside> | 278 | </aside> |
279 | <article> | 279 | <article{% if entry.language is defined and entry.language is not null %} lang="{{ entry.getHTMLLanguage() }}"{% endif %}> |
280 | {{ entry.content | raw }} | 280 | {{ entry.content | raw }} |
281 | </article> | 281 | </article> |
282 | 282 | ||
283 | <div class="fixed-action-btn horizontal click-to-toggle hide-on-large-only"> | 283 | <div class="fixed-action-btn js-fixed-action-btn horizontal click-to-toggle hide-on-large-only"> |
284 | <a class="btn-floating btn-large"> | 284 | <a class="btn-floating btn-large" data-toggle="actions"> |
285 | <i class="material-icons">menu</i> | 285 | <i class="material-icons">menu</i> |
286 | </a> | 286 | </a> |
287 | <ul> | 287 | <ul> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/new_form.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/new_form.html.twig index e0d5e794..4cf81167 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/new_form.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/new_form.html.twig | |||
@@ -2,14 +2,14 @@ | |||
2 | {% if form_errors(form) %} | 2 | {% if form_errors(form) %} |
3 | <span class="black-text">{{ form_errors(form) }}</span> | 3 | <span class="black-text">{{ form_errors(form) }}</span> |
4 | {% endif %} | 4 | {% endif %} |
5 | <button type="submit" class="nav-form-button"><i class="material-icons add">add</i></button> | 5 | <button type="submit" class="nav-form-button" aria-label="add"><i class="material-icons add" aria-hidden="true"></i></button> |
6 | 6 | ||
7 | {% if form_errors(form.url) %} | 7 | {% if form_errors(form.url) %} |
8 | <span class="black-text">{{ form_errors(form.url) }}</span> | 8 | <span class="black-text">{{ form_errors(form.url) }}</span> |
9 | {% endif %} | 9 | {% endif %} |
10 | 10 | ||
11 | {{ form_widget(form.url, { 'attr': {'autocomplete': 'off', 'placeholder': 'entry.new.placeholder'} }) }} | 11 | {{ form_widget(form.url, { 'attr': {'autocomplete': 'off', 'placeholder': 'entry.new.placeholder'} }) }} |
12 | <i class="material-icons close">clear</i> | 12 | <i class="material-icons close" aria-label="clear" role="button"></i> |
13 | 13 | ||
14 | {{ form_rest(form) }} | 14 | {{ form_rest(form) }} |
15 | </form> | 15 | </form> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig index ba1b3aac..0ae8b0b3 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig | |||
@@ -2,7 +2,7 @@ | |||
2 | {% if form_errors(form) %} | 2 | {% if form_errors(form) %} |
3 | <span class="black-text">{{ form_errors(form) }}</span> | 3 | <span class="black-text">{{ form_errors(form) }}</span> |
4 | {% endif %} | 4 | {% endif %} |
5 | <button type="submit" class="nav-form-button"><i class="material-icons search">search</i></button> | 5 | <button type="submit" class="nav-form-button" aria-label="search"><i class="material-icons search" aria-hidden="true"></i></button> |
6 | 6 | ||
7 | {% if form_errors(form.term) %} | 7 | {% if form_errors(form.term) %} |
8 | <span class="black-text">{{ form_errors(form.term) }}</span> | 8 | <span class="black-text">{{ form_errors(form.term) }}</span> |
@@ -11,7 +11,7 @@ | |||
11 | <input type="hidden" name="currentRoute" value="{{ currentRoute }}" /> | 11 | <input type="hidden" name="currentRoute" value="{{ currentRoute }}" /> |
12 | 12 | ||
13 | {{ form_widget(form.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'entry.search.placeholder'} }) }} | 13 | {{ form_widget(form.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'entry.search.placeholder'} }) }} |
14 | <i class="material-icons close">clear</i> | 14 | <i class="material-icons close" aria-label="clear" role="button"></i> |
15 | 15 | ||
16 | {{ form_rest(form) }} | 16 | {{ form_rest(form) }} |
17 | </form> | 17 | </form> |
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..0a3475ef 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,9 +13,20 @@ | |||
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 | {% if app.user.config.rssToken %} | 17 | {{ tag.label }} ({{ tag.nbEntries }}) |
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> | 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 %} | ||
28 | {% if app.user.config.feedToken %} | ||
29 | <a rel="alternate" type="application/atom+xml" href="{{ path('tag_feed', {'username': app.user.username, 'token': app.user.config.feedToken, 'slug': tag.slug}) }}" class="card-tag-rss"><i class="material-icons">rss_feed</i></a> | ||
19 | {% endif %} | 30 | {% endif %} |
20 | </li> | 31 | </li> |
21 | {% endfor %} | 32 | {% endfor %} |
@@ -23,6 +34,10 @@ | |||
23 | </div> | 34 | </div> |
24 | 35 | ||
25 | <div> | 36 | <div> |
26 | <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }}</a> | 37 | {% if nbEntriesUntagged == 0 %} |
38 | {{ 'tag.list.no_untagged_entries'|trans }} | ||
39 | {% else %} | ||
40 | <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }} ({{nbEntriesUntagged}})</a> | ||
41 | {% endif %} | ||
27 | </div> | 42 | </div> |
28 | {% endblock %} | 43 | {% endblock %} |
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..c51d07fc 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 %}"> |
@@ -89,6 +91,9 @@ | |||
89 | <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"> | 91 | <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"> |
90 | <a class="waves-effect" href="{{ path('howto') }}">{{ 'menu.left.howto'|trans }}</a> | 92 | <a class="waves-effect" href="{{ path('howto') }}">{{ 'menu.left.howto'|trans }}</a> |
91 | </li> | 93 | </li> |
94 | <li class="bold {% if currentRoute == 'quickstart' %}active{% endif %}"> | ||
95 | <a class="waves-effect" href="{{ path('quickstart') }}">{{ 'menu.left.quickstart'|trans }}</a> | ||
96 | </li> | ||
92 | <li class="bold"> | 97 | <li class="bold"> |
93 | <a class="waves-effect icon icon-power" href="{{ path('fos_user_security_logout') }}">{{ 'menu.left.logout'|trans }}</a> | 98 | <a class="waves-effect icon icon-power" href="{{ path('fos_user_security_logout') }}">{{ 'menu.left.logout'|trans }}</a> |
94 | </li> | 99 | </li> |
@@ -113,6 +118,13 @@ | |||
113 | <i class="material-icons">search</i> | 118 | <i class="material-icons">search</i> |
114 | </a> | 119 | </a> |
115 | </li> | 120 | </li> |
121 | {% if activeRoute %} | ||
122 | <li id="button_random"> | ||
123 | <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 }) }}"> | ||
124 | <i class="material-icons">casino</i> | ||
125 | </a> | ||
126 | </li> | ||
127 | {% endif %} | ||
116 | <li id="button_filters"> | 128 | <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"> | 129 | <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> | 130 | <i class="material-icons">filter_list</i> |
@@ -125,7 +137,7 @@ | |||
125 | </li> | 137 | </li> |
126 | </ul> | 138 | </ul> |
127 | </div> | 139 | </div> |
128 | {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': app.request.attributes.get('_route')})) }} | 140 | {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': currentRoute})) }} |
129 | {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }} | 141 | {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }} |
130 | </div> | 142 | </div> |
131 | </nav> | 143 | </nav> |
diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php index 46bb1dc5..b7ad7966 100644 --- a/src/Wallabag/CoreBundle/Tools/Utils.php +++ b/src/Wallabag/CoreBundle/Tools/Utils.php | |||
@@ -5,7 +5,7 @@ namespace Wallabag\CoreBundle\Tools; | |||
5 | class Utils | 5 | class Utils |
6 | { | 6 | { |
7 | /** | 7 | /** |
8 | * Generate a token used for RSS. | 8 | * Generate a token used for Feeds. |
9 | * | 9 | * |
10 | * @param int $length Length of the token | 10 | * @param int $length Length of the token |
11 | * | 11 | * |
@@ -20,15 +20,14 @@ class Utils | |||
20 | } | 20 | } |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * For a given text, we calculate reading time for an article | 23 | * For a given text, we calculate reading time for an article based on 200 words per minute. |
24 | * based on 200 words per minute. | ||
25 | * | 24 | * |
26 | * @param $text | 25 | * @param string $text |
27 | * | 26 | * |
28 | * @return float | 27 | * @return float |
29 | */ | 28 | */ |
30 | public static function getReadingTime($text) | 29 | public static function getReadingTime($text) |
31 | { | 30 | { |
32 | return floor(\count(preg_split('~[^\p{L}\p{N}\']+~u', strip_tags($text))) / 200); | 31 | return floor(\count(preg_split('~([^\p{L}\p{N}\']+|(\p{Han}|\p{Hiragana}|\p{Katakana}|\p{Hangul}){1,2})~u', strip_tags($text))) / 200); |
33 | } | 32 | } |
34 | } | 33 | } |
diff --git a/src/Wallabag/CoreBundle/Twig/WallabagExtension.php b/src/Wallabag/CoreBundle/Twig/WallabagExtension.php index 00b1e595..02f17f50 100644 --- a/src/Wallabag/CoreBundle/Twig/WallabagExtension.php +++ b/src/Wallabag/CoreBundle/Twig/WallabagExtension.php | |||
@@ -4,10 +4,14 @@ namespace Wallabag\CoreBundle\Twig; | |||
4 | 4 | ||
5 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | 5 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; |
6 | use Symfony\Component\Translation\TranslatorInterface; | 6 | use Symfony\Component\Translation\TranslatorInterface; |
7 | use Twig\Extension\AbstractExtension; | ||
8 | use Twig\Extension\GlobalsInterface; | ||
9 | use Twig\TwigFilter; | ||
10 | use Twig\TwigFunction; | ||
7 | use Wallabag\CoreBundle\Repository\EntryRepository; | 11 | use Wallabag\CoreBundle\Repository\EntryRepository; |
8 | use Wallabag\CoreBundle\Repository\TagRepository; | 12 | use Wallabag\CoreBundle\Repository\TagRepository; |
9 | 13 | ||
10 | class WallabagExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface | 14 | class WallabagExtension extends AbstractExtension implements GlobalsInterface |
11 | { | 15 | { |
12 | private $tokenStorage; | 16 | private $tokenStorage; |
13 | private $entryRepository; | 17 | private $entryRepository; |
@@ -24,20 +28,26 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa | |||
24 | $this->translator = $translator; | 28 | $this->translator = $translator; |
25 | } | 29 | } |
26 | 30 | ||
31 | public function getGlobals() | ||
32 | { | ||
33 | return []; | ||
34 | } | ||
35 | |||
27 | public function getFilters() | 36 | public function getFilters() |
28 | { | 37 | { |
29 | return [ | 38 | return [ |
30 | new \Twig_SimpleFilter('removeWww', [$this, 'removeWww']), | 39 | new TwigFilter('removeWww', [$this, 'removeWww']), |
31 | new \Twig_SimpleFilter('removeSchemeAndWww', [$this, 'removeSchemeAndWww']), | 40 | new TwigFilter('removeScheme', [$this, 'removeScheme']), |
41 | new TwigFilter('removeSchemeAndWww', [$this, 'removeSchemeAndWww']), | ||
32 | ]; | 42 | ]; |
33 | } | 43 | } |
34 | 44 | ||
35 | public function getFunctions() | 45 | public function getFunctions() |
36 | { | 46 | { |
37 | return [ | 47 | return [ |
38 | new \Twig_SimpleFunction('count_entries', [$this, 'countEntries']), | 48 | new TwigFunction('count_entries', [$this, 'countEntries']), |
39 | new \Twig_SimpleFunction('count_tags', [$this, 'countTags']), | 49 | new TwigFunction('count_tags', [$this, 'countTags']), |
40 | new \Twig_SimpleFunction('display_stats', [$this, 'displayStats']), | 50 | new TwigFunction('display_stats', [$this, 'displayStats']), |
41 | ]; | 51 | ]; |
42 | } | 52 | } |
43 | 53 | ||
@@ -46,11 +56,14 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa | |||
46 | return preg_replace('/^www\./i', '', $url); | 56 | return preg_replace('/^www\./i', '', $url); |
47 | } | 57 | } |
48 | 58 | ||
59 | public function removeScheme($url) | ||
60 | { | ||
61 | return preg_replace('#^https?://#i', '', $url); | ||
62 | } | ||
63 | |||
49 | public function removeSchemeAndWww($url) | 64 | public function removeSchemeAndWww($url) |
50 | { | 65 | { |
51 | return $this->removeWww( | 66 | return $this->removeWww($this->removeScheme($url)); |
52 | preg_replace('@^https?://@i', '', $url) | ||
53 | ); | ||
54 | } | 67 | } |
55 | 68 | ||
56 | /** | 69 | /** |
diff --git a/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php b/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php index b035f5cc..e4bfbdf0 100644 --- a/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php +++ b/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php | |||
@@ -52,6 +52,13 @@ abstract class AbstractConsumer | |||
52 | 52 | ||
53 | $this->import->setUser($user); | 53 | $this->import->setUser($user); |
54 | 54 | ||
55 | if (false === $this->import->validateEntry($storedEntry)) { | ||
56 | $this->logger->warning('Entry is invalid', ['entry' => $storedEntry]); | ||
57 | |||
58 | // return true to skip message | ||
59 | return true; | ||
60 | } | ||
61 | |||
55 | $entry = $this->import->parseEntry($storedEntry); | 62 | $entry = $this->import->parseEntry($storedEntry); |
56 | 63 | ||
57 | if (null === $entry) { | 64 | if (null === $entry) { |
diff --git a/src/Wallabag/ImportBundle/Controller/BrowserController.php b/src/Wallabag/ImportBundle/Controller/BrowserController.php index 6418925c..8c2bdfe5 100644 --- a/src/Wallabag/ImportBundle/Controller/BrowserController.php +++ b/src/Wallabag/ImportBundle/Controller/BrowserController.php | |||
@@ -2,10 +2,10 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\HttpFoundation\Response; | 7 | use Symfony\Component\HttpFoundation\Response; |
8 | use Symfony\Component\Routing\Annotation\Route; | ||
9 | use Wallabag\ImportBundle\Form\Type\UploadImportType; | 9 | use Wallabag\ImportBundle\Form\Type\UploadImportType; |
10 | 10 | ||
11 | abstract class BrowserController extends Controller | 11 | abstract class BrowserController extends Controller |
@@ -13,8 +13,6 @@ abstract class BrowserController extends Controller | |||
13 | /** | 13 | /** |
14 | * @Route("/browser", name="import_browser") | 14 | * @Route("/browser", name="import_browser") |
15 | * | 15 | * |
16 | * @param Request $request | ||
17 | * | ||
18 | * @return Response | 16 | * @return Response |
19 | */ | 17 | */ |
20 | public function indexAction(Request $request) | 18 | public function indexAction(Request $request) |
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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Component\HttpFoundation\Request; | 5 | use Symfony\Component\HttpFoundation\Request; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class ChromeController extends BrowserController | 8 | class ChromeController extends BrowserController |
9 | { | 9 | { |
diff --git a/src/Wallabag/ImportBundle/Controller/ElcuratorController.php b/src/Wallabag/ImportBundle/Controller/ElcuratorController.php new file mode 100644 index 00000000..174c2c96 --- /dev/null +++ b/src/Wallabag/ImportBundle/Controller/ElcuratorController.php | |||
@@ -0,0 +1,41 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ImportBundle\Controller; | ||
4 | |||
5 | use Symfony\Component\HttpFoundation\Request; | ||
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | |||
8 | class ElcuratorController extends WallabagController | ||
9 | { | ||
10 | /** | ||
11 | * @Route("/elcurator", name="import_elcurator") | ||
12 | */ | ||
13 | public function indexAction(Request $request) | ||
14 | { | ||
15 | return parent::indexAction($request); | ||
16 | } | ||
17 | |||
18 | /** | ||
19 | * {@inheritdoc} | ||
20 | */ | ||
21 | protected function getImportService() | ||
22 | { | ||
23 | $service = $this->get('wallabag_import.elcurator.import'); | ||
24 | |||
25 | if ($this->get('craue_config')->get('import_with_rabbitmq')) { | ||
26 | $service->setProducer($this->get('old_sound_rabbit_mq.import_elcurator_producer')); | ||
27 | } elseif ($this->get('craue_config')->get('import_with_redis')) { | ||
28 | $service->setProducer($this->get('wallabag_import.producer.redis.elcurator')); | ||
29 | } | ||
30 | |||
31 | return $service; | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * {@inheritdoc} | ||
36 | */ | ||
37 | protected function getImportTemplate() | ||
38 | { | ||
39 | return 'WallabagImportBundle:Elcurator:index.html.twig'; | ||
40 | } | ||
41 | } | ||
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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Component\HttpFoundation\Request; | 5 | use Symfony\Component\HttpFoundation\Request; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class FirefoxController extends BrowserController | 8 | class FirefoxController extends BrowserController |
9 | { | 9 | { |
diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php index 7e4fd174..5a7e53d6 100644 --- a/src/Wallabag/ImportBundle/Controller/ImportController.php +++ b/src/Wallabag/ImportBundle/Controller/ImportController.php | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class ImportController extends Controller | 8 | class ImportController extends Controller |
9 | { | 9 | { |
@@ -43,6 +43,7 @@ class ImportController extends Controller | |||
43 | + $this->getTotalMessageInRabbitQueue('chrome') | 43 | + $this->getTotalMessageInRabbitQueue('chrome') |
44 | + $this->getTotalMessageInRabbitQueue('instapaper') | 44 | + $this->getTotalMessageInRabbitQueue('instapaper') |
45 | + $this->getTotalMessageInRabbitQueue('pinboard') | 45 | + $this->getTotalMessageInRabbitQueue('pinboard') |
46 | + $this->getTotalMessageInRabbitQueue('elcurator') | ||
46 | ; | 47 | ; |
47 | } catch (\Exception $e) { | 48 | } catch (\Exception $e) { |
48 | $rabbitNotInstalled = true; | 49 | $rabbitNotInstalled = true; |
@@ -59,6 +60,7 @@ class ImportController extends Controller | |||
59 | + $redis->llen('wallabag.import.chrome') | 60 | + $redis->llen('wallabag.import.chrome') |
60 | + $redis->llen('wallabag.import.instapaper') | 61 | + $redis->llen('wallabag.import.instapaper') |
61 | + $redis->llen('wallabag.import.pinboard') | 62 | + $redis->llen('wallabag.import.pinboard') |
63 | + $redis->llen('wallabag.import.elcurator') | ||
62 | ; | 64 | ; |
63 | } catch (\Exception $e) { | 65 | } catch (\Exception $e) { |
64 | $redisNotInstalled = true; | 66 | $redisNotInstalled = true; |
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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
7 | use Symfony\Component\Routing\Annotation\Route; | ||
8 | use Wallabag\ImportBundle\Form\Type\UploadImportType; | 8 | use Wallabag\ImportBundle\Form\Type\UploadImportType; |
9 | 9 | ||
10 | class InstapaperController extends Controller | 10 | class 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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
7 | use Symfony\Component\Routing\Annotation\Route; | ||
8 | use Wallabag\ImportBundle\Form\Type\UploadImportType; | 8 | use Wallabag\ImportBundle\Form\Type\UploadImportType; |
9 | 9 | ||
10 | class PinboardController extends Controller | 10 | class 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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | 6 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; |
8 | use Symfony\Component\HttpFoundation\Request; | 7 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\Routing\Annotation\Route; | ||
9 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 9 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
10 | 10 | ||
11 | class PocketController extends Controller | 11 | class 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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
7 | use Symfony\Component\Routing\Annotation\Route; | ||
8 | use Wallabag\ImportBundle\Form\Type\UploadImportType; | 8 | use Wallabag\ImportBundle\Form\Type\UploadImportType; |
9 | 9 | ||
10 | class ReadabilityController extends Controller | 10 | class ReadabilityController extends Controller |
diff --git a/src/Wallabag/ImportBundle/Controller/WallabagController.php b/src/Wallabag/ImportBundle/Controller/WallabagController.php index d182dd2c..5180006d 100644 --- a/src/Wallabag/ImportBundle/Controller/WallabagController.php +++ b/src/Wallabag/ImportBundle/Controller/WallabagController.php | |||
@@ -16,8 +16,6 @@ abstract class WallabagController extends Controller | |||
16 | /** | 16 | /** |
17 | * Handle import request. | 17 | * Handle import request. |
18 | * | 18 | * |
19 | * @param Request $request | ||
20 | * | ||
21 | * @return Response|RedirectResponse | 19 | * @return Response|RedirectResponse |
22 | */ | 20 | */ |
23 | public function indexAction(Request $request) | 21 | public function indexAction(Request $request) |
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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Component\HttpFoundation\Request; | 5 | use Symfony\Component\HttpFoundation\Request; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class WallabagV1Controller extends WallabagController | 8 | class 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 | ||
3 | namespace Wallabag\ImportBundle\Controller; | 3 | namespace Wallabag\ImportBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Component\HttpFoundation\Request; | 5 | use Symfony\Component\HttpFoundation\Request; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class WallabagV2Controller extends WallabagController | 8 | class WallabagV2Controller extends WallabagController |
9 | { | 9 | { |
diff --git a/src/Wallabag/ImportBundle/Import/AbstractImport.php b/src/Wallabag/ImportBundle/Import/AbstractImport.php index 58a234f4..1b073e99 100644 --- a/src/Wallabag/ImportBundle/Import/AbstractImport.php +++ b/src/Wallabag/ImportBundle/Import/AbstractImport.php | |||
@@ -46,8 +46,6 @@ abstract class AbstractImport implements ImportInterface | |||
46 | /** | 46 | /** |
47 | * Set RabbitMQ/Redis Producer to send each entry to a queue. | 47 | * Set RabbitMQ/Redis Producer to send each entry to a queue. |
48 | * This method should be called when user has enabled RabbitMQ. | 48 | * This method should be called when user has enabled RabbitMQ. |
49 | * | ||
50 | * @param ProducerInterface $producer | ||
51 | */ | 49 | */ |
52 | public function setProducer(ProducerInterface $producer) | 50 | public function setProducer(ProducerInterface $producer) |
53 | { | 51 | { |
@@ -57,8 +55,6 @@ abstract class AbstractImport implements ImportInterface | |||
57 | /** | 55 | /** |
58 | * Set current user. | 56 | * Set current user. |
59 | * Could the current *connected* user or one retrieve by the consumer. | 57 | * Could the current *connected* user or one retrieve by the consumer. |
60 | * | ||
61 | * @param User $user | ||
62 | */ | 58 | */ |
63 | public function setUser(User $user) | 59 | public function setUser(User $user) |
64 | { | 60 | { |
@@ -112,13 +108,18 @@ abstract class AbstractImport implements ImportInterface | |||
112 | /** | 108 | /** |
113 | * Parse one entry. | 109 | * Parse one entry. |
114 | * | 110 | * |
115 | * @param array $importedEntry | ||
116 | * | ||
117 | * @return Entry | 111 | * @return Entry |
118 | */ | 112 | */ |
119 | abstract public function parseEntry(array $importedEntry); | 113 | abstract public function parseEntry(array $importedEntry); |
120 | 114 | ||
121 | /** | 115 | /** |
116 | * Validate that an entry is valid (like has some required keys, etc.). | ||
117 | * | ||
118 | * @return bool | ||
119 | */ | ||
120 | abstract public function validateEntry(array $importedEntry); | ||
121 | |||
122 | /** | ||
122 | * Fetch content from the ContentProxy (using graby). | 123 | * Fetch content from the ContentProxy (using graby). |
123 | * If it fails return the given entry to be saved in all case (to avoid user to loose the content). | 124 | * If it fails return the given entry to be saved in all case (to avoid user to loose the content). |
124 | * | 125 | * |
@@ -140,10 +141,8 @@ abstract class AbstractImport implements ImportInterface | |||
140 | 141 | ||
141 | /** | 142 | /** |
142 | * Parse and insert all given entries. | 143 | * Parse and insert all given entries. |
143 | * | ||
144 | * @param $entries | ||
145 | */ | 144 | */ |
146 | protected function parseEntries($entries) | 145 | protected function parseEntries(array $entries) |
147 | { | 146 | { |
148 | $i = 1; | 147 | $i = 1; |
149 | $entryToBeFlushed = []; | 148 | $entryToBeFlushed = []; |
@@ -153,6 +152,10 @@ abstract class AbstractImport implements ImportInterface | |||
153 | $importedEntry = $this->setEntryAsRead($importedEntry); | 152 | $importedEntry = $this->setEntryAsRead($importedEntry); |
154 | } | 153 | } |
155 | 154 | ||
155 | if (false === $this->validateEntry($importedEntry)) { | ||
156 | continue; | ||
157 | } | ||
158 | |||
156 | $entry = $this->parseEntry($importedEntry); | 159 | $entry = $this->parseEntry($importedEntry); |
157 | 160 | ||
158 | if (null === $entry) { | 161 | if (null === $entry) { |
@@ -197,8 +200,6 @@ abstract class AbstractImport implements ImportInterface | |||
197 | * | 200 | * |
198 | * Faster parse entries for Producer. | 201 | * Faster parse entries for Producer. |
199 | * We don't care to make check at this time. They'll be done by the consumer. | 202 | * We don't care to make check at this time. They'll be done by the consumer. |
200 | * | ||
201 | * @param array $entries | ||
202 | */ | 203 | */ |
203 | protected function parseEntriesForProducer(array $entries) | 204 | protected function parseEntriesForProducer(array $entries) |
204 | { | 205 | { |
@@ -220,8 +221,6 @@ abstract class AbstractImport implements ImportInterface | |||
220 | * Set current imported entry to archived / read. | 221 | * Set current imported entry to archived / read. |
221 | * Implementation is different accross all imports. | 222 | * Implementation is different accross all imports. |
222 | * | 223 | * |
223 | * @param array $importedEntry | ||
224 | * | ||
225 | * @return array | 224 | * @return array |
226 | */ | 225 | */ |
227 | abstract protected function setEntryAsRead(array $importedEntry); | 226 | abstract protected function setEntryAsRead(array $importedEntry); |
diff --git a/src/Wallabag/ImportBundle/Import/BrowserImport.php b/src/Wallabag/ImportBundle/Import/BrowserImport.php index 225f1791..ea7afd3d 100644 --- a/src/Wallabag/ImportBundle/Import/BrowserImport.php +++ b/src/Wallabag/ImportBundle/Import/BrowserImport.php | |||
@@ -77,7 +77,7 @@ abstract class BrowserImport extends AbstractImport | |||
77 | */ | 77 | */ |
78 | public function parseEntry(array $importedEntry) | 78 | public function parseEntry(array $importedEntry) |
79 | { | 79 | { |
80 | if ((!array_key_exists('guid', $importedEntry) || (!array_key_exists('id', $importedEntry))) && \is_array(reset($importedEntry))) { | 80 | if ((!\array_key_exists('guid', $importedEntry) || (!\array_key_exists('id', $importedEntry))) && \is_array(reset($importedEntry))) { |
81 | if ($this->producer) { | 81 | if ($this->producer) { |
82 | $this->parseEntriesForProducer($importedEntry); | 82 | $this->parseEntriesForProducer($importedEntry); |
83 | 83 | ||
@@ -89,7 +89,7 @@ abstract class BrowserImport extends AbstractImport | |||
89 | return; | 89 | return; |
90 | } | 90 | } |
91 | 91 | ||
92 | if (array_key_exists('children', $importedEntry)) { | 92 | if (\array_key_exists('children', $importedEntry)) { |
93 | if ($this->producer) { | 93 | if ($this->producer) { |
94 | $this->parseEntriesForProducer($importedEntry['children']); | 94 | $this->parseEntriesForProducer($importedEntry['children']); |
95 | 95 | ||
@@ -101,11 +101,11 @@ abstract class BrowserImport extends AbstractImport | |||
101 | return; | 101 | return; |
102 | } | 102 | } |
103 | 103 | ||
104 | if (!array_key_exists('uri', $importedEntry) && !array_key_exists('url', $importedEntry)) { | 104 | if (!\array_key_exists('uri', $importedEntry) && !\array_key_exists('url', $importedEntry)) { |
105 | return; | 105 | return; |
106 | } | 106 | } |
107 | 107 | ||
108 | $url = array_key_exists('uri', $importedEntry) ? $importedEntry['uri'] : $importedEntry['url']; | 108 | $url = \array_key_exists('uri', $importedEntry) ? $importedEntry['uri'] : $importedEntry['url']; |
109 | 109 | ||
110 | $existingEntry = $this->em | 110 | $existingEntry = $this->em |
111 | ->getRepository('WallabagCoreBundle:Entry') | 111 | ->getRepository('WallabagCoreBundle:Entry') |
@@ -126,14 +126,14 @@ abstract class BrowserImport extends AbstractImport | |||
126 | // update entry with content (in case fetching failed, the given entry will be return) | 126 | // update entry with content (in case fetching failed, the given entry will be return) |
127 | $this->fetchContent($entry, $data['url'], $data); | 127 | $this->fetchContent($entry, $data['url'], $data); |
128 | 128 | ||
129 | if (array_key_exists('tags', $data)) { | 129 | if (\array_key_exists('tags', $data)) { |
130 | $this->tagsAssigner->assignTagsToEntry( | 130 | $this->tagsAssigner->assignTagsToEntry( |
131 | $entry, | 131 | $entry, |
132 | $data['tags'] | 132 | $data['tags'] |
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(); |
@@ -148,10 +148,8 @@ abstract class BrowserImport extends AbstractImport | |||
148 | 148 | ||
149 | /** | 149 | /** |
150 | * Parse and insert all given entries. | 150 | * Parse and insert all given entries. |
151 | * | ||
152 | * @param $entries | ||
153 | */ | 151 | */ |
154 | protected function parseEntries($entries) | 152 | protected function parseEntries(array $entries) |
155 | { | 153 | { |
156 | $i = 1; | 154 | $i = 1; |
157 | $entryToBeFlushed = []; | 155 | $entryToBeFlushed = []; |
@@ -199,8 +197,6 @@ abstract class BrowserImport extends AbstractImport | |||
199 | * | 197 | * |
200 | * Faster parse entries for Producer. | 198 | * Faster parse entries for Producer. |
201 | * We don't care to make check at this time. They'll be done by the consumer. | 199 | * We don't care to make check at this time. They'll be done by the consumer. |
202 | * | ||
203 | * @param array $entries | ||
204 | */ | 200 | */ |
205 | protected function parseEntriesForProducer(array $entries) | 201 | protected function parseEntriesForProducer(array $entries) |
206 | { | 202 | { |
diff --git a/src/Wallabag/ImportBundle/Import/ChromeImport.php b/src/Wallabag/ImportBundle/Import/ChromeImport.php index 09183abe..4ae82ade 100644 --- a/src/Wallabag/ImportBundle/Import/ChromeImport.php +++ b/src/Wallabag/ImportBundle/Import/ChromeImport.php | |||
@@ -33,6 +33,18 @@ class ChromeImport extends BrowserImport | |||
33 | /** | 33 | /** |
34 | * {@inheritdoc} | 34 | * {@inheritdoc} |
35 | */ | 35 | */ |
36 | public function validateEntry(array $importedEntry) | ||
37 | { | ||
38 | if (empty($importedEntry['url'])) { | ||
39 | return false; | ||
40 | } | ||
41 | |||
42 | return true; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * {@inheritdoc} | ||
47 | */ | ||
36 | protected function prepareEntry(array $entry = []) | 48 | protected function prepareEntry(array $entry = []) |
37 | { | 49 | { |
38 | $data = [ | 50 | $data = [ |
@@ -45,7 +57,7 @@ class ChromeImport extends BrowserImport | |||
45 | 'created_at' => substr($entry['date_added'], 0, 10), | 57 | 'created_at' => substr($entry['date_added'], 0, 10), |
46 | ]; | 58 | ]; |
47 | 59 | ||
48 | if (array_key_exists('tags', $entry) && '' !== $entry['tags']) { | 60 | if (\array_key_exists('tags', $entry) && '' !== $entry['tags']) { |
49 | $data['tags'] = $entry['tags']; | 61 | $data['tags'] = $entry['tags']; |
50 | } | 62 | } |
51 | 63 | ||
diff --git a/src/Wallabag/ImportBundle/Import/ElcuratorImport.php b/src/Wallabag/ImportBundle/Import/ElcuratorImport.php new file mode 100644 index 00000000..d1281613 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/ElcuratorImport.php | |||
@@ -0,0 +1,54 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ImportBundle\Import; | ||
4 | |||
5 | class ElcuratorImport extends WallabagImport | ||
6 | { | ||
7 | /** | ||
8 | * {@inheritdoc} | ||
9 | */ | ||
10 | public function getName() | ||
11 | { | ||
12 | return 'elcurator'; | ||
13 | } | ||
14 | |||
15 | /** | ||
16 | * {@inheritdoc} | ||
17 | */ | ||
18 | public function getUrl() | ||
19 | { | ||
20 | return 'import_elcurator'; | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * {@inheritdoc} | ||
25 | */ | ||
26 | public function getDescription() | ||
27 | { | ||
28 | return 'import.elcurator.description'; | ||
29 | } | ||
30 | |||
31 | /** | ||
32 | * {@inheritdoc} | ||
33 | */ | ||
34 | protected function prepareEntry($entry = []) | ||
35 | { | ||
36 | return [ | ||
37 | 'url' => $entry['url'], | ||
38 | 'title' => $entry['title'], | ||
39 | 'created_at' => $entry['created_at'], | ||
40 | 'is_archived' => 0, | ||
41 | 'is_starred' => $entry['is_saved'], | ||
42 | ] + $entry; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * {@inheritdoc} | ||
47 | */ | ||
48 | protected function setEntryAsRead(array $importedEntry) | ||
49 | { | ||
50 | $importedEntry['is_archived'] = 1; | ||
51 | |||
52 | return $importedEntry; | ||
53 | } | ||
54 | } | ||
diff --git a/src/Wallabag/ImportBundle/Import/FirefoxImport.php b/src/Wallabag/ImportBundle/Import/FirefoxImport.php index 73269fe1..b3558f21 100644 --- a/src/Wallabag/ImportBundle/Import/FirefoxImport.php +++ b/src/Wallabag/ImportBundle/Import/FirefoxImport.php | |||
@@ -33,6 +33,18 @@ class FirefoxImport extends BrowserImport | |||
33 | /** | 33 | /** |
34 | * {@inheritdoc} | 34 | * {@inheritdoc} |
35 | */ | 35 | */ |
36 | public function validateEntry(array $importedEntry) | ||
37 | { | ||
38 | if (empty($importedEntry['uri'])) { | ||
39 | return false; | ||
40 | } | ||
41 | |||
42 | return true; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * {@inheritdoc} | ||
47 | */ | ||
36 | protected function prepareEntry(array $entry = []) | 48 | protected function prepareEntry(array $entry = []) |
37 | { | 49 | { |
38 | $data = [ | 50 | $data = [ |
@@ -45,7 +57,7 @@ class FirefoxImport extends BrowserImport | |||
45 | 'created_at' => substr($entry['dateAdded'], 0, 10), | 57 | 'created_at' => substr($entry['dateAdded'], 0, 10), |
46 | ]; | 58 | ]; |
47 | 59 | ||
48 | if (array_key_exists('tags', $entry) && '' !== $entry['tags']) { | 60 | if (\array_key_exists('tags', $entry) && '' !== $entry['tags']) { |
49 | $data['tags'] = $entry['tags']; | 61 | $data['tags'] = $entry['tags']; |
50 | } | 62 | } |
51 | 63 | ||
diff --git a/src/Wallabag/ImportBundle/Import/ImportChain.php b/src/Wallabag/ImportBundle/Import/ImportChain.php index 9dd77956..e1b5867d 100644 --- a/src/Wallabag/ImportBundle/Import/ImportChain.php +++ b/src/Wallabag/ImportBundle/Import/ImportChain.php | |||
@@ -14,8 +14,7 @@ class ImportChain | |||
14 | /** | 14 | /** |
15 | * Add an import to the chain. | 15 | * Add an import to the chain. |
16 | * | 16 | * |
17 | * @param ImportInterface $import | 17 | * @param string $alias |
18 | * @param string $alias | ||
19 | */ | 18 | */ |
20 | public function addImport(ImportInterface $import, $alias) | 19 | public function addImport(ImportInterface $import, $alias) |
21 | { | 20 | { |
diff --git a/src/Wallabag/ImportBundle/Import/InstapaperImport.php b/src/Wallabag/ImportBundle/Import/InstapaperImport.php index e4f0970c..f7bee9ef 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, |
@@ -94,6 +93,10 @@ class InstapaperImport extends AbstractImport | |||
94 | return false; | 93 | return false; |
95 | } | 94 | } |
96 | 95 | ||
96 | // most recent articles are first, which means we should create them at the end so they will show up first | ||
97 | // as Instapaper doesn't export the creation date of the article | ||
98 | $entries = array_reverse($entries); | ||
99 | |||
97 | if ($this->producer) { | 100 | if ($this->producer) { |
98 | $this->parseEntriesForProducer($entries); | 101 | $this->parseEntriesForProducer($entries); |
99 | 102 | ||
@@ -108,6 +111,18 @@ class InstapaperImport extends AbstractImport | |||
108 | /** | 111 | /** |
109 | * {@inheritdoc} | 112 | * {@inheritdoc} |
110 | */ | 113 | */ |
114 | public function validateEntry(array $importedEntry) | ||
115 | { | ||
116 | if (empty($importedEntry['url'])) { | ||
117 | return false; | ||
118 | } | ||
119 | |||
120 | return true; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * {@inheritdoc} | ||
125 | */ | ||
111 | public function parseEntry(array $importedEntry) | 126 | public function parseEntry(array $importedEntry) |
112 | { | 127 | { |
113 | $existingEntry = $this->em | 128 | $existingEntry = $this->em |
@@ -135,7 +150,7 @@ class InstapaperImport extends AbstractImport | |||
135 | ); | 150 | ); |
136 | } | 151 | } |
137 | 152 | ||
138 | $entry->setArchived($importedEntry['is_archived']); | 153 | $entry->updateArchived($importedEntry['is_archived']); |
139 | $entry->setStarred($importedEntry['is_starred']); | 154 | $entry->setStarred($importedEntry['is_starred']); |
140 | 155 | ||
141 | $this->em->persist($entry); | 156 | $this->em->persist($entry); |
diff --git a/src/Wallabag/ImportBundle/Import/PinboardImport.php b/src/Wallabag/ImportBundle/Import/PinboardImport.php index 110b0464..202eb1b3 100644 --- a/src/Wallabag/ImportBundle/Import/PinboardImport.php +++ b/src/Wallabag/ImportBundle/Import/PinboardImport.php | |||
@@ -83,6 +83,18 @@ class PinboardImport extends AbstractImport | |||
83 | /** | 83 | /** |
84 | * {@inheritdoc} | 84 | * {@inheritdoc} |
85 | */ | 85 | */ |
86 | public function validateEntry(array $importedEntry) | ||
87 | { | ||
88 | if (empty($importedEntry['href'])) { | ||
89 | return false; | ||
90 | } | ||
91 | |||
92 | return true; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * {@inheritdoc} | ||
97 | */ | ||
86 | public function parseEntry(array $importedEntry) | 98 | public function parseEntry(array $importedEntry) |
87 | { | 99 | { |
88 | $existingEntry = $this->em | 100 | $existingEntry = $this->em |
@@ -119,7 +131,7 @@ class PinboardImport extends AbstractImport | |||
119 | ); | 131 | ); |
120 | } | 132 | } |
121 | 133 | ||
122 | $entry->setArchived($data['is_archived']); | 134 | $entry->updateArchived($data['is_archived']); |
123 | $entry->setStarred($data['is_starred']); | 135 | $entry->setStarred($data['is_starred']); |
124 | $entry->setCreatedAt(new \DateTime($data['created_at'])); | 136 | $entry->setCreatedAt(new \DateTime($data['created_at'])); |
125 | 137 | ||
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index c1b35b7e..24fdaa2b 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php | |||
@@ -2,13 +2,22 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ImportBundle\Import; | 3 | namespace Wallabag\ImportBundle\Import; |
4 | 4 | ||
5 | use GuzzleHttp\Client; | 5 | use Http\Client\Common\HttpMethodsClient; |
6 | use GuzzleHttp\Exception\RequestException; | 6 | use Http\Client\Common\Plugin\ErrorPlugin; |
7 | use Http\Client\Common\PluginClient; | ||
8 | use Http\Client\Exception\RequestException; | ||
9 | use Http\Client\HttpClient; | ||
10 | use Http\Discovery\MessageFactoryDiscovery; | ||
11 | use Http\Message\MessageFactory; | ||
12 | use Psr\Http\Message\ResponseInterface; | ||
7 | use Wallabag\CoreBundle\Entity\Entry; | 13 | use Wallabag\CoreBundle\Entity\Entry; |
8 | 14 | ||
9 | class PocketImport extends AbstractImport | 15 | class PocketImport extends AbstractImport |
10 | { | 16 | { |
11 | const NB_ELEMENTS = 5000; | 17 | const NB_ELEMENTS = 5000; |
18 | /** | ||
19 | * @var HttpMethodsClient | ||
20 | */ | ||
12 | private $client; | 21 | private $client; |
13 | private $accessToken; | 22 | private $accessToken; |
14 | 23 | ||
@@ -55,24 +64,18 @@ class PocketImport extends AbstractImport | |||
55 | */ | 64 | */ |
56 | public function getRequestToken($redirectUri) | 65 | public function getRequestToken($redirectUri) |
57 | { | 66 | { |
58 | $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', | ||
59 | [ | ||
60 | 'body' => json_encode([ | ||
61 | 'consumer_key' => $this->user->getConfig()->getPocketConsumerKey(), | ||
62 | 'redirect_uri' => $redirectUri, | ||
63 | ]), | ||
64 | ] | ||
65 | ); | ||
66 | |||
67 | try { | 67 | try { |
68 | $response = $this->client->send($request); | 68 | $response = $this->client->post('https://getpocket.com/v3/oauth/request', [], json_encode([ |
69 | 'consumer_key' => $this->user->getConfig()->getPocketConsumerKey(), | ||
70 | 'redirect_uri' => $redirectUri, | ||
71 | ])); | ||
69 | } catch (RequestException $e) { | 72 | } catch (RequestException $e) { |
70 | $this->logger->error(sprintf('PocketImport: Failed to request token: %s', $e->getMessage()), ['exception' => $e]); | 73 | $this->logger->error(sprintf('PocketImport: Failed to request token: %s', $e->getMessage()), ['exception' => $e]); |
71 | 74 | ||
72 | return false; | 75 | return false; |
73 | } | 76 | } |
74 | 77 | ||
75 | return $response->json()['code']; | 78 | return $this->jsonDecode($response)['code']; |
76 | } | 79 | } |
77 | 80 | ||
78 | /** | 81 | /** |
@@ -85,24 +88,18 @@ class PocketImport extends AbstractImport | |||
85 | */ | 88 | */ |
86 | public function authorize($code) | 89 | public function authorize($code) |
87 | { | 90 | { |
88 | $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', | ||
89 | [ | ||
90 | 'body' => json_encode([ | ||
91 | 'consumer_key' => $this->user->getConfig()->getPocketConsumerKey(), | ||
92 | 'code' => $code, | ||
93 | ]), | ||
94 | ] | ||
95 | ); | ||
96 | |||
97 | try { | 91 | try { |
98 | $response = $this->client->send($request); | 92 | $response = $this->client->post('https://getpocket.com/v3/oauth/authorize', [], json_encode([ |
93 | 'consumer_key' => $this->user->getConfig()->getPocketConsumerKey(), | ||
94 | 'code' => $code, | ||
95 | ])); | ||
99 | } catch (RequestException $e) { | 96 | } catch (RequestException $e) { |
100 | $this->logger->error(sprintf('PocketImport: Failed to authorize client: %s', $e->getMessage()), ['exception' => $e]); | 97 | $this->logger->error(sprintf('PocketImport: Failed to authorize client: %s', $e->getMessage()), ['exception' => $e]); |
101 | 98 | ||
102 | return false; | 99 | return false; |
103 | } | 100 | } |
104 | 101 | ||
105 | $this->accessToken = $response->json()['access_token']; | 102 | $this->accessToken = $this->jsonDecode($response)['access_token']; |
106 | 103 | ||
107 | return true; | 104 | return true; |
108 | } | 105 | } |
@@ -114,29 +111,23 @@ class PocketImport extends AbstractImport | |||
114 | { | 111 | { |
115 | static $run = 0; | 112 | static $run = 0; |
116 | 113 | ||
117 | $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/get', | ||
118 | [ | ||
119 | 'body' => json_encode([ | ||
120 | 'consumer_key' => $this->user->getConfig()->getPocketConsumerKey(), | ||
121 | 'access_token' => $this->accessToken, | ||
122 | 'detailType' => 'complete', | ||
123 | 'state' => 'all', | ||
124 | 'sort' => 'newest', | ||
125 | 'count' => self::NB_ELEMENTS, | ||
126 | 'offset' => $offset, | ||
127 | ]), | ||
128 | ] | ||
129 | ); | ||
130 | |||
131 | try { | 114 | try { |
132 | $response = $this->client->send($request); | 115 | $response = $this->client->post('https://getpocket.com/v3/get', [], json_encode([ |
116 | 'consumer_key' => $this->user->getConfig()->getPocketConsumerKey(), | ||
117 | 'access_token' => $this->accessToken, | ||
118 | 'detailType' => 'complete', | ||
119 | 'state' => 'all', | ||
120 | 'sort' => 'newest', | ||
121 | 'count' => self::NB_ELEMENTS, | ||
122 | 'offset' => $offset, | ||
123 | ])); | ||
133 | } catch (RequestException $e) { | 124 | } catch (RequestException $e) { |
134 | $this->logger->error(sprintf('PocketImport: Failed to import: %s', $e->getMessage()), ['exception' => $e]); | 125 | $this->logger->error(sprintf('PocketImport: Failed to import: %s', $e->getMessage()), ['exception' => $e]); |
135 | 126 | ||
136 | return false; | 127 | return false; |
137 | } | 128 | } |
138 | 129 | ||
139 | $entries = $response->json(); | 130 | $entries = $this->jsonDecode($response); |
140 | 131 | ||
141 | if ($this->producer) { | 132 | if ($this->producer) { |
142 | $this->parseEntriesForProducer($entries['list']); | 133 | $this->parseEntriesForProducer($entries['list']); |
@@ -159,13 +150,23 @@ class PocketImport extends AbstractImport | |||
159 | } | 150 | } |
160 | 151 | ||
161 | /** | 152 | /** |
162 | * Set the Guzzle client. | 153 | * Set the Http client. |
163 | * | 154 | */ |
164 | * @param Client $client | 155 | public function setClient(HttpClient $client, MessageFactory $messageFactory = null) |
156 | { | ||
157 | $this->client = new HttpMethodsClient(new PluginClient($client, [new ErrorPlugin()]), $messageFactory ?: MessageFactoryDiscovery::find()); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * {@inheritdoc} | ||
165 | */ | 162 | */ |
166 | public function setClient(Client $client) | 163 | public function validateEntry(array $importedEntry) |
167 | { | 164 | { |
168 | $this->client = $client; | 165 | if (empty($importedEntry['resolved_url']) && empty($importedEntry['given_url'])) { |
166 | return false; | ||
167 | } | ||
168 | |||
169 | return true; | ||
169 | } | 170 | } |
170 | 171 | ||
171 | /** | 172 | /** |
@@ -194,10 +195,10 @@ class PocketImport extends AbstractImport | |||
194 | $this->fetchContent($entry, $url); | 195 | $this->fetchContent($entry, $url); |
195 | 196 | ||
196 | // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted | 197 | // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted |
197 | $entry->setArchived(1 === $importedEntry['status'] || $this->markAsRead); | 198 | $entry->updateArchived(1 === (int) $importedEntry['status'] || $this->markAsRead); |
198 | 199 | ||
199 | // 0 or 1 - 1 If the item is starred | 200 | // 0 or 1 - 1 if the item is starred |
200 | $entry->setStarred(1 === $importedEntry['favorite']); | 201 | $entry->setStarred(1 === (int) $importedEntry['favorite']); |
201 | 202 | ||
202 | $title = 'Untitled'; | 203 | $title = 'Untitled'; |
203 | if (isset($importedEntry['resolved_title']) && '' !== $importedEntry['resolved_title']) { | 204 | if (isset($importedEntry['resolved_title']) && '' !== $importedEntry['resolved_title']) { |
@@ -240,4 +241,15 @@ class PocketImport extends AbstractImport | |||
240 | 241 | ||
241 | return $importedEntry; | 242 | return $importedEntry; |
242 | } | 243 | } |
244 | |||
245 | protected function jsonDecode(ResponseInterface $response) | ||
246 | { | ||
247 | $data = json_decode((string) $response->getBody(), true); | ||
248 | |||
249 | if (JSON_ERROR_NONE !== json_last_error()) { | ||
250 | throw new \InvalidArgumentException('Unable to parse JSON data: ' . json_last_error_msg()); | ||
251 | } | ||
252 | |||
253 | return $data; | ||
254 | } | ||
243 | } | 255 | } |
diff --git a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php index 002b27f4..c5abf189 100644 --- a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php +++ b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php | |||
@@ -83,6 +83,18 @@ class ReadabilityImport extends AbstractImport | |||
83 | /** | 83 | /** |
84 | * {@inheritdoc} | 84 | * {@inheritdoc} |
85 | */ | 85 | */ |
86 | public function validateEntry(array $importedEntry) | ||
87 | { | ||
88 | if (empty($importedEntry['article__url'])) { | ||
89 | return false; | ||
90 | } | ||
91 | |||
92 | return true; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * {@inheritdoc} | ||
97 | */ | ||
86 | public function parseEntry(array $importedEntry) | 98 | public function parseEntry(array $importedEntry) |
87 | { | 99 | { |
88 | $existingEntry = $this->em | 100 | $existingEntry = $this->em |
@@ -111,7 +123,7 @@ class ReadabilityImport extends AbstractImport | |||
111 | // 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) |
112 | $this->fetchContent($entry, $data['url'], $data); | 124 | $this->fetchContent($entry, $data['url'], $data); |
113 | 125 | ||
114 | $entry->setArchived($data['is_archived']); | 126 | $entry->updateArchived($data['is_archived']); |
115 | $entry->setStarred($data['is_starred']); | 127 | $entry->setStarred($data['is_starred']); |
116 | $entry->setCreatedAt(new \DateTime($data['created_at'])); | 128 | $entry->setCreatedAt(new \DateTime($data['created_at'])); |
117 | 129 | ||
diff --git a/src/Wallabag/ImportBundle/Import/WallabagImport.php b/src/Wallabag/ImportBundle/Import/WallabagImport.php index c64ccd64..75a28fbf 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagImport.php +++ b/src/Wallabag/ImportBundle/Import/WallabagImport.php | |||
@@ -89,6 +89,18 @@ abstract class WallabagImport extends AbstractImport | |||
89 | /** | 89 | /** |
90 | * {@inheritdoc} | 90 | * {@inheritdoc} |
91 | */ | 91 | */ |
92 | public function validateEntry(array $importedEntry) | ||
93 | { | ||
94 | if (empty($importedEntry['url'])) { | ||
95 | return false; | ||
96 | } | ||
97 | |||
98 | return true; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * {@inheritdoc} | ||
103 | */ | ||
92 | public function parseEntry(array $importedEntry) | 104 | public function parseEntry(array $importedEntry) |
93 | { | 105 | { |
94 | $existingEntry = $this->em | 106 | $existingEntry = $this->em |
@@ -110,7 +122,7 @@ abstract class WallabagImport extends AbstractImport | |||
110 | // update entry with content (in case fetching failed, the given entry will be return) | 122 | // update entry with content (in case fetching failed, the given entry will be return) |
111 | $this->fetchContent($entry, $data['url'], $data); | 123 | $this->fetchContent($entry, $data['url'], $data); |
112 | 124 | ||
113 | if (array_key_exists('tags', $data)) { | 125 | if (\array_key_exists('tags', $data)) { |
114 | $this->tagsAssigner->assignTagsToEntry( | 126 | $this->tagsAssigner->assignTagsToEntry( |
115 | $entry, | 127 | $entry, |
116 | $data['tags'], | 128 | $data['tags'], |
@@ -122,7 +134,7 @@ abstract class WallabagImport extends AbstractImport | |||
122 | $entry->setPreviewPicture($importedEntry['preview_picture']); | 134 | $entry->setPreviewPicture($importedEntry['preview_picture']); |
123 | } | 135 | } |
124 | 136 | ||
125 | $entry->setArchived($data['is_archived']); | 137 | $entry->updateArchived($data['is_archived']); |
126 | $entry->setStarred($data['is_starred']); | 138 | $entry->setStarred($data['is_starred']); |
127 | 139 | ||
128 | if (!empty($data['created_at'])) { | 140 | if (!empty($data['created_at'])) { |
diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php index b9bb525a..e0562611 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php | |||
@@ -61,7 +61,7 @@ class WallabagV1Import extends WallabagImport | |||
61 | $data['html'] = $this->fetchingErrorMessage; | 61 | $data['html'] = $this->fetchingErrorMessage; |
62 | } | 62 | } |
63 | 63 | ||
64 | if (array_key_exists('tags', $entry) && '' !== $entry['tags']) { | 64 | if (\array_key_exists('tags', $entry) && '' !== $entry['tags']) { |
65 | $data['tags'] = $entry['tags']; | 65 | $data['tags'] = $entry['tags']; |
66 | } | 66 | } |
67 | 67 | ||
diff --git a/src/Wallabag/ImportBundle/Import/WallabagV2Import.php b/src/Wallabag/ImportBundle/Import/WallabagV2Import.php index 3e085ecf..2ba26003 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV2Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV2Import.php | |||
@@ -35,7 +35,9 @@ class WallabagV2Import extends WallabagImport | |||
35 | { | 35 | { |
36 | return [ | 36 | return [ |
37 | 'html' => $entry['content'], | 37 | 'html' => $entry['content'], |
38 | 'content_type' => $entry['mimetype'], | 38 | 'headers' => [ |
39 | 'content-type' => $entry['mimetype'], | ||
40 | ], | ||
39 | 'is_archived' => (bool) ($entry['is_archived'] || $this->markAsRead), | 41 | 'is_archived' => (bool) ($entry['is_archived'] || $this->markAsRead), |
40 | 'is_starred' => (bool) $entry['is_starred'], | 42 | 'is_starred' => (bool) $entry['is_starred'], |
41 | ] + $entry; | 43 | ] + $entry; |
diff --git a/src/Wallabag/ImportBundle/Resources/config/rabbit.yml b/src/Wallabag/ImportBundle/Resources/config/rabbit.yml index e9ecb846..0bf0e761 100644 --- a/src/Wallabag/ImportBundle/Resources/config/rabbit.yml +++ b/src/Wallabag/ImportBundle/Resources/config/rabbit.yml | |||
@@ -48,6 +48,14 @@ services: | |||
48 | - "@wallabag_import.wallabag_v2.import" | 48 | - "@wallabag_import.wallabag_v2.import" |
49 | - "@event_dispatcher" | 49 | - "@event_dispatcher" |
50 | - "@logger" | 50 | - "@logger" |
51 | wallabag_import.consumer.amqp.elcurator: | ||
52 | class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer | ||
53 | arguments: | ||
54 | - "@doctrine.orm.entity_manager" | ||
55 | - "@wallabag_user.user_repository" | ||
56 | - "@wallabag_import.elcurator.import" | ||
57 | - "@event_dispatcher" | ||
58 | - "@logger" | ||
51 | wallabag_import.consumer.amqp.firefox: | 59 | wallabag_import.consumer.amqp.firefox: |
52 | class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer | 60 | class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer |
53 | arguments: | 61 | arguments: |
diff --git a/src/Wallabag/ImportBundle/Resources/config/redis.yml b/src/Wallabag/ImportBundle/Resources/config/redis.yml index 091cdba0..40a6e224 100644 --- a/src/Wallabag/ImportBundle/Resources/config/redis.yml +++ b/src/Wallabag/ImportBundle/Resources/config/redis.yml | |||
@@ -126,6 +126,27 @@ services: | |||
126 | - "@event_dispatcher" | 126 | - "@event_dispatcher" |
127 | - "@logger" | 127 | - "@logger" |
128 | 128 | ||
129 | # elcurator | ||
130 | wallabag_import.queue.redis.elcurator: | ||
131 | class: Simpleue\Queue\RedisQueue | ||
132 | arguments: | ||
133 | - "@wallabag_core.redis.client" | ||
134 | - "wallabag.import.elcurator" | ||
135 | |||
136 | wallabag_import.producer.redis.elcurator: | ||
137 | class: Wallabag\ImportBundle\Redis\Producer | ||
138 | arguments: | ||
139 | - "@wallabag_import.queue.redis.elcurator" | ||
140 | |||
141 | wallabag_import.consumer.redis.elcurator: | ||
142 | class: Wallabag\ImportBundle\Consumer\RedisEntryConsumer | ||
143 | arguments: | ||
144 | - "@doctrine.orm.entity_manager" | ||
145 | - "@wallabag_user.user_repository" | ||
146 | - "@wallabag_import.elcurator.import" | ||
147 | - "@event_dispatcher" | ||
148 | - "@logger" | ||
149 | |||
129 | # firefox | 150 | # firefox |
130 | wallabag_import.queue.redis.firefox: | 151 | wallabag_import.queue.redis.firefox: |
131 | class: Simpleue\Queue\RedisQueue | 152 | class: Simpleue\Queue\RedisQueue |
diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index b224a6a2..d824da4a 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml | |||
@@ -7,13 +7,7 @@ services: | |||
7 | class: Wallabag\ImportBundle\Import\ImportChain | 7 | class: Wallabag\ImportBundle\Import\ImportChain |
8 | 8 | ||
9 | wallabag_import.pocket.client: | 9 | wallabag_import.pocket.client: |
10 | class: GuzzleHttp\Client | 10 | alias: 'httplug.client.wallabag_import.pocket.client' |
11 | arguments: | ||
12 | - | ||
13 | defaults: | ||
14 | headers: | ||
15 | content-type: "application/json" | ||
16 | X-Accept: "application/json" | ||
17 | 11 | ||
18 | wallabag_import.pocket.import: | 12 | wallabag_import.pocket.import: |
19 | class: Wallabag\ImportBundle\Import\PocketImport | 13 | class: Wallabag\ImportBundle\Import\PocketImport |
@@ -54,6 +48,18 @@ services: | |||
54 | tags: | 48 | tags: |
55 | - { name: wallabag_import.import, alias: wallabag_v2 } | 49 | - { name: wallabag_import.import, alias: wallabag_v2 } |
56 | 50 | ||
51 | wallabag_import.elcurator.import: | ||
52 | class: Wallabag\ImportBundle\Import\ElcuratorImport | ||
53 | arguments: | ||
54 | - "@doctrine.orm.entity_manager" | ||
55 | - "@wallabag_core.content_proxy" | ||
56 | - "@wallabag_core.tags_assigner" | ||
57 | - "@event_dispatcher" | ||
58 | calls: | ||
59 | - [ setLogger, [ "@logger" ]] | ||
60 | tags: | ||
61 | - { name: wallabag_import.import, alias: elcurator } | ||
62 | |||
57 | wallabag_import.readability.import: | 63 | wallabag_import.readability.import: |
58 | class: Wallabag\ImportBundle\Import\ReadabilityImport | 64 | class: Wallabag\ImportBundle\Import\ReadabilityImport |
59 | arguments: | 65 | arguments: |
@@ -112,3 +118,11 @@ services: | |||
112 | - [ setLogger, [ "@logger" ]] | 118 | - [ setLogger, [ "@logger" ]] |
113 | tags: | 119 | tags: |
114 | - { name: wallabag_import.import, alias: chrome } | 120 | - { name: wallabag_import.import, alias: chrome } |
121 | |||
122 | wallabag_import.command.import: | ||
123 | class: Wallabag\ImportBundle\Command\ImportCommand | ||
124 | tags: ['console.command'] | ||
125 | |||
126 | wallabag_import.command.redis_worker: | ||
127 | class: Wallabag\ImportBundle\Command\RedisWorkerCommand | ||
128 | tags: ['console.command'] | ||
diff --git a/src/Wallabag/ImportBundle/Resources/views/Elcurator/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Elcurator/index.html.twig new file mode 100644 index 00000000..e3a0d709 --- /dev/null +++ b/src/Wallabag/ImportBundle/Resources/views/Elcurator/index.html.twig | |||
@@ -0,0 +1,3 @@ | |||
1 | {% extends "WallabagImportBundle:WallabagV1:index.html.twig" %} | ||
2 | |||
3 | {% block title %}{{ 'import.elcurator.page_title'|trans }}{% endblock %} | ||
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php index f3de656f..1122f8f0 100644 --- a/src/Wallabag/UserBundle/Controller/ManageController.php +++ b/src/Wallabag/UserBundle/Controller/ManageController.php | |||
@@ -7,10 +7,9 @@ use FOS\UserBundle\FOSUserEvents; | |||
7 | use Pagerfanta\Adapter\DoctrineORMAdapter; | 7 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
8 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 8 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
9 | use Pagerfanta\Pagerfanta; | 9 | use Pagerfanta\Pagerfanta; |
10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | ||
11 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
12 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 10 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
13 | use Symfony\Component\HttpFoundation\Request; | 11 | use Symfony\Component\HttpFoundation\Request; |
12 | use Symfony\Component\Routing\Annotation\Route; | ||
14 | use Wallabag\UserBundle\Entity\User; | 13 | use Wallabag\UserBundle\Entity\User; |
15 | use Wallabag\UserBundle\Form\SearchUserType; | 14 | use 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 | { |
@@ -116,8 +127,7 @@ class ManageController extends Controller | |||
116 | } | 127 | } |
117 | 128 | ||
118 | /** | 129 | /** |
119 | * @param Request $request | 130 | * @param int $page |
120 | * @param int $page | ||
121 | * | 131 | * |
122 | * @Route("/list/{page}", name="user_index", defaults={"page" = 1}) | 132 | * @Route("/list/{page}", name="user_index", defaults={"page" = 1}) |
123 | * | 133 | * |
@@ -135,8 +145,6 @@ class ManageController extends Controller | |||
135 | $form->handleRequest($request); | 145 | $form->handleRequest($request); |
136 | 146 | ||
137 | if ($form->isSubmitted() && $form->isValid()) { | 147 | 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'] : ''); | 148 | $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : ''); |
141 | 149 | ||
142 | $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); | 150 | $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); |
@@ -161,7 +169,7 @@ class ManageController extends Controller | |||
161 | } | 169 | } |
162 | 170 | ||
163 | /** | 171 | /** |
164 | * Creates a form to delete a User entity. | 172 | * Create a form to delete a User entity. |
165 | * | 173 | * |
166 | * @param User $user The User entity | 174 | * @param User $user The User entity |
167 | * | 175 | * |
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 | ||
3 | namespace Wallabag\UserBundle\DataFixtures\ORM; | 3 | namespace Wallabag\UserBundle\DataFixtures; |
4 | 4 | ||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | 5 | use Doctrine\Bundle\FixturesBundle\Fixture; |
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | ||
7 | use Doctrine\Common\Persistence\ObjectManager; | 6 | use Doctrine\Common\Persistence\ObjectManager; |
8 | use Wallabag\UserBundle\Entity\User; | 7 | use Wallabag\UserBundle\Entity\User; |
9 | 8 | ||
10 | class LoadUserData extends AbstractFixture implements OrderedFixtureInterface | 9 | class 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..aeab761d 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; | |||
8 | use JMS\Serializer\Annotation\Accessor; | 8 | use JMS\Serializer\Annotation\Accessor; |
9 | use JMS\Serializer\Annotation\Groups; | 9 | use JMS\Serializer\Annotation\Groups; |
10 | use JMS\Serializer\Annotation\XmlRoot; | 10 | use JMS\Serializer\Annotation\XmlRoot; |
11 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | 11 | use Scheb\TwoFactorBundle\Model\BackupCodeInterface; |
12 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; | 12 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface as EmailTwoFactorInterface; |
13 | use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface as GoogleTwoFactorInterface; | ||
13 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | 14 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; |
14 | use Symfony\Component\Security\Core\User\UserInterface; | 15 | use Symfony\Component\Security\Core\User\UserInterface; |
15 | use Wallabag\ApiBundle\Entity\Client; | 16 | use 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 | */ |
31 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | 32 | class 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 | { |
@@ -182,8 +188,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
182 | } | 188 | } |
183 | 189 | ||
184 | /** | 190 | /** |
185 | * @param Entry $entry | ||
186 | * | ||
187 | * @return User | 191 | * @return User |
188 | */ | 192 | */ |
189 | public function addEntry(Entry $entry) | 193 | public function addEntry(Entry $entry) |
@@ -233,54 +237,122 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
233 | /** | 237 | /** |
234 | * @return bool | 238 | * @return bool |
235 | */ | 239 | */ |
236 | public function isTwoFactorAuthentication() | 240 | public function isEmailTwoFactor() |
237 | { | 241 | { |
238 | return $this->twoFactorAuthentication; | 242 | return $this->emailTwoFactor; |
239 | } | 243 | } |
240 | 244 | ||
241 | /** | 245 | /** |
242 | * @param bool $twoFactorAuthentication | 246 | * @param bool $emailTwoFactor |
243 | */ | 247 | */ |
244 | public function setTwoFactorAuthentication($twoFactorAuthentication) | 248 | public function setEmailTwoFactor($emailTwoFactor) |
245 | { | 249 | { |
246 | $this->twoFactorAuthentication = $twoFactorAuthentication; | 250 | $this->emailTwoFactor = $emailTwoFactor; |
247 | } | 251 | } |
248 | 252 | ||
249 | public function isEmailAuthEnabled() | 253 | /** |
254 | * Used in the user config form to be "like" the email option. | ||
255 | */ | ||
256 | public function isGoogleTwoFactor() | ||
250 | { | 257 | { |
251 | return $this->twoFactorAuthentication; | 258 | return $this->isGoogleAuthenticatorEnabled(); |
252 | } | 259 | } |
253 | 260 | ||
254 | public function getEmailAuthCode() | 261 | /** |
262 | * {@inheritdoc} | ||
263 | */ | ||
264 | public function isEmailAuthEnabled(): bool | ||
265 | { | ||
266 | return $this->emailTwoFactor; | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * {@inheritdoc} | ||
271 | */ | ||
272 | public function getEmailAuthCode(): string | ||
255 | { | 273 | { |
256 | return $this->authCode; | 274 | return $this->authCode; |
257 | } | 275 | } |
258 | 276 | ||
259 | public function setEmailAuthCode($authCode) | 277 | /** |
278 | * {@inheritdoc} | ||
279 | */ | ||
280 | public function setEmailAuthCode(string $authCode): void | ||
260 | { | 281 | { |
261 | $this->authCode = $authCode; | 282 | $this->authCode = $authCode; |
262 | } | 283 | } |
263 | 284 | ||
264 | public function addTrustedComputer($token, \DateTime $validUntil) | 285 | /** |
286 | * {@inheritdoc} | ||
287 | */ | ||
288 | public function getEmailAuthRecipient(): string | ||
265 | { | 289 | { |
266 | $this->trusted[$token] = $validUntil->format('r'); | 290 | return $this->email; |
267 | } | 291 | } |
268 | 292 | ||
269 | public function isTrustedComputer($token) | 293 | /** |
294 | * {@inheritdoc} | ||
295 | */ | ||
296 | public function isGoogleAuthenticatorEnabled(): bool | ||
270 | { | 297 | { |
271 | if (isset($this->trusted[$token])) { | 298 | return $this->googleAuthenticatorSecret ? true : false; |
272 | $now = new \DateTime(); | 299 | } |
273 | $validUntil = new \DateTime($this->trusted[$token]); | ||
274 | 300 | ||
275 | return $now < $validUntil; | 301 | /** |
276 | } | 302 | * {@inheritdoc} |
303 | */ | ||
304 | public function getGoogleAuthenticatorUsername(): string | ||
305 | { | ||
306 | return $this->username; | ||
307 | } | ||
277 | 308 | ||
278 | return false; | 309 | /** |
310 | * {@inheritdoc} | ||
311 | */ | ||
312 | public function getGoogleAuthenticatorSecret(): string | ||
313 | { | ||
314 | return $this->googleAuthenticatorSecret; | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * {@inheritdoc} | ||
319 | */ | ||
320 | public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): void | ||
321 | { | ||
322 | $this->googleAuthenticatorSecret = $googleAuthenticatorSecret; | ||
323 | } | ||
324 | |||
325 | public function setBackupCodes(array $codes = null) | ||
326 | { | ||
327 | $this->backupCodes = $codes; | ||
328 | } | ||
329 | |||
330 | public function getBackupCodes() | ||
331 | { | ||
332 | return $this->backupCodes; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * {@inheritdoc} | ||
337 | */ | ||
338 | public function isBackupCode(string $code): bool | ||
339 | { | ||
340 | return false === $this->findBackupCode($code) ? false : true; | ||
341 | } | ||
342 | |||
343 | /** | ||
344 | * {@inheritdoc} | ||
345 | */ | ||
346 | public function invalidateBackupCode(string $code): void | ||
347 | { | ||
348 | $key = $this->findBackupCode($code); | ||
349 | |||
350 | if (false !== $key) { | ||
351 | unset($this->backupCodes[$key]); | ||
352 | } | ||
279 | } | 353 | } |
280 | 354 | ||
281 | /** | 355 | /** |
282 | * @param Client $client | ||
283 | * | ||
284 | * @return User | 356 | * @return User |
285 | */ | 357 | */ |
286 | public function addClient(Client $client) | 358 | public function addClient(Client $client) |
@@ -309,4 +381,24 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
309 | return $this->clients->first(); | 381 | return $this->clients->first(); |
310 | } | 382 | } |
311 | } | 383 | } |
384 | |||
385 | /** | ||
386 | * Try to find a backup code from the list of backup codes of the current user. | ||
387 | * | ||
388 | * @param string $code Given code from the user | ||
389 | * | ||
390 | * @return string|false | ||
391 | */ | ||
392 | private function findBackupCode(string $code) | ||
393 | { | ||
394 | foreach ($this->backupCodes as $key => $backupCode) { | ||
395 | // backup code are hashed using `password_hash` | ||
396 | // see ConfigController->otpAppAction | ||
397 | if (password_verify($code, $backupCode)) { | ||
398 | return $key; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | return false; | ||
403 | } | ||
312 | } | 404 | } |
diff --git a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php index e4d55c19..81954213 100644 --- a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php +++ b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php | |||
@@ -6,6 +6,7 @@ use Doctrine\ORM\EntityManager; | |||
6 | use FOS\UserBundle\Event\UserEvent; | 6 | use FOS\UserBundle\Event\UserEvent; |
7 | use FOS\UserBundle\FOSUserEvents; | 7 | use FOS\UserBundle\FOSUserEvents; |
8 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | 8 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
9 | use Symfony\Component\HttpFoundation\Session\Session; | ||
9 | use Wallabag\CoreBundle\Entity\Config; | 10 | use Wallabag\CoreBundle\Entity\Config; |
10 | 11 | ||
11 | /** | 12 | /** |
@@ -17,22 +18,24 @@ class CreateConfigListener implements EventSubscriberInterface | |||
17 | private $em; | 18 | private $em; |
18 | private $theme; | 19 | private $theme; |
19 | private $itemsOnPage; | 20 | private $itemsOnPage; |
20 | private $rssLimit; | 21 | private $feedLimit; |
21 | private $language; | 22 | private $language; |
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, $feedLimit, $language, $readingSpeed, $actionMarkAsRead, $listMode, Session $session) |
27 | { | 29 | { |
28 | $this->em = $em; | 30 | $this->em = $em; |
29 | $this->theme = $theme; | 31 | $this->theme = $theme; |
30 | $this->itemsOnPage = $itemsOnPage; | 32 | $this->itemsOnPage = $itemsOnPage; |
31 | $this->rssLimit = $rssLimit; | 33 | $this->feedLimit = $feedLimit; |
32 | $this->language = $language; | 34 | $this->language = $language; |
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() |
@@ -51,8 +54,8 @@ class CreateConfigListener implements EventSubscriberInterface | |||
51 | $config = new Config($event->getUser()); | 54 | $config = new Config($event->getUser()); |
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->setFeedLimit($this->feedLimit); |
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..03fad971 100644 --- a/src/Wallabag/UserBundle/Form/UserType.php +++ b/src/Wallabag/UserBundle/Form/UserType.php | |||
@@ -12,10 +12,6 @@ use Symfony\Component\OptionsResolver\OptionsResolver; | |||
12 | 12 | ||
13 | class UserType extends AbstractType | 13 | class UserType extends AbstractType |
14 | { | 14 | { |
15 | /** | ||
16 | * @param FormBuilderInterface $builder | ||
17 | * @param array $options | ||
18 | */ | ||
19 | public function buildForm(FormBuilderInterface $builder, array $options) | 15 | public function buildForm(FormBuilderInterface $builder, array $options) |
20 | { | 16 | { |
21 | $builder | 17 | $builder |
@@ -35,9 +31,14 @@ class UserType extends AbstractType | |||
35 | 'required' => false, | 31 | 'required' => false, |
36 | 'label' => 'user.form.enabled_label', | 32 | 'label' => 'user.form.enabled_label', |
37 | ]) | 33 | ]) |
38 | ->add('twoFactorAuthentication', CheckboxType::class, [ | 34 | ->add('emailTwoFactor', CheckboxType::class, [ |
39 | 'required' => false, | 35 | 'required' => false, |
40 | 'label' => 'user.form.twofactor_label', | 36 | 'label' => 'user.form.twofactor_email_label', |
37 | ]) | ||
38 | ->add('googleTwoFactor', CheckboxType::class, [ | ||
39 | 'required' => false, | ||
40 | 'label' => 'user.form.twofactor_google_label', | ||
41 | 'mapped' => false, | ||
41 | ]) | 42 | ]) |
42 | ->add('save', SubmitType::class, [ | 43 | ->add('save', SubmitType::class, [ |
43 | 'label' => 'user.form.save', | 44 | 'label' => 'user.form.save', |
@@ -45,9 +46,6 @@ class UserType extends AbstractType | |||
45 | ; | 46 | ; |
46 | } | 47 | } |
47 | 48 | ||
48 | /** | ||
49 | * @param OptionsResolver $resolver | ||
50 | */ | ||
51 | public function configureOptions(OptionsResolver $resolver) | 49 | public function configureOptions(OptionsResolver $resolver) |
52 | { | 50 | { |
53 | $resolver->setDefaults([ | 51 | $resolver->setDefaults([ |
diff --git a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php index aed805c9..4eea444f 100644 --- a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php +++ b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php | |||
@@ -4,6 +4,7 @@ namespace Wallabag\UserBundle\Mailer; | |||
4 | 4 | ||
5 | use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface; | 5 | use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface; |
6 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | 6 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; |
7 | use Twig\Environment; | ||
7 | 8 | ||
8 | /** | 9 | /** |
9 | * Custom mailer for TwoFactorBundle email. | 10 | * Custom mailer for TwoFactorBundle email. |
@@ -21,7 +22,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface | |||
21 | /** | 22 | /** |
22 | * Twig to render the html's email. | 23 | * Twig to render the html's email. |
23 | * | 24 | * |
24 | * @var \Twig_Environment | 25 | * @var Environment |
25 | */ | 26 | */ |
26 | private $twig; | 27 | private $twig; |
27 | 28 | ||
@@ -56,14 +57,12 @@ class AuthCodeMailer implements AuthCodeMailerInterface | |||
56 | /** | 57 | /** |
57 | * Initialize the auth code mailer with the SwiftMailer object. | 58 | * Initialize the auth code mailer with the SwiftMailer object. |
58 | * | 59 | * |
59 | * @param \Swift_Mailer $mailer | 60 | * @param string $senderEmail |
60 | * @param \Twig_Environment $twig | 61 | * @param string $senderName |
61 | * @param string $senderEmail | 62 | * @param string $supportUrl wallabag support url |
62 | * @param string $senderName | 63 | * @param string $wallabagUrl wallabag instance url |
63 | * @param string $supportUrl wallabag support url | ||
64 | * @param string $wallabagUrl wallabag instance url | ||
65 | */ | 64 | */ |
66 | public function __construct(\Swift_Mailer $mailer, \Twig_Environment $twig, $senderEmail, $senderName, $supportUrl, $wallabagUrl) | 65 | public function __construct(\Swift_Mailer $mailer, Environment $twig, $senderEmail, $senderName, $supportUrl, $wallabagUrl) |
67 | { | 66 | { |
68 | $this->mailer = $mailer; | 67 | $this->mailer = $mailer; |
69 | $this->twig = $twig; | 68 | $this->twig = $twig; |
@@ -75,10 +74,8 @@ class AuthCodeMailer implements AuthCodeMailerInterface | |||
75 | 74 | ||
76 | /** | 75 | /** |
77 | * Send the auth code to the user via email. | 76 | * Send the auth code to the user via email. |
78 | * | ||
79 | * @param TwoFactorInterface $user | ||
80 | */ | 77 | */ |
81 | public function sendAuthCode(TwoFactorInterface $user) | 78 | public function sendAuthCode(TwoFactorInterface $user): void |
82 | { | 79 | { |
83 | $template = $this->twig->loadTemplate('WallabagUserBundle:TwoFactor:email_auth_code.html.twig'); | 80 | $template = $this->twig->loadTemplate('WallabagUserBundle:TwoFactor:email_auth_code.html.twig'); |
84 | 81 | ||
@@ -97,7 +94,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface | |||
97 | 94 | ||
98 | $message = new \Swift_Message(); | 95 | $message = new \Swift_Message(); |
99 | $message | 96 | $message |
100 | ->setTo($user->getEmail()) | 97 | ->setTo($user->getEmailAuthRecipient()) |
101 | ->setFrom($this->senderEmail, $this->senderName) | 98 | ->setFrom($this->senderEmail, $this->senderName) |
102 | ->setSubject($subject) | 99 | ->setSubject($subject) |
103 | ->setBody($bodyText, 'text/plain') | 100 | ->setBody($bodyText, 'text/plain') |
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php index be693d3b..4abd55f1 100644 --- a/src/Wallabag/UserBundle/Repository/UserRepository.php +++ b/src/Wallabag/UserBundle/Repository/UserRepository.php | |||
@@ -9,18 +9,18 @@ use Wallabag\UserBundle\Entity\User; | |||
9 | class UserRepository extends EntityRepository | 9 | class UserRepository extends EntityRepository |
10 | { | 10 | { |
11 | /** | 11 | /** |
12 | * Find a user by its username and rss roken. | 12 | * Find a user by its username and Feed token. |
13 | * | 13 | * |
14 | * @param string $username | 14 | * @param string $username |
15 | * @param string $rssToken | 15 | * @param string $feedToken |
16 | * | 16 | * |
17 | * @return User|null | 17 | * @return User|null |
18 | */ | 18 | */ |
19 | public function findOneByUsernameAndRsstoken($username, $rssToken) | 19 | public function findOneByUsernameAndFeedtoken($username, $feedToken) |
20 | { | 20 | { |
21 | return $this->createQueryBuilder('u') | 21 | return $this->createQueryBuilder('u') |
22 | ->leftJoin('u.config', 'c') | 22 | ->leftJoin('u.config', 'c') |
23 | ->where('c.rssToken = :rss_token')->setParameter('rss_token', $rssToken) | 23 | ->where('c.feedToken = :feed_token')->setParameter('feed_token', $feedToken) |
24 | ->andWhere('u.username = :username')->setParameter('username', $username) | 24 | ->andWhere('u.username = :username')->setParameter('username', $username) |
25 | ->getQuery() | 25 | ->getQuery() |
26 | ->getOneOrNullResult(); | 26 | ->getOneOrNullResult(); |
diff --git a/src/Wallabag/UserBundle/Resources/config/services.yml b/src/Wallabag/UserBundle/Resources/config/services.yml index d3925de3..2dcf3011 100644 --- a/src/Wallabag/UserBundle/Resources/config/services.yml +++ b/src/Wallabag/UserBundle/Resources/config/services.yml | |||
@@ -28,11 +28,12 @@ services: | |||
28 | - "@doctrine.orm.entity_manager" | 28 | - "@doctrine.orm.entity_manager" |
29 | - "%wallabag_core.theme%" | 29 | - "%wallabag_core.theme%" |
30 | - "%wallabag_core.items_on_page%" | 30 | - "%wallabag_core.items_on_page%" |
31 | - "%wallabag_core.rss_limit%" | 31 | - "%wallabag_core.feed_limit%" |
32 | - "%wallabag_core.language%" | 32 | - "%wallabag_core.language%" |
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..e15ed255 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,15 +10,20 @@ | |||
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, 'SchebTwoFactorBundle') }}</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">{{ "auth_code"|trans({}, 'SchebTwoFactorBundle') }}</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">{{ "trusted"|trans({}, 'SchebTwoFactorBundle') }}</label> |
21 | </div> | 27 | </div> |
22 | {% endif %} | 28 | {% endif %} |
23 | </div> | 29 | </div> |
@@ -25,7 +31,7 @@ | |||
25 | <div class="card-action center"> | 31 | <div class="card-action center"> |
26 | <a href="{{ path('fos_user_security_logout') }}" class="waves-effect waves-light grey btn">{{ 'security.login.cancel'|trans }}</a> | 32 | <a href="{{ path('fos_user_security_logout') }}" class="waves-effect waves-light grey btn">{{ 'security.login.cancel'|trans }}</a> |
27 | <button class="btn waves-effect waves-light" type="submit" name="send"> | 33 | <button class="btn waves-effect waves-light" type="submit" name="send"> |
28 | {{ "scheb_two_factor.login"|trans }} | 34 | {{ "login"|trans({}, 'SchebTwoFactorBundle') }} |
29 | <i class="material-icons right">send</i> | 35 | <i class="material-icons right">send</i> |
30 | </button> | 36 | </button> |
31 | </div> | 37 | </div> |
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/TwoFactor/email_auth_code.html.twig b/src/Wallabag/UserBundle/Resources/views/TwoFactor/email_auth_code.html.twig index ecc1d79a..cd5aaf40 100644 --- a/src/Wallabag/UserBundle/Resources/views/TwoFactor/email_auth_code.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/TwoFactor/email_auth_code.html.twig | |||
@@ -74,7 +74,7 @@ | |||
74 | 74 | ||
75 | <table cellpadding="0" cellspacing="0" border="0" align="center" id="card"> | 75 | <table cellpadding="0" cellspacing="0" border="0" align="center" id="card"> |
76 | <tr> | 76 | <tr> |
77 | <td style="padding: 20px;" width="96px" valign="top"><img class="image_fix" src="{{ absolute_url(asset('wallassets/themes/_global/img/logo-other_themes.png')) }}" alt="logo" title="{{ wallabag_url }}" style="width: 96px; height: 96px;" /></td> | 77 | <td style="padding: 20px;" width="96px" valign="top"><img class="image_fix" src="{{ absolute_url(asset('wallassets/themes/_global/img/logo-square.svg')) }}" alt="logo" title="{{ wallabag_url }}" style="width: 96px; height: 96px;" /></td> |
78 | <td style="padding: 20px; padding-left: 0;" valign="top" id="cell_desc"> | 78 | <td style="padding: 20px; padding-left: 0;" valign="top" id="cell_desc"> |
79 | <h1>wallabag</h1> | 79 | <h1>wallabag</h1> |
80 | <h5>{{ "auth_code.on"|trans({}, 'wallabag_user') }} {{ wallabag_url }}</h5> | 80 | <h5>{{ "auth_code.on"|trans({}, 'wallabag_user') }} {{ wallabag_url }}</h5> |
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 %} |