]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Add ability to import/export tagging rules 4028/head
authorJeremy Benoist <jeremy.benoist@gmail.com>
Wed, 26 Jun 2019 20:31:47 +0000 (22:31 +0200)
committerJeremy Benoist <jeremy.benoist@gmail.com>
Mon, 8 Jul 2019 07:38:32 +0000 (09:38 +0200)
- Add missing translations
- Add some tests
- Add `/api/taggingrule/export` API endpoint
- Add baggy theme
- Add error message when importing tagging rules failed
- Also fix all translations (I think we are good now)

25 files changed:
.gitignore
src/Wallabag/ApiBundle/Controller/TaggingRuleRestController.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
src/Wallabag/CoreBundle/Controller/ConfigController.php
src/Wallabag/CoreBundle/Entity/TaggingRule.php
src/Wallabag/CoreBundle/Form/Type/TaggingRuleImportType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml
src/Wallabag/CoreBundle/Resources/translations/messages.th.yml
src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
tests/Wallabag/ApiBundle/Controller/TaggingRuleRestControllerTest.php [new file with mode: 0644]
tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php
tests/Wallabag/CoreBundle/fixtures/tagging_rules_admin.json [new file with mode: 0644]

index 49ff72c6d6d3b7e38beb780b456f2ba4f5fe9d60..553b0e947ff22e211c72e97164f14d6efc7fbc0c 100644 (file)
@@ -32,6 +32,7 @@ web/uploads/
 # Build
 /app/build
 /build
+/coverage
 
 # Composer PHAR
 /composer.phar
diff --git a/src/Wallabag/ApiBundle/Controller/TaggingRuleRestController.php b/src/Wallabag/ApiBundle/Controller/TaggingRuleRestController.php
new file mode 100644 (file)
index 0000000..2496298
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+namespace Wallabag\ApiBundle\Controller;
+
+use JMS\Serializer\SerializationContext;
+use JMS\Serializer\SerializerBuilder;
+use Nelmio\ApiDocBundle\Annotation\ApiDoc;
+use Symfony\Component\HttpFoundation\Response;
+
+class TaggingRuleRestController extends WallabagRestController
+{
+    /**
+     * Export all tagging rules as a json file.
+     *
+     * @ApiDoc()
+     *
+     * @return Response
+     */
+    public function getTaggingruleExportAction()
+    {
+        $this->validateAuthentication();
+
+        $data = SerializerBuilder::create()->build()->serialize(
+            $this->getUser()->getConfig()->getTaggingRules(),
+            'json',
+            SerializationContext::create()->setGroups(['export_tagging_rule'])
+        );
+
+        return Response::create(
+            $data,
+            200,
+            [
+                'Content-type' => 'application/json',
+                'Content-Disposition' => 'attachment; filename="tagging_rules_' . $this->getUser()->getUsername() . '.json"',
+                'Content-Transfer-Encoding' => 'UTF-8',
+            ]
+        );
+    }
+}
index 06e62c379eedfd96778526474421f86d15d37e00..98efeeb12dc98324d35a6fb16cdcb0bcc1386c92 100644 (file)
@@ -13,6 +13,11 @@ tag:
   resource: "WallabagApiBundle:TagRest"
   name_prefix:  api_
 
+tagging_rule:
+  type: rest
+  resource: "WallabagApiBundle:TaggingRuleRest"
+  name_prefix:  api_
+
 annotation:
   type: rest
   resource: "WallabagApiBundle:AnnotationRest"
index cea4130317e7ebfea4afc1430534718f7b939642..0db90ba4bcfc291abe0d945abaf633e5372c2bc0 100644 (file)
@@ -2,11 +2,14 @@
 
 namespace Wallabag\CoreBundle\Controller;
 
+use JMS\Serializer\SerializationContext;
+use JMS\Serializer\SerializerBuilder;
 use PragmaRX\Recovery\Recovery as BackupCodes;
 use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\Routing\Annotation\Route;
 use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint;
@@ -15,6 +18,7 @@ use Wallabag\CoreBundle\Entity\TaggingRule;
 use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
 use Wallabag\CoreBundle\Form\Type\ConfigType;
 use Wallabag\CoreBundle\Form\Type\FeedType;
+use Wallabag\CoreBundle\Form\Type\TaggingRuleImportType;
 use Wallabag\CoreBundle\Form\Type\TaggingRuleType;
 use Wallabag\CoreBundle\Form\Type\UserInformationType;
 use Wallabag\CoreBundle\Tools\Utils;
@@ -140,6 +144,37 @@ class ConfigController extends Controller
             return $this->redirect($this->generateUrl('config') . '#set5');
         }
 
+        // handle tagging rules import
+        $taggingRulesImportform = $this->createForm(TaggingRuleImportType::class);
+        $taggingRulesImportform->handleRequest($request);
+
+        if ($taggingRulesImportform->isSubmitted() && $taggingRulesImportform->isValid()) {
+            $message = 'flashes.config.notice.tagging_rules_not_imported';
+            $file = $taggingRulesImportform->get('file')->getData();
+
+            if (null !== $file && $file->isValid() && \in_array($file->getClientMimeType(), ['application/json', 'application/octet-stream'], true)) {
+                $content = json_decode(file_get_contents($file->getPathname()), true);
+
+                if (\is_array($content)) {
+                    foreach ($content as $rule) {
+                        $taggingRule = new TaggingRule();
+                        $taggingRule->setRule($rule['rule']);
+                        $taggingRule->setTags($rule['tags']);
+                        $taggingRule->setConfig($config);
+                        $em->persist($taggingRule);
+                    }
+
+                    $em->flush();
+
+                    $message = 'flashes.config.notice.tagging_rules_imported';
+                }
+            }
+
+            $this->addFlash('notice', $message);
+
+            return $this->redirect($this->generateUrl('config') . '#set5');
+        }
+
         return $this->render('WallabagCoreBundle:Config:index.html.twig', [
             'form' => [
                 'config' => $configForm->createView(),
@@ -147,6 +182,7 @@ class ConfigController extends Controller
                 'pwd' => $pwdForm->createView(),
                 'user' => $userForm->createView(),
                 'new_tagging_rule' => $newTaggingRule->createView(),
+                'import_tagging_rule' => $taggingRulesImportform->createView(),
             ],
             'feed' => [
                 'username' => $user->getUsername(),
@@ -492,6 +528,32 @@ class ConfigController extends Controller
         return $this->redirect($request->headers->get('referer', $this->generateUrl('homepage')));
     }
 
+    /**
+     * Export tagging rules for the logged in user.
+     *
+     * @Route("/tagging-rule/export", name="export_tagging_rule")
+     *
+     * @return Response
+     */
+    public function exportTaggingRulesAction()
+    {
+        $data = SerializerBuilder::create()->build()->serialize(
+            $this->getUser()->getConfig()->getTaggingRules(),
+            'json',
+            SerializationContext::create()->setGroups(['export_tagging_rule'])
+        );
+
+        return Response::create(
+            $data,
+            200,
+            [
+                'Content-type' => 'application/json',
+                'Content-Disposition' => 'attachment; filename="tagging_rules_' . $this->getUser()->getUsername() . '.json"',
+                'Content-Transfer-Encoding' => 'UTF-8',
+            ]
+        );
+    }
+
     /**
      * Remove all tags for given tags and a given user and cleanup orphan tags.
      *
index c1be3165d7085185b07d27329ee47fbaff8fc7df..eac53fa32c2e01ab971123ea4583a4ca926bac9c 100644 (file)
@@ -3,12 +3,16 @@
 namespace Wallabag\CoreBundle\Entity;
 
 use Doctrine\ORM\Mapping as ORM;
+use JMS\Serializer\Annotation\Exclude;
+use JMS\Serializer\Annotation\Groups;
+use JMS\Serializer\Annotation\XmlRoot;
 use Symfony\Bridge\RulerZ\Validator\Constraints as RulerZAssert;
 use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Tagging rule.
  *
+ * @XmlRoot("tagging_rule")
  * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\TaggingRuleRepository")
  * @ORM\Table(name="`tagging_rule`")
  * @ORM\Entity
@@ -34,6 +38,8 @@ class TaggingRule
      *  allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches", "notmatches"}
      * )
      * @ORM\Column(name="rule", type="string", nullable=false)
+     *
+     * @Groups({"export_tagging_rule"})
      */
     private $rule;
 
@@ -42,10 +48,14 @@ class TaggingRule
      *
      * @Assert\NotBlank()
      * @ORM\Column(name="tags", type="simple_array", nullable=false)
+     *
+     * @Groups({"export_tagging_rule"})
      */
     private $tags = [];
 
     /**
+     * @Exclude
+     *
      * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", inversedBy="taggingRules")
      */
     private $config;
diff --git a/src/Wallabag/CoreBundle/Form/Type/TaggingRuleImportType.php b/src/Wallabag/CoreBundle/Form/Type/TaggingRuleImportType.php
new file mode 100644 (file)
index 0000000..c6a8c0b
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\FileType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\FormBuilderInterface;
+
+class TaggingRuleImportType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('file', FileType::class, [
+                'label' => 'config.form_rules.file_label',
+                'required' => true,
+            ])
+            ->add('import', SubmitType::class, [
+                'label' => 'config.form_rules.import_submit',
+            ])
+        ;
+    }
+
+    public function getBlockPrefix()
+    {
+        return 'upload_tagging_rule_file';
+    }
+}
index 5c4ca29cefc80e112b55d66dfd23b04bf774d6eb..fab05835b6515dbd9102ff0199a32d7f6975a8b0 100644 (file)
@@ -140,6 +140,15 @@ config:
         # edit_rule_label: 'edit'
         # rule_label: 'Rule'
         # tags_label: 'Tags'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         # faq:
         #     title: 'FAQ'
         #     tagging_rules_definition_title: 'What does « tagging rules » mean?'
@@ -602,6 +611,9 @@ flashes:
             # tags_reset: Tags reset
             # entries_reset: Entries reset
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             # entry_already_saved: 'Entry already saved on %date%'
index a21bd0f10e4525b81ae3c49a5f655a9e9ac78665..6ba464d04be4abe00da45dc02e64cc74d689d0fc 100644 (file)
@@ -140,6 +140,15 @@ config:
         edit_rule_label: 'bearbeiten'
         rule_label: 'Regel'
         tags_label: 'Tags'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'Was bedeuten die "Tagging-Regeln"?'
@@ -172,6 +181,15 @@ config:
                 and: 'Eine Regel UND eine andere'
                 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>'
                 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>'
+    otp:
+        # page_title: Two-factor authentication
+        # app:
+        #     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.
+        #     two_factor_code_description_2: 'You can scan that QR Code with your app:'
+        #     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:'
+        #     two_factor_code_description_4: 'Test an OTP code from your configured app:'
+        #     cancel: Cancel
+        #     enable: Enable
 
 entry:
     default_title: 'Titel des Eintrags'
@@ -593,6 +611,9 @@ flashes:
             tags_reset: Tags zurücksetzen
             entries_reset: Einträge zurücksetzen
             archived_reset: Archiverte Einträge zurücksetzen
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Eintrag bereits am %date% gespeichert'
index 2f310246b97b70586b841e495ef765bd290af43d..a7c32f115f4036a0950d3231db9adef4ab846c33 100644 (file)
@@ -140,6 +140,15 @@ config:
         edit_rule_label: 'edit'
         rule_label: 'Rule'
         tags_label: 'Tags'
+        card:
+            new_tagging_rule: Create a tagging rule
+            import_tagging_rules: Import tagging rules
+            import_tagging_rules_detail: You have to select the JSON file you previously exported.
+            export_tagging_rules: Export tagging rules
+            export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        file_label: JSON file
+        import_submit: Import
+        export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'What does « tagging rules » mean?'
@@ -603,6 +612,8 @@ flashes:
             entries_reset: Entries reset
             archived_reset: Archived entries deleted
             otp_enabled: Two-factor authentication enabled
+            tagging_rules_imported: Tagging rules imported
+            tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Entry already saved on %date%'
index c194041a5aaccde6828370d56c4fe89e266ffbdf..093c585748afeb942c72bdce08c5f6f8bbfc6ffd 100644 (file)
@@ -140,6 +140,15 @@ config:
         edit_rule_label: 'editar'
         rule_label: 'Regla'
         tags_label: 'Etiquetas'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'Preguntas frecuentes'
             tagging_rules_definition_title: '¿Qué significa « reglas de etiquetado automático »?'
@@ -602,6 +611,9 @@ flashes:
             tags_reset: Etiquetas reiniciadas
             entries_reset: Artículos reiniciados
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Artículo ya guardado el %fecha%'
index 9aef7ddec2b53b5652b2350c945281ff1f3faeb7..00caa0ac0c8808ef4642273b615aeb971d025523 100644 (file)
@@ -140,6 +140,15 @@ config:
         # edit_rule_label: 'edit'
         rule_label: 'قانون'
         tags_label: 'برچسب‌ها'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'پرسش‌های متداول'
             tagging_rules_definition_title: 'برچسب‌گذاری خودکار یعنی چه؟'
@@ -602,6 +611,9 @@ flashes:
             # tags_reset: Tags reset
             # entries_reset: Entries reset
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود'
index 9848ed9ae6744e4339ac827712d43e572dbcef55..ca66acde783f1997f837852ca8d2838c6ecda228 100644 (file)
@@ -140,6 +140,15 @@ config:
         edit_rule_label: "éditer"
         rule_label: "Règle"
         tags_label: "Tags"
+        card:
+            new_tagging_rule: Créer une règle
+            import_tagging_rules: Importer des règles
+            import_tagging_rules_detail: Vous devez sélectionné un fichier JSON que vous avez précédemment exporté.
+            export_tagging_rules: Exporter les règles
+            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.
+        file_label: Fichier JSON
+        import_submit: Importer
+        export: Export
         faq:
             title: "FAQ"
             tagging_rules_definition_title: "Que signifient les règles de tag automatiques ?"
@@ -604,6 +613,8 @@ flashes:
             entries_reset: "Articles supprimés"
             archived_reset: "Articles archivés supprimés"
             otp_enabled: "Authentification à double-facteur activée"
+            tagging_rules_imported: Règles bien importées
+            tagging_rules_not_imported: Impossible d'importer les règles
     entry:
         notice:
             entry_already_saved: "Article déjà sauvegardé le %date%"
index efbf062b1c469653b32597fc67326e2eb3797757..85720ef8c454195040b38b8fce0a61a499d23d87 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'Nome'
         email_label: 'E-mail'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         edit_rule_label: 'modifica'
         rule_label: 'Regola'
         tags_label: 'Etichetta'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'Cosa significa « regole di etichettatura » ?'
@@ -601,6 +611,9 @@ flashes:
             tags_reset: Reset etichette
             entries_reset: Reset articoli
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Contenuto già salvato in data %date%'
index 86ce464496604285373a287678fef2159b698e91..18d1173bd5db208c774664d5c53aa64485d4733e 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'Nom'
         email_label: 'Adreça de corrièl'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         edit_rule_label: 'modificar'
         rule_label: 'Règla'
         tags_label: 'Etiquetas'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: "Qué significa las règlas d'etiquetas automaticas ?"
@@ -601,6 +611,9 @@ flashes:
             tags_reset: Etiquetas levadas
             entries_reset: Articles levats
             archived_reset: Articles archivat suprimits
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Article ja salvagardat lo %date%'
index 9ebe02360dc535c9657fa6ccfa44b7bd35c5ec22..6528a5623a46fa46e34c4a8563753354ce6490eb 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'Nazwa'
         email_label: 'Adres email'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         edit_rule_label: 'edytuj'
         rule_label: 'Reguła'
         tags_label: 'Tagi'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'Co oznaczają « reguły tagowania » ?'
@@ -601,6 +611,9 @@ flashes:
             tags_reset: Zresetuj tagi
             entries_reset: Zresetuj wpisy
             archived_reset: Zarchiwizowane wpisy usunięte
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Wpis już został dodany %date%'
index d310e016f06bed218392b08f96010663818d2c8e..3f1c7a68929d21f9513aba6a21e292ce4b612759 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'Nome'
         email_label: 'E-mail'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         edit_rule_label: 'editar'
         rule_label: 'Regras'
         tags_label: 'Tags'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'O que as « regras de tags » significam?'
@@ -601,6 +611,9 @@ flashes:
             # tags_reset: Tags reset
             # entries_reset: Entries reset
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Entrada já foi salva em %date%'
index c11ff0b8ab7adc2b5f92abd2460bb7d2b389c272..d82e9377a7ef7c94eafd2ac4994289b4aca64d67 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'Nume'
         email_label: 'E-mail'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         # edit_rule_label: 'edit'
         # rule_label: 'Rule'
         # tags_label: 'Tags'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         # faq:
         #     title: 'FAQ'
         #     tagging_rules_definition_title: 'What does « tagging rules » mean?'
@@ -429,9 +439,9 @@ tag:
     rename:
         # placeholder: 'You can update tag name.'
 
-export:
-#     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>'
-#     unknown: 'Unknown'
+export:
+    # 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>'
+    # unknown: 'Unknown'
 
 import:
     # page_title: 'Import'
@@ -601,6 +611,9 @@ flashes:
             # tags_reset: Tags reset
             # entries_reset: Entries reset
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             # entry_already_saved: 'Entry already saved on %date%'
index 9fe7536958807765ef2e95f5ec9f8df76c2ebc1e..23d31333569b118bda13346efa2f7c60f9700484 100644 (file)
@@ -80,6 +80,7 @@ config:
             redirect_current_page: 'На текущую страницу'
         pocket_consumer_key_label: "Ключ от Pocket для импорта контента"
         android_configuration: "Настройте Ваше Android приложение"
+        # android_instruction: "Touch here to prefill your Android application"
         help_theme: "wallabag настраиваемый, здесь Вы можете выбрать тему."
         help_items_per_page: "Вы можете выбрать количество отображаемых записей на странице."
         help_reading_speed: "wallabag посчитает сколько времени занимает чтение каждой записи. Вы можете определить здесь, как быстро вы читаете. wallabag пересчитает время чтения для каждой записи."
@@ -97,12 +98,14 @@ config:
             unread: 'непрочитанные'
             starred: 'помеченные'
             archive: 'архивные'
+            # all: 'All'
         feed_limit: 'Количество записей в фиде'
     form_user:
         # 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."
         # login_label: 'Login (can not be changed)'
         name_label: 'Имя'
         email_label: 'Email'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -123,6 +126,7 @@ config:
         annotations: "Удалить все аннотации"
         tags: "Удалить все теги"
         entries: "Удалить все записи"
+        # archived: Remove ALL archived entries
         confirm: "Вы уверены? (Данные будут БЕЗВОЗВРАТНО удалены, эти действия необратимы)"
     form_password:
         description: "Здесь Вы можете поменять своя пароль. Ваш пароль должен быть длиннее 8 символов."
@@ -136,6 +140,15 @@ config:
         edit_rule_label: 'изменить'
         rule_label: 'Правило'
         tags_label: 'теги'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'Что значит "правило тегирования"?'
@@ -167,6 +180,7 @@ config:
                 or: 'Одно правило ИЛИ другое'
                 and: 'Одно правило И другое'
                 matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>'
+                # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
     otp:
         # page_title: Two-factor authentication
         # app:
@@ -187,6 +201,7 @@ entry:
         filtered_tags: 'Отфильтрованные по тегу:'
         filtered_search: 'Отфильтрованные по поиску:'
         untagged: 'Записи без тегов'
+        # all: 'All entries'
     list:
         number_on_the_page: '{0} Записей не обнаружено.|{1} Одна запись.|]1,Inf[ Найдено %count% записей.'
         reading_time: 'расчетное время чтения'
@@ -208,6 +223,8 @@ entry:
         unread_label: 'Непрочитанная'
         preview_picture_label: 'Есть картинка предварительного просмотра'
         preview_picture_help: 'Картинка предварительного просмотра'
+        # is_public_label: 'Has a public link'
+        # is_public_help: 'Public link'
         language_label: 'Язык'
         http_status_label: 'статус HTTP'
         reading_time:
@@ -246,6 +263,8 @@ entry:
         original_article: 'оригинал'
         annotations_on_the_entry: '{0} Нет аннотации|{1} Одна аннотация|]1,Inf[ %count% аннотаций'
         created_at: 'Дата создания'
+        # published_at: 'Publication date'
+        # published_by: 'Published by'
         # provided_by: 'Provided by'
     new:
         page_title: 'Сохранить новую запись'
@@ -259,10 +278,12 @@ entry:
         title_label: 'Название'
         url_label: 'Ссылка'
         # origin_url_label: 'Origin url (from where you found that entry)'
-        is_public_label: 'Публичная'
         save_label: 'Сохранить'
     public:
         shared_by_wallabag: "Запись была опубликована <a href='%wallabag_instance%'>wallabag</a>"
+    confirm:
+        # delete: "Are you sure you want to remove that article?"
+        # delete_tag: "Are you sure you want to remove that tag from that article?"
     metadata:
         # reading_time: "Estimated reading time"
         # reading_time_minutes_short: "%readingTime% min"
@@ -418,9 +439,9 @@ tag:
     rename:
         # placeholder: 'You can update tag name.'
 
-export:
-#     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>'
-#     unknown: 'Unknown'
+export:
+    # 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>'
+    # unknown: 'Unknown'
 
 import:
     page_title: 'Импорт'
@@ -548,6 +569,28 @@ user:
         delete: "Удалить"
         delete_confirm: "Вы уверены?"
         back_to_list: "Назад к списку"
+    search:
+        # placeholder: Filter by login or email
+
+site_credential:
+    # page_title: Site credentials management
+    # new_site_credential: Create a credential
+    # edit_site_credential: Edit an existing credential
+    # description: "Here you can manage all credentials for sites which required them (create, edit and delete), like a paywall, an authentication, etc."
+    # list:
+    #     actions: Actions
+    #     edit_action: Edit
+    #     yes: Yes
+    #     no: No
+    #     create_new_one: Create a new credential
+    # form:
+    #     username_label: 'Login'
+    #     host_label: 'Host (subdomain.example.org, .example.org, etc.)'
+    #     password_label: 'Password'
+    #     save: Save
+    #     delete: Delete
+    #     delete_confirm: Are you sure?
+    #     back_to_list: Back to list
 
 error:
     page_title: "Произошла ошибка"
@@ -567,6 +610,10 @@ flashes:
             annotations_reset: "Аннотации сброшены"
             tags_reset: "Теги сброшены"
             entries_reset: "Записи сброшены"
+            # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Запись была сохранена ранее %date%'
@@ -603,3 +650,8 @@ flashes:
             added: 'Пользователь "%username%" добавлен'
             updated: 'Пользователь "%username%" обновлен'
             deleted: 'Пользователь "%username%" удален'
+    site_credential:
+        notice:
+            # added: 'Site credential for "%host%" added'
+            # updated: 'Site credential for "%host%" updated'
+            # deleted: 'Site credential for "%host%" deleted'
index 672dcbf0106f74e133ea17cc966b9e8d5cb56618..d7f47904adf3e84240bd0497bd22e749f6c5b129 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'ชื่อ'
         email_label: 'อีเมล'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         edit_rule_label: 'ปรับแก้'
         rule_label: 'ข้อบังคับ'
         tags_label: 'แท็ก'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'FAQ'
             tagging_rules_definition_title: 'ข้อบังคับการแท็กคืออะไร?'
@@ -255,6 +265,7 @@ entry:
         created_at: 'วันที่สร้าง'
         published_at: 'วันที่ประกาศ'
         published_by: 'ประกาศโดย'
+        # provided_by: 'Provided by'
     new:
         page_title: 'บันทึกรายการใหม่'
         placeholder: 'http://website.com'
@@ -266,6 +277,7 @@ entry:
         page_title: 'แก้ไขรายการ'
         title_label: 'หัวข้อ'
         url_label: 'Url'
+        # origin_url_label: 'Origin url (from where you found that entry)'
         save_label: 'บันทึก'
     public:
         shared_by_wallabag: "บทความนี้จะมีการแชร์โดย %username% กับ <a href='%wallabag_instance%'>wallabag</a>"
@@ -599,6 +611,9 @@ flashes:
             tags_reset: รีเซ็ตแท็ก
             entries_reset: รีเซ็ตรายการ
             archived_reset: การลบเอกสารของรายการ
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'รายการพร้อมบันทึกที่ %date%'
index c2ad854d252ea010071362d3e473948439eae2c0..a444cadbd1d4394299425da46414a57a0f7681f9 100644 (file)
@@ -105,6 +105,7 @@ config:
         # login_label: 'Login (can not be changed)'
         name_label: 'İsim'
         email_label: 'E-posta'
+        two_factor:
             # emailTwoFactor_label: 'Using email (receive a code by email)'
             # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
             # table_method: Method
@@ -139,6 +140,15 @@ config:
         # edit_rule_label: 'edit'
         rule_label: 'Kural'
         tags_label: 'Etiketler'
+        # card:
+        #     new_tagging_rule: Create a tagging rule
+        #     import_tagging_rules: Import tagging rules
+        #     import_tagging_rules_detail: You have to select the JSON file you previously exported.
+        #     export_tagging_rules: Export tagging rules
+        #     export_tagging_rules_detail: This will download a JSON file that you can use to import tagging rules elsewhere or to backup them.
+        # file_label: JSON file
+        # import_submit: Import
+        # export: Export
         faq:
             title: 'S.S.S.'
             tagging_rules_definition_title: '« etiketleme kuralları » ne anlama geliyor?'
@@ -213,6 +223,8 @@ entry:
         unread_label: 'Okunmayan'
         preview_picture_label: 'Resim önizlemesi varsa'
         preview_picture_help: 'Resim önizlemesi'
+        # is_public_label: 'Has a public link'
+        # is_public_help: 'Public link'
         language_label: 'Dil'
         # http_status_label: 'HTTP status'
         reading_time:
@@ -427,9 +439,9 @@ tag:
     rename:
         # placeholder: 'You can update tag name.'
 
-export:
-#     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>'
-#     unknown: 'Unknown'
+export:
+    # 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>'
+    # unknown: 'Unknown'
 
 import:
     page_title: 'İçe Aktar'
@@ -560,6 +572,26 @@ user:
     search:
         # placeholder: Filter by username or email
 
+site_credential:
+    # page_title: Site credentials management
+    # new_site_credential: Create a credential
+    # edit_site_credential: Edit an existing credential
+    # description: "Here you can manage all credentials for sites which required them (create, edit and delete), like a paywall, an authentication, etc."
+    # list:
+    #     actions: Actions
+    #     edit_action: Edit
+    #     yes: Yes
+    #     no: No
+    #     create_new_one: Create a new credential
+    # form:
+    #     username_label: 'Login'
+    #     host_label: 'Host (subdomain.example.org, .example.org, etc.)'
+    #     password_label: 'Password'
+    #     save: Save
+    #     delete: Delete
+    #     delete_confirm: Are you sure?
+    #     back_to_list: Back to list
+
 error:
     # page_title: An error occurred
 
@@ -571,13 +603,17 @@ flashes:
             password_not_updated_demo: "In demonstration mode, you can't change password for this user."
             user_updated: 'Bilgiler güncellendi'
             feed_updated: 'RSS bilgiler güncellendi'
-            tagging_rules_updated: 'Tagging rules updated'
-            tagging_rules_deleted: 'Tagging rule deleted'
-            feed_token_updated: 'RSS token updated'
+            # tagging_rules_updated: 'Tagging rules updated'
+            # tagging_rules_deleted: 'Tagging rule deleted'
+            # feed_token_updated: 'RSS token updated'
+            # feed_token_revoked: 'RSS token revoked'
             # annotations_reset: Annotations reset
             # tags_reset: Tags reset
             # entries_reset: Entries reset
             # archived_reset: Archived entries deleted
+            # otp_enabled: Two-factor authentication enabled
+            # tagging_rules_imported: Tagging rules imported
+            # tagging_rules_not_imported: Error while importing tagging rules
     entry:
         notice:
             entry_already_saved: 'Entry already saved on %date%'
index eba4539fa6a4e98ffc921786219d82774ca608a7..f719bea252e44a532ad099838cad299b181cc039 100644 (file)
 
         {{ form_rest(form.new_tagging_rule) }}
     </form>
+
+    <div class="row">
+        <h3>{{ 'config.form_rules.card.import_tagging_rules'|trans }}</h3>
+        <p>{{ 'config.form_rules.card.import_tagging_rules_detail'|trans }}</p>
+    </div>
+
+    {{ form_start(form.import_tagging_rule) }}
+        {{ form_errors(form.import_tagging_rule) }}
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(form.import_tagging_rule.file) }}
+                {{ form_errors(form.import_tagging_rule.file) }}
+                {{ form_widget(form.import_tagging_rule.file) }}
+            </div>
+        </fieldset>
+
+        {{ form_rest(form.import_tagging_rule) }}
+    </form>
+
+    {% if app.user.config.taggingRules is not empty %}
+    <div class="row">
+        <h3>{{ 'config.form_rules.card.export_tagging_rules'|trans }}</h3>
+        <p>{{ 'config.form_rules.card.export_tagging_rules_detail'|trans }}</p>
+        <p><a href="{{ path('export_tagging_rule') }}" class="waves-effect waves-light btn">{{ 'config.form_rules.export'|trans }}</a></p>
+    </div>
+    {% endif %}
+
     <div class="row">
         <div class="input-field col s12">
             <h3>{{ 'config.form_rules.faq.title'|trans }}</h3>
index 990546e8cd61c401b02aeda1acc9ddc385a3c1ce..d8e9694d5ce16be5fd73e06ace424fa171b81c03 100644 (file)
                         </div>
                         {% endif %}
 
-                        {{ form_start(form.new_tagging_rule) }}
-                            {{ form_errors(form.new_tagging_rule) }}
-
-                            <div class="row">
-                                <div class="input-field col s12">
-                                    {{ form_label(form.new_tagging_rule.rule) }}
-                                    {{ form_errors(form.new_tagging_rule.rule) }}
-                                    {{ form_widget(form.new_tagging_rule.rule) }}
+                        <ul class="row">
+                            <li class="col l6 m6 s12">
+                                <div class="card">
+                                    <div class="card-content">
+                                        <span class="card-title">{{ 'config.form_rules.card.new_tagging_rule'|trans }}</span>
+
+                                        {{ form_start(form.new_tagging_rule) }}
+                                        {{ form_errors(form.new_tagging_rule) }}
+
+                                        <div class="row">
+                                            <div class="input-field col s12">
+                                                {{ form_label(form.new_tagging_rule.rule) }}
+                                                {{ form_errors(form.new_tagging_rule.rule) }}
+                                                {{ form_widget(form.new_tagging_rule.rule) }}
+                                            </div>
+                                        </div>
+
+                                        <div class="row">
+                                            <div class="input-field col s12">
+                                                {{ form_label(form.new_tagging_rule.tags) }}
+                                                {{ form_errors(form.new_tagging_rule.tags) }}
+                                                {{ form_widget(form.new_tagging_rule.tags) }}
+                                            </div>
+                                        </div>
+
+                                        {{ form_widget(form.new_tagging_rule.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
+                                        {{ form_rest(form.new_tagging_rule) }}
+                                    </form>
+                                    </div>
                                 </div>
-                            </div>
-
-                            <div class="row">
-                                <div class="input-field col s12">
-                                    {{ form_label(form.new_tagging_rule.tags) }}
-                                    {{ form_errors(form.new_tagging_rule.tags) }}
-                                    {{ form_widget(form.new_tagging_rule.tags) }}
+                            </li>
+                            <li class="col l6 m6 s12">
+                                <div class="card z-depth-1">
+                                    <div class="card-content">
+                                        <span class="card-title">{{ 'config.form_rules.card.import_tagging_rules'|trans }}</span>
+                                        <p>{{ 'config.form_rules.card.import_tagging_rules_detail'|trans }}</p>
+                                        {{ form_start(form.import_tagging_rule) }}
+                                            {{ form_errors(form.import_tagging_rule) }}
+                                            <div class="row">
+                                                <div class="file-field input-field col s12">
+                                                    {{ form_errors(form.import_tagging_rule.file) }}
+                                                    <div class="btn">
+                                                        <span>{{ form.import_tagging_rule.file.vars.label|trans }}</span>
+                                                        {{ form_widget(form.import_tagging_rule.file) }}
+                                                    </div>
+                                                    <div class="file-path-wrapper">
+                                                        <input class="file-path validate" type="text">
+                                                    </div>
+                                                </div>
+                                            </div>
+
+                                            {{ form_widget(form.import_tagging_rule.import, { 'attr': {'class': 'btn waves-effect waves-light'} }) }}
+
+                                            {{ form_rest(form.import_tagging_rule) }}
+                                        </form>
+                                    </div>
                                 </div>
-                            </div>
-
-                            {{ form_widget(form.new_tagging_rule.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
-                            {{ form_rest(form.new_tagging_rule) }}
-                        </form>
+                            </li>
+                            {% if app.user.config.taggingRules is not empty %}
+                            <li class="col l6 m6 s12">
+                                <div class="card z-depth-1">
+                                    <div class="card-content">
+                                        <span class="card-title">{{ 'config.form_rules.card.export_tagging_rules'|trans }}</span>
+                                        <p>{{ 'config.form_rules.card.export_tagging_rules_detail'|trans }}</p>
+                                        <br/>
+                                        <p><a href="{{ path('export_tagging_rule') }}" class="waves-effect waves-light btn">{{ 'config.form_rules.export'|trans }}</a></p>
+                                    </div>
+                                </div>
+                            </li>
+                            {% endif %}
+                        </ul>
 
                         <div class="row">
                             <div class="input-field col s12">
diff --git a/tests/Wallabag/ApiBundle/Controller/TaggingRuleRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/TaggingRuleRestControllerTest.php
new file mode 100644 (file)
index 0000000..b647725
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+namespace Tests\Wallabag\ApiBundle\Controller;
+
+use Tests\Wallabag\ApiBundle\WallabagApiTestCase;
+
+class TaggingRuleRestControllerTest extends WallabagApiTestCase
+{
+    public function testExportEntry()
+    {
+        $this->client->request('GET', '/api/taggingrule/export');
+        $this->assertSame(200, $this->client->getResponse()->getStatusCode());
+        $this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
+    }
+}
index b9e0bed25118c27faaddcd223617fe572f4132f4..d8b5f38357c39ed4504552ab056122ca44897863 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Tests\Wallabag\CoreBundle\Controller;
 
+use Symfony\Component\HttpFoundation\File\UploadedFile;
 use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
 use Wallabag\AnnotationBundle\Entity\Annotation;
 use Wallabag\CoreBundle\Entity\Config;
@@ -1097,4 +1098,67 @@ class ConfigControllerTest extends WallabagCoreTestCase
         $this->assertFalse($user->isGoogleTwoFactor());
         $this->assertEmpty($user->getBackupCodes());
     }
+
+    public function testExportTaggingRule()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        ob_start();
+        $crawler = $client->request('GET', '/tagging-rule/export');
+        ob_end_clean();
+
+        $this->assertSame(200, $client->getResponse()->getStatusCode());
+
+        $headers = $client->getResponse()->headers;
+        $this->assertSame('application/json', $headers->get('content-type'));
+        $this->assertSame('attachment; filename="tagging_rules_admin.json"', $headers->get('content-disposition'));
+        $this->assertSame('UTF-8', $headers->get('content-transfer-encoding'));
+
+        $content = json_decode($client->getResponse()->getContent(), true);
+
+        $this->assertCount(4, $content);
+        $this->assertSame('content matches "spurs"', $content[0]['rule']);
+        $this->assertSame('sport', $content[0]['tags'][0]);
+    }
+
+    public function testImportTagginfRuleBadFile()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+        $form = $crawler->filter('form[name=upload_tagging_rule_file] > button[type=submit]')->form();
+
+        $data = [
+            'upload_tagging_rule_file[file]' => '',
+        ];
+
+        $client->submit($form, $data);
+
+        $this->assertSame(302, $client->getResponse()->getStatusCode());
+    }
+
+    public function testImportTagginfRuleFile()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+        $form = $crawler->filter('form[name=upload_tagging_rule_file] > button[type=submit]')->form();
+
+        $file = new UploadedFile(__DIR__ . '/../fixtures/tagging_rules_admin.json', 'tagging_rules_admin.json');
+
+        $data = [
+            'upload_tagging_rule_file[file]' => $file,
+        ];
+
+        $client->submit($form, $data);
+        $this->assertSame(302, $client->getResponse()->getStatusCode());
+
+        $user = $client->getContainer()->get('fos_user.user_manager.test')->findUserBy(['username' => 'admin']);
+        $taggingRules = $user->getConfig()->getTaggingRules()->toArray();
+        $this->assertCount(5, $taggingRules);
+        $this->assertSame('title matches "football"', $taggingRules[4]->getRule());
+    }
 }
diff --git a/tests/Wallabag/CoreBundle/fixtures/tagging_rules_admin.json b/tests/Wallabag/CoreBundle/fixtures/tagging_rules_admin.json
new file mode 100644 (file)
index 0000000..a54824e
--- /dev/null
@@ -0,0 +1,4 @@
+[{
+    "rule": "title matches \"football\"",
+    "tags": ["football"]
+}]