]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #2326 from wallabag/update-quickstart
authorJeremy Benoist <j0k3r@users.noreply.github.com>
Sun, 2 Oct 2016 09:06:03 +0000 (11:06 +0200)
committerGitHub <noreply@github.com>
Sun, 2 Oct 2016 09:06:03 +0000 (11:06 +0200)
Changed quickstart layout

35 files changed:
app/config/config.yml
app/config/services.yml
docker/php/Dockerfile
docs/de/developer/docker.rst
docs/en/developer/docker.rst
docs/fr/developer/docker.rst
src/Wallabag/CoreBundle/Command/InstallCommand.php
src/Wallabag/CoreBundle/Controller/ConfigController.php
src/Wallabag/CoreBundle/Controller/ExceptionController.php [new file with mode: 0644]
src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php
src/Wallabag/CoreBundle/Resources/config/services.yml
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.ro.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/baggy/Exception/error.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/Exception/error.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
src/Wallabag/CoreBundle/Twig/WallabagExtension.php
src/Wallabag/UserBundle/EventListener/CreateConfigListener.php [moved from src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php with 53% similarity]
src/Wallabag/UserBundle/Resources/config/services.yml
src/Wallabag/UserBundle/Resources/views/Registration/check_email.html.twig [moved from src/Wallabag/UserBundle/Resources/views/Registration/checkEmail.html.twig with 100% similarity]
tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php
tests/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverterTest.php
tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php
tests/Wallabag/UserBundle/EventListener/CreateConfigListenerTest.php [moved from tests/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListenerTest.php with 83% similarity]

index b5d82ed9a0e183793f6c6074427f3c4d12fd5bf9..fbebfee7f1f2420f53e7568c51d237f9c931be01 100644 (file)
@@ -64,6 +64,7 @@ twig:
     strict_variables: "%kernel.debug%"
     form_themes:
         - "LexikFormFilterBundle:Form:form_div_layout.html.twig"
+    exception_controller: wallabag_core.exception_controller:showAction
 
 # Doctrine Configuration
 doctrine:
index 76bbce27c741b49aeae4898e87ca469305630d35..a57ef0f3d42e43f0d24c96dcb56183769d7b1b03 100644 (file)
@@ -21,6 +21,7 @@ services:
             - "@wallabag_core.tag_repository"
             - "@security.token_storage"
             - "%wallabag_core.cache_lifetime%"
+            - "@translator"
         tags:
             - { name: twig.extension }
 
index 29d27c3a80ce1a3fa933f824492d0e0f02c1e9d5..1fb1f29826e7c402cecb9274006767dea4dd4558 100644 (file)
@@ -4,9 +4,10 @@ FROM php:fpm
 ARG timezone='Europe/Paris'
 
 RUN apt-get update && apt-get install -y \
-        libmcrypt-dev libicu-dev libpq-dev libxml2-dev \
+        libmcrypt-dev libicu-dev libpq-dev libxml2-dev libpng12-dev libjpeg-dev \
+    && /usr/local/bin/docker-php-ext-configure gd --with-jpeg-dir=/usr/include \
     && docker-php-ext-install \
-        iconv mcrypt mbstring intl pdo pdo_mysql pdo_pgsql
+        iconv mcrypt mbstring intl pdo pdo_mysql pdo_pgsql gd
 
 RUN echo "date.timezone="$timezone > /usr/local/etc/php/conf.d/date_timezone.ini
 
index c63194aadd9864f2f6b030113987d6012cff4af6..9948fe8c79796f14d57469ef2bbd883a4eb2fdb5 100644 (file)
@@ -44,7 +44,7 @@ wallabag laufen lassen
    Eigenschaften mit den kommentierten zu ersetzen (mit Werten
    mit ``env.`` Präfix)
 #. ``composer install`` die Projektabhängigkeiten
-#. ``php app/console wallabag:install``, um das Schema zu erstellen
+#. ``php bin/console wallabag:install``, um das Schema zu erstellen
 #. ``docker-compose up`` um die Container laufen zu lassen
 #. Schließlich öffne http://localhost:8080/, um dein frisch
    installiertes wallabag zu finden.
index 8816cbcfbdc2cdf395b29e2383bbeadb756f0a93..5e4f2ce6bda0326e2ff0c4ae306f199b3480c046 100644 (file)
@@ -40,7 +40,7 @@ Run wallabag
 #. Edit ``app/config/parameters.yml`` to replace ``database_*``
    properties with commented ones (with values prefixed by ``env.``)
 #. ``composer install`` the project dependencies
-#. ``php app/console wallabag:install`` to create the schema
+#. ``php bin/console wallabag:install`` to create the schema
 #. ``docker-compose up`` to run the containers
 #. Finally, browse to http://localhost:8080/ to find your freshly
    installed wallabag.
index 73cb56be833d7dd920212d2da444bfa1bdf3c58b..84724ed3eae9ab9fcc734d3bb3b8aedb08f62edf 100644 (file)
@@ -39,7 +39,7 @@ Exécuter wallabag
 #. Editer ``app/config/parameters.yml`` pour remplacer les propriétés ``database_*``
     par les lignes commentées (celles avec des valeurs préfixées par ``env.``)
 #. ``composer install`` pour installer les dépendances
-#. ``php app/console wallabag:install`` pour créer le schéma de la BDD
+#. ``php bin/console wallabag:install`` pour créer le schéma de la BDD
 #. ``docker-compose up`` pour démarrer les conteneurs
 #. Enfin, se rendre sur http://localhost:8080/ pour accéder à une installation
     tout propre de wallabag.
index 3873d2d366762b88241874bb27415696b0b1cca3..cc7c2c94cf268be86cd4de51d895404a7d433ec2 100644 (file)
@@ -2,6 +2,8 @@
 
 namespace Wallabag\CoreBundle\Command;
 
+use FOS\UserBundle\Event\UserEvent;
+use FOS\UserBundle\FOSUserEvents;
 use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
 use Symfony\Component\Console\Helper\Table;
 use Symfony\Component\Console\Input\ArrayInput;
@@ -236,14 +238,9 @@ class InstallCommand extends ContainerAwareCommand
 
         $em->persist($user);
 
-        $config = new Config($user);
-        $config->setTheme($this->getContainer()->getParameter('wallabag_core.theme'));
-        $config->setItemsPerPage($this->getContainer()->getParameter('wallabag_core.items_on_page'));
-        $config->setRssLimit($this->getContainer()->getParameter('wallabag_core.rss_limit'));
-        $config->setReadingSpeed($this->getContainer()->getParameter('wallabag_core.reading_speed'));
-        $config->setLanguage($this->getContainer()->getParameter('wallabag_core.language'));
-
-        $em->persist($config);
+        // dispatch a created event so the associated config will be created
+        $event = new UserEvent($user);
+        $this->getContainer()->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
 
         $this->defaultOutput->writeln('');
 
index 4f75511bf62cf5c7ee23b5ceb5eaeeb16a89248f..f1e212d989e849da34a45afe66a7803f709a90a0 100644 (file)
@@ -2,6 +2,8 @@
 
 namespace Wallabag\CoreBundle\Controller;
 
+use FOS\UserBundle\Event\UserEvent;
+use FOS\UserBundle\FOSUserEvents;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 use Symfony\Component\HttpFoundation\JsonResponse;
@@ -106,7 +108,21 @@ class ConfigController extends Controller
 
         // handle tagging rule
         $taggingRule = new TaggingRule();
-        $newTaggingRule = $this->createForm(TaggingRuleType::class, $taggingRule, ['action' => $this->generateUrl('config').'#set5']);
+        $action = $this->generateUrl('config').'#set5';
+
+        if ($request->query->has('tagging-rule')) {
+            $taggingRule = $this->getDoctrine()
+                ->getRepository('WallabagCoreBundle:TaggingRule')
+                ->find($request->query->get('tagging-rule'));
+
+            if ($this->getUser()->getId() !== $taggingRule->getConfig()->getUser()->getId()) {
+                return $this->redirect($action);
+            }
+
+            $action = $this->generateUrl('config').'?tagging-rule='.$taggingRule->getId().'#set5';
+        }
+
+        $newTaggingRule = $this->createForm(TaggingRuleType::class, $taggingRule, ['action' => $action]);
         $newTaggingRule->handleRequest($request);
 
         if ($newTaggingRule->isValid()) {
@@ -133,18 +149,11 @@ class ConfigController extends Controller
         $newUserForm->handleRequest($request);
 
         if ($newUserForm->isValid() && $this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) {
-            $userManager->updateUser($newUser, true);
-
-            $config = new Config($newUser);
-            $config->setTheme($this->getParameter('wallabag_core.theme'));
-            $config->setItemsPerPage($this->getParameter('wallabag_core.items_on_page'));
-            $config->setRssLimit($this->getParameter('wallabag_core.rss_limit'));
-            $config->setLanguage($this->getParameter('wallabag_core.language'));
-            $config->setReadingSpeed($this->getParameter('wallabag_core.reading_speed'));
+            $userManager->updateUser($newUser);
 
-            $em->persist($config);
-
-            $em->flush();
+            // dispatch a created event so the associated config will be created
+            $event = new UserEvent($newUser, $request);
+            $this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
 
             $this->get('session')->getFlashBag()->add(
                 'notice',
@@ -210,9 +219,7 @@ class ConfigController extends Controller
      */
     public function deleteTaggingRuleAction(TaggingRule $rule)
     {
-        if ($this->getUser()->getId() != $rule->getConfig()->getUser()->getId()) {
-            throw $this->createAccessDeniedException('You can not access this tagging rule.');
-        }
+        $this->validateRuleAction($rule);
 
         $em = $this->getDoctrine()->getManager();
         $em->remove($rule);
@@ -226,6 +233,34 @@ class ConfigController extends Controller
         return $this->redirect($this->generateUrl('config').'#set5');
     }
 
+    /**
+     * Edit a tagging rule.
+     *
+     * @param TaggingRule $rule
+     *
+     * @Route("/tagging-rule/edit/{id}", requirements={"id" = "\d+"}, name="edit_tagging_rule")
+     *
+     * @return RedirectResponse
+     */
+    public function editTaggingRuleAction(TaggingRule $rule)
+    {
+        $this->validateRuleAction($rule);
+
+        return $this->redirect($this->generateUrl('config').'?tagging-rule='.$rule->getId().'#set5');
+    }
+
+    /**
+     * Validate that a rule can be edited/deleted by the current user.
+     *
+     * @param TaggingRule $rule
+     */
+    private function validateRuleAction(TaggingRule $rule)
+    {
+        if ($this->getUser()->getId() != $rule->getConfig()->getUser()->getId()) {
+            throw $this->createAccessDeniedException('You can not access this tagging rule.');
+        }
+    }
+
     /**
      * Retrieve config for the current user.
      * If no config were found, create a new one.
@@ -238,6 +273,7 @@ class ConfigController extends Controller
             ->getRepository('WallabagCoreBundle:Config')
             ->findOneByUser($this->getUser());
 
+        // should NEVER HAPPEN ...
         if (!$config) {
             $config = new Config($this->getUser());
         }
diff --git a/src/Wallabag/CoreBundle/Controller/ExceptionController.php b/src/Wallabag/CoreBundle/Controller/ExceptionController.php
new file mode 100644 (file)
index 0000000..abfa9c2
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+namespace Wallabag\CoreBundle\Controller;
+
+use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * This controller allow us to customize the error template.
+ * The only modified line from the parent template is for "WallabagCoreBundle".
+ */
+class ExceptionController extends BaseExceptionController
+{
+    protected function findTemplate(Request $request, $format, $code, $showException)
+    {
+        $name = $showException ? 'exception' : 'error';
+        if ($showException && 'html' == $format) {
+            $name = 'exception_full';
+        }
+
+        // For error pages, try to find a template for the specific HTTP status code and format
+        if (!$showException) {
+            $template = sprintf('WallabagCoreBundle:Exception:%s.%s.twig', $name, $format);
+            if ($this->templateExists($template)) {
+                return $template;
+            }
+        }
+
+        // try to find a template for the given format
+        $template = sprintf('@Twig/Exception/%s.%s.twig', $name, $format);
+        if ($this->templateExists($template)) {
+            return $template;
+        }
+
+        // default to a generic HTML exception
+        $request->setRequestFormat('html');
+
+        return sprintf('@Twig/Exception/%s.html.twig', $showException ? 'exception_full' : $name);
+    }
+}
index 6ea2a4f3af29edbb1872291e61d4ac7fa684959f..40b5673ddf62310d61b9484a148b71bf1bb55281 100644 (file)
@@ -49,7 +49,7 @@ class UsernameRssTokenConverter implements ParamConverterInterface
         $em = $this->registry->getManagerForClass($configuration->getClass());
 
         // Check, if class name is what we need
-        if ('Wallabag\UserBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) {
+        if (null !== $em && 'Wallabag\UserBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) {
             return false;
         }
 
@@ -69,9 +69,8 @@ class UsernameRssTokenConverter implements ParamConverterInterface
         $username = $request->attributes->get('username');
         $rssToken = $request->attributes->get('token');
 
-        // Check, if route attributes exists
-        if (null === $username || null === $rssToken) {
-            throw new \InvalidArgumentException('Route attribute is missing');
+        if (!$request->attributes->has('username') || !$request->attributes->has('token')) {
+            return false;
         }
 
         // Get actual entity manager for class
index 23e6d3ca91d2ea4f578a8ad0aab7aa16ce0f2e8f..d11398469757c4a60957a2a37c98adeca5b0dfd6 100644 (file)
@@ -88,17 +88,6 @@ services:
         arguments:
             - WallabagCoreBundle:Tag
 
-    wallabag_core.registration_confirmed:
-        class: Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener
-        arguments:
-            - "@doctrine.orm.entity_manager"
-            - "%wallabag_core.theme%"
-            - "%wallabag_core.items_on_page%"
-            - "%wallabag_core.rss_limit%"
-            - "%wallabag_core.language%"
-        tags:
-            - { name: kernel.event_subscriber }
-
     wallabag_core.helper.entries_export:
         class: Wallabag\CoreBundle\Helper\EntriesExport
         arguments:
@@ -133,3 +122,9 @@ services:
                 host: '%redis_host%'
                 port: '%redis_port%'
                 schema: tcp
+
+    wallabag_core.exception_controller:
+        class: Wallabag\CoreBundle\Controller\ExceptionController
+        arguments:
+            - '@twig'
+            - '%kernel.debug%'
index 16e4f063f457b0f57c1ec558b8307b5c0d9e19ff..da7e2652aadafd335f1a83d43e913b410544f0a1 100644 (file)
@@ -45,6 +45,7 @@ footer:
         # social: 'Social'
         # powered_by: 'powered by'
         about: 'Om'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Opsætning'
@@ -94,6 +95,7 @@ config:
         # if_label: 'if'
         # then_tag_as_label: 'then tag as'
         # delete_rule_label: 'delete'
+        # edit_rule_label: 'edit'
         # rule_label: 'Rule'
         # tags_label: 'Tags'
         # faq:
@@ -358,7 +360,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     # firefox:
     #    page_title: 'Import > Firefox'
-    #    description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+    #    description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
     #    how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     #chrome:
     #    page_title: 'Import > Chrome'
index 5db4b28e50c51e6378373fb9992c4cae03f6e313..eb82f13f3535bb6b8244fd66ef0b36d5b0852cb6 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Soziales'
         powered_by: 'angetrieben von'
         about: 'Über'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Einstellungen'
@@ -94,6 +95,7 @@ config:
         if_label: 'Wenn'
         then_tag_as_label: 'dann tagge als'
         delete_rule_label: 'löschen'
+        # edit_rule_label: 'edit'
         rule_label: 'Regel'
         tags_label: 'Tags'
         faq:
@@ -358,7 +360,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     firefox:
         page_title: 'Aus Firefox importieren'
-        # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+        # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
         # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     chrome:
         page_title: 'Aus Chrome importieren'
index f9f8e217a575bfed3f0b3ddaa44a2c1c9d4ba773..01d8053be5c7e9f367dece9cd97c006f9d8531b8 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Social'
         powered_by: 'powered by'
         about: 'About'
+    stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Config'
@@ -94,6 +95,7 @@ config:
         if_label: 'if'
         then_tag_as_label: 'then tag as'
         delete_rule_label: 'delete'
+        edit_rule_label: 'edit'
         rule_label: 'Rule'
         tags_label: 'Tags'
         faq:
@@ -358,7 +360,7 @@ import:
         enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     firefox:
         page_title: 'Import > Firefox'
-        description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+        description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
         how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     chrome:
         page_title: 'Import > Chrome'
index db87cd966f3a99512f6a46f7d6c05f7bb2353f92..5364e99a616a23e2750579c645e80085d7f1b106 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Social'
         powered_by: 'funciona por'
         about: 'Acerca de'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Configuración'
@@ -94,6 +95,7 @@ config:
         if_label: 'si'
         then_tag_as_label: 'Etiquete como'
         delete_rule_label: 'Borre'
+        # edit_rule_label: 'edit'
         rule_label: 'Regla'
         tags_label: 'Etiquetas'
         faq:
@@ -358,7 +360,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     firefox:
        page_title: 'Importar > Firefox'
-       # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+       # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
        # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     chrome:
        page_title: 'Importar > Chrome'
index f6943ae5a3e067e327f7352cdb8b7f6a71536a2f..6f42b173edbc138002060ed940f88c220f35acaf 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'شبکه‌های اجتماعی'
         powered_by: 'توانمند با'
         about: 'درباره'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'پیکربندی'
@@ -94,6 +95,7 @@ config:
         if_label: 'اگر'
         then_tag_as_label: 'این برچسب را بزن'
         delete_rule_label: 'پاک کن'
+        # edit_rule_label: 'edit'
         rule_label: 'قانون'
         tags_label: 'برچسب‌ها'
         faq:
@@ -357,7 +359,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     firefox:
        page_title: 'درون‌ریزی > Firefox'
-       # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+       # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
        # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     chrome:
        page_title: 'درون‌ریزی > Chrome'
index f2c92070540ae94350d339fdfcc22fcc30f5b6dc..6984be834b51998bdb6b641befb134ba16e943db 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Social'
         powered_by: 'propulsé par'
         about: 'À propos'
+    stats: Depuis le %user_creation% vous avez lu %nb_archives% articles. Ce qui fait %per_day% par jour !
 
 config:
     page_title: 'Configuration'
@@ -94,6 +95,7 @@ config:
         if_label: 'si'
         then_tag_as_label: 'alors attribuer les tags'
         delete_rule_label: 'supprimer'
+        edit_rule_label: 'éditer'
         rule_label: 'Règle'
         tags_label: 'Tags'
         faq:
@@ -358,7 +360,7 @@ import:
         enabled: "Les imports sont asynchrones. Une fois l'import commencé un worker externe traitera les messages un par un. Le service activé est :"
     firefox:
         page_title: 'Import > Firefox'
-        description: "Cet outil va vous permettre d'importer tous vos marques-pages de Firefox. <p>Pour Firefox, ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json. </p>"
+        description: "Cet outil va vous permettre d'importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json. </p>"
         how_to: "Choisissez le fichier de sauvegarde de vos marques-page et cliquez sur le bouton pour l'importer. Soyez avertis que le processus peut prendre un temps assez long car tous les articles doivent être récupérés en ligne."
     chrome:
         page_title: 'Import > Chrome'
index 32897b32da90811e2ded39b9434076c74cc82e91..30b3287ebf3113ae0420e1a3e1799f1f3b0d7bed 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Social'
         powered_by: 'powered by'
         about: 'About'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Configurazione'
@@ -94,6 +95,7 @@ config:
         if_label: 'se'
         then_tag_as_label: 'allora tagga come'
         delete_rule_label: 'elimina'
+        # edit_rule_label: 'edit'
         rule_label: 'Regola'
         tags_label: 'Tag'
         faq:
@@ -357,7 +359,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     firefox:
        page_title: 'Importa da > Firefox'
-       # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+       # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
        # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     chrome:
        page_title: 'Importa da > Chrome'
index 8caf3c0c5b8d3e4e5a8571f99b544365c8c9f5d3..a077f1bf30756a50221f1293e5499126e51a71ac 100644 (file)
@@ -19,14 +19,14 @@ menu:
         unread: 'Pas legits'
         starred: 'Favorits'
         archive: 'Legits'
-        all_articles: 'Tots los articles'
+        all_articles: 'Totes los articles'
         config: 'Configuracion'
         tags: 'Etiquetas'
         internal_settings: 'Configuracion interna'
         import: 'Importar'
         howto: 'Ajuda'
         developer: 'Desvolopador'
-        logout: 'Déconnexion'
+        logout: 'Desconnexion'
         about: 'A prepaus'
         search: 'Cercar'
         save_link: 'Enregistrar un novèl article'
@@ -45,9 +45,10 @@ footer:
         social: 'Social'
         powered_by: 'propulsat per'
         about: 'A prepaus'
-    page_title: 'Configuracion'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
+    page_title: 'Configuracion'
     tab_menu:
         settings: 'Paramètres'
         rss: 'RSS'
@@ -72,8 +73,8 @@ config:
     form_rss:
         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."
         token_label: 'Geton RSS'
-        no_token: 'Aucun jeton généré'
-        token_create: 'Pas cap de geton generat'
+        no_token: 'Pas cap de geton generat'
+        token_create: 'Creatz vòstre geton'
         token_reset: 'Reïnicializatz vòstre geton'
         rss_links: 'URL de vòstres fluxes RSS'
         rss_link:
@@ -94,6 +95,7 @@ config:
         if_label: 'se'
         then_tag_as_label: 'alara atribuir las etiquetas'
         delete_rule_label: 'suprimir'
+        # edit_rule_label: 'edit'
         rule_label: 'Règla'
         tags_label: 'Etiquetas'
         faq:
@@ -187,7 +189,7 @@ entry:
             re_fetch_content: 'Tornar cargar lo contengut'
             delete: 'Suprimir'
             add_a_tag: 'Ajustar una etiqueta'
-            share_content: 'Partatjar'
+            share_content: 'Partejar'
             share_email_label: 'Corrièl'
             public_link: 'ligam public'
             delete_public_link: 'suprimir lo ligam public'
@@ -224,7 +226,7 @@ about:
         developped_by: 'Desvolopat per'
         website: 'Site web'
         many_contributors: 'E un fum de contributors ♥ <a href="https://github.com/wallabag/wallabag/graphs/contributors">sur Github</a>'
-        project_website: 'Site web del projète'
+        project_website: 'Site web del projècte'
         license: 'Licéncia'
         version: 'Version'
     getting_help:
@@ -245,7 +247,7 @@ about:
 
 howto:
     page_title: 'Ajuda'
-    page_description: "I a mai d'un biai d'enregistrar un article :"
+    page_description: "I a mai d'un biais d'enregistrar un article :"
     top_menu:
         browser_addons: 'Extensions de navigator'
         mobile_apps: 'Aplicacions mobil'
@@ -351,26 +353,26 @@ import:
         page_title: 'Importar > Wallabag v2'
         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\". Traparatz un fichièr \"All articles.json\""
     readability:
-        page_title: 'Importer > Readability'
+        page_title: 'Importar > Readability'
         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)."
         how_to: "Mercés de seleccionar vòstre Readability fichièr e de clicar sul boton dejós per lo telecargar e l'importar."
     worker:
-        # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
+        enabled: "L'importacion se fa de manièra asincròna. Un còp l'importacion lançada, una aisina externa s'ocuparà dels messatges un per un. Lo servici actual es : "
     firefox:
-       page_title: 'Importer > Firefox'
-       # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
-       # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+        page_title: 'Importar > Firefox'
+        description: "Aquesta aisina importarà totas vòstres favorits de Firefox. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+        how_to: "Mercés de causir lo fichièr de salvagarda e de clicar sul boton dejós per l'importar. Notatz que lo tractament pòt durar un moment ja que totes los articles an d'èsser recuperats."
     chrome:
-       page_title: 'Importer > Chrome'
-       # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
-       # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+        page_title: 'Importar > Chrome'
+        description: "Aquesta aisina importarà totas vòstres favorits de Chrome. L'emplaçament del fichièr depend de vòstre sistèma operatiu : <ul><li>Sus Linux, anatz al dorsièr <code>~/.config/chromium/Default/</code></li><li>Sus Windows, deu èsser dins <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>sus OS X, deu èsser dins <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Un còp enlà, copiatz lo fichièr de favorits dins un endrech que volètz.<em><br>Notatz que s'avètz Chromium al lòc de Chrome, vos cal cambiar lo camin segon aquesta situacion.</em></p>"
+        how_to: "Mercés de causir lo fichièr de salvagarda e de clicar sul boton dejós per l'importar. Notatz que lo tractament pòt durar un moment ja que totes los articles an d'èsser recuperats."
     instapaper:
-        page_title: 'Importer > Instapaper'
-        # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
-        # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
+        page_title: 'Importar > Instapaper'
+        description: "Aquesta aisina importarà totas vòstres articles d'Instapaper. Sus la pagina de paramètres (https://www.instapaper.com/user), clicatz sus \"Download .CSV file\" dins la seccion \"Export\". Un fichièr CSV serà telecargat (aital \"instapaper-export.csv\")."
+        how_to: "Mercés de causir vòstre fichièr Instapaper e de clicar sul boton dejós per lo telecargar e l'importar"
 
 developer:
-    page_title: 'Desvolopador'
+    page_title: 'Desvolopaire'
     welcome_message: "Benvenguda sus l'API de wallabag"
     documentation: 'Documentacion'
     how_to_first_app: 'Cossí crear vòstra primièra aplicacion'
@@ -394,16 +396,18 @@ developer:
         page_title: 'Desvlopador > Novèl client'
         page_description: "Anatz crear un novèl client. Mercés de cumplir l'url de redireccion cap a vòstra aplicacion."
         form:
+            name_label: "Nom del client"
             redirect_uris_label: 'URLs de redireccion'
             save_label: 'Crear un novèl client'
         action_back: 'Retorn'
     client_parameter:
         page_title: 'Desvolopador > Los paramètres de vòstre client'
         page_description: 'Vaquí los paramètres de vòstre client'
+        field_name: 'Nom del client'
         field_id: 'ID Client'
         field_secret: 'Clau secreta'
         back: 'Retour'
-        read_howto: 'Legir \"cossí crear ma primièra aplicacion\"'
+        read_howto: 'Legir "cossí crear ma primièra aplicacion"'
     howto:
         page_title: 'Desvolopador > Cossí crear ma primièra aplicacion'
         description:
@@ -433,10 +437,10 @@ flashes:
         notice:
             entry_already_saved: 'Article ja salvargardat lo %date%'
             entry_saved: 'Article enregistrat'
-            # entry_saved_failed: 'Entry saved but fetching content failed'
+            entry_saved_failed: 'Article salvat mai fracàs de la recuperacion del contengut'
             entry_updated: 'Article mes a jorn'
             entry_reloaded: 'Article recargat'
-            # entry_reload_failed: 'Entry reloaded but fetching content failed'
+            entry_reload_failed: "L'article es estat cargat de nòu mai la recuperacion del contengut a fracassat"
             entry_archived: 'Article marcat coma legit'
             entry_unarchived: 'Article marcat coma pas legit'
             entry_starred: 'Article apondut dins los favorits'
@@ -450,10 +454,10 @@ flashes:
             failed: "L'importacion a fracassat, mercés de tornar ensajar"
             failed_on_file: "Errorr pendent du tractament de l'import. Mercés de verificar vòstre fichièr."
             summary: "Rapòrt d'import: %imported% importats, %skipped% ja presents."
-            # summary_with_queue: 'Import summary: %queued% queued.'
+            summary_with_queue: "Rapòrt d'import : %queued% en espèra de tractament."
         error:
-            # redis_enabled_not_installed: Redis is enabled for handle asynchronous import but it looks like <u>we can't connect to it</u>. Please check Redis configuration.
-            # rabbit_enabled_not_installed: RabbitMQ is enabled for handle asynchronous import but it looks like <u>we can't connect to it</u>. Please check RabbitMQ configuration.
+            redis_enabled_not_installed: "Redis es capable d'importar de manièra asincròna mai sembla que <u>podèm pas nos conectar amb el</u>. Mercés de verificar la configuracion de Redis."
+            rabbit_enabled_not_installed: "RabbitMQ es capable d'importar de manièra asincròna mai sembla que <u>podèm pas nos conectar amb el</u>. Mercés de verificar la configuracion de RabbitMQ."
     developer:
         notice:
             client_created: 'Novèl client creat'
index 8f0555b1efea7f5bef4388fc6eb2bbb4e9490140..cad94dd5da85e08ea85f624fd124a7b695a1e6eb 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Społeczność'
         powered_by: 'Kontrolowany przez'
         about: 'O nas'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Konfiguracja'
@@ -94,6 +95,7 @@ config:
         if_label: 'jeżeli'
         then_tag_as_label: 'wtedy otaguj jako'
         delete_rule_label: 'usuń'
+        # edit_rule_label: 'edit'
         rule_label: 'Reguła'
         tags_label: 'Tagi'
         faq:
@@ -358,7 +360,7 @@ import:
         enabled: "Import jest wykonywany asynchronicznie. Od momentu rozpoczęcia importu, zewnętrzna usługa może zajmować się na raz tylko jednym zadaniem. Bieżącą usługą jest:"
     firefox:
        page_title: 'Import > Firefox'
-       description: "Ten importer zaimportuje wszystkie twoje zakładki z Firefoksa. <p>Dla Firefoksa, idź do twoich zakładek (Ctrl+Shift+O), następnie w \"Import i kopie zapasowe\", wybierz \"Utwórz kopię zapasową...\". Uzyskasz plik .json."
+       description: "Ten importer zaimportuje wszystkie twoje zakładki z Firefoksa. Idź do twoich zakładek (Ctrl+Shift+O), następnie w \"Import i kopie zapasowe\", wybierz \"Utwórz kopię zapasową...\". Uzyskasz plik .json."
        how_to: "Wybierz swój plik z zakładkami i naciśnij poniższy przycisk, aby je zaimportować. Może to zająć dłuższą chwilę, zanim wszystkie artykuły zostaną przeniesione."
     chrome:
        page_title: 'Import > Chrome'
index ee56dd15ced3220f3335844ea041da224a1c6b2f..a271d6f3c584d4a9d515f8b162f55fd65c60837d 100644 (file)
@@ -45,6 +45,7 @@ footer:
         # social: 'Social'
         # powered_by: 'powered by'
         about: 'Despre'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Configurație'
@@ -94,6 +95,7 @@ config:
         # if_label: 'if'
         # then_tag_as_label: 'then tag as'
         # delete_rule_label: 'delete'
+        # edit_rule_label: 'edit'
         # rule_label: 'Rule'
         # tags_label: 'Tags'
         # faq:
@@ -358,7 +360,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     # firefox:
     #    page_title: 'Import > Firefox'
-    #    description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+    #    description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
     #    how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     # chrome:
     #    page_title: 'Import > Chrome'
index befd39ed865fd6bae0b1fffacacbdc875225e8a6..f2307e65815dc4bb4eb1ff13d0359e72a9e432f9 100644 (file)
@@ -45,6 +45,7 @@ footer:
         social: 'Sosyal'
         powered_by: 'powered by'
         about: 'Hakkımızda'
+    # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
 
 config:
     page_title: 'Yapılandırma'
@@ -358,7 +359,7 @@ import:
         # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
     firefox:
        page_title: 'İçe Aktar > Firefox'
-       # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+       # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
        # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
     chrome:
        page_title: 'İçe Aktar > Chrome'
index 6446cf2c33823d2f5fd724fa454bcb7b5dbaa37a..dd4f7b009e941cc8940a6ddbee7c1c51320ca8c5 100644 (file)
             « {{ tagging_rule.rule }} »
             {{ 'config.form_rules.then_tag_as_label'|trans }}
             « {{ tagging_rule.tags|join(', ') }} »
+            <a href="{{ path('edit_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.edit_rule_label'|trans }}" class="tool mode_edit">✎</a>
             <a href="{{ path('delete_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.delete_rule_label'|trans }}" class="tool delete icon-trash icon"></a>
         </li>
         {% endfor %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Exception/error.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Exception/error.html.twig
new file mode 100644 (file)
index 0000000..b52634f
--- /dev/null
@@ -0,0 +1,24 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'error.page_title'|trans }}{% endblock %}
+
+{% block body_class %}login{% endblock %}
+
+{% block menu %}{% endblock %}
+{% block messages %}{% endblock %}
+{% block header %}{% endblock %}
+
+{% block content %}
+<main class="valign-wrapper">
+    <div class="valign row">
+        <div class="card sw">
+            <div class="center"><img src="{{ asset('bundles/wallabagcore/themes/_global/img/logo-w.png') }}" alt="wallabag logo" /></div>
+            <h2>{{ status_code }}: {{ status_text }}</h2>
+            <p>{{ exception.message }}</p>
+        </div>
+    </div>
+</main>
+{% endblock %}
+
+{% block footer %}
+{% endblock %}
index 5330c35392d92f3dc7c442141e09e88b95201fcf..650a3ae2a03ce061ea148e318724799934ff4e38 100644 (file)
                                         « {{ tagging_rule.rule }} »
                                         {{ 'config.form_rules.then_tag_as_label'|trans }}
                                         « {{ tagging_rule.tags|join(', ') }} »
+                                        <a href="{{ path('edit_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.edit_rule_label'|trans }}">
+                                            <i class="tool grey-text mode_edit material-icons">mode_edit</i>
+                                        </a>
                                         <a href="{{ path('delete_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.delete_rule_label'|trans }}">
                                             <i class="tool grey-text delete material-icons">delete</i>
                                         </a>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Exception/error.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Exception/error.html.twig
new file mode 100644 (file)
index 0000000..6be78ed
--- /dev/null
@@ -0,0 +1,30 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'error.page_title'|trans }}{% endblock %}
+
+{% block body_class %}login{% endblock %}
+
+{% block menu %}{% endblock %}
+{% block messages %}{% endblock %}
+
+{% block content %}
+<main class="valign-wrapper">
+    <div class="valign row">
+        <div class="card sw">
+            <div class="center"><img src="{{ asset('bundles/wallabagcore/themes/_global/img/logo-other_themes.png') }}" alt="wallabag logo" /></div>
+            <div class="card-content">
+                <div class="row">
+                    <h5>{{ status_code }}: {{ status_text }}</h5>
+                    <p>{{ exception.message }}</p>
+                    {# {% for trace in exception.trace %}
+                        <p>{{ trace.class }} - {{ trace.type }} - {{ trace.file }} - {{ trace.line }}</p>
+                    {% endfor %} #}
+                </div>
+            </div>
+        </div>
+    </div>
+</main>
+{% endblock %}
+
+{% block footer %}
+{% endblock %}
index df05e2a4890bd5dfd5d4aa751ec5dfbf46436540..b2d77c2e2d81cf1f73c6cc1ebd583b9908292015 100644 (file)
     <footer class="page-footer cyan darken-2">
         <div class="footer-copyright">
             <div class="container">
-                <p>{{ 'footer.wallabag.powered_by'|trans }} <a target="_blank" href="https://wallabag.org" class="grey-text text-lighten-4">wallabag</a></p>
-                <a class="grey-text text-lighten-4 right" href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans }}</a>
+                <div class="row">
+                    <div class="col s8">
+                        <p>
+                            {{ display_stats() }}
+                        </p>
+                    </div>
+                    <div class="col s4">
+                        <p>
+                            {{ 'footer.wallabag.powered_by'|trans }} <a target="_blank" href="https://wallabag.org" class="grey-text text-lighten-4">wallabag</a> –
+                            <a class="grey-text text-lighten-4" href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans|lower }}</a>
+                        </p>
+                    </div>
+                </div>
             </div>
         </div>
     </footer>
index fb4c7412395f4affcb3b4b73f844ea06d498d4cc..783cde3e70897aedb877f45f8ad0562a5b68cc9b 100644 (file)
@@ -5,6 +5,7 @@ namespace Wallabag\CoreBundle\Twig;
 use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
 use Wallabag\CoreBundle\Repository\EntryRepository;
 use Wallabag\CoreBundle\Repository\TagRepository;
+use Symfony\Component\Translation\TranslatorInterface;
 
 class WallabagExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface
 {
@@ -12,13 +13,15 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
     private $entryRepository;
     private $tagRepository;
     private $lifeTime;
+    private $translator;
 
-    public function __construct(EntryRepository $entryRepository = null, TagRepository $tagRepository = null, TokenStorageInterface $tokenStorage = null, $lifeTime = 0)
+    public function __construct(EntryRepository $entryRepository, TagRepository $tagRepository, TokenStorageInterface $tokenStorage, $lifeTime, TranslatorInterface $translator)
     {
         $this->entryRepository = $entryRepository;
         $this->tagRepository = $tagRepository;
         $this->tokenStorage = $tokenStorage;
         $this->lifeTime = $lifeTime;
+        $this->translator = $translator;
     }
 
     public function getFilters()
@@ -33,6 +36,7 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
         return array(
             new \Twig_SimpleFunction('count_entries', [$this, 'countEntries']),
             new \Twig_SimpleFunction('count_tags', [$this, 'countTags']),
+            new \Twig_SimpleFunction('display_stats', [$this, 'displayStats']),
         );
     }
 
@@ -107,6 +111,40 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
         return $this->tagRepository->countAllTags($user->getId());
     }
 
+    /**
+     * Display a single line about reading stats.
+     *
+     * @return string
+     */
+    public function displayStats()
+    {
+        $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
+
+        if (null === $user || !is_object($user)) {
+            return 0;
+        }
+
+        $query = $this->entryRepository->getBuilderForArchiveByUser($user->getId())
+            ->select('e.id')
+            ->groupBy('e.id')
+            ->getQuery();
+
+        $query->useQueryCache(true);
+        $query->useResultCache(true);
+        $query->setResultCacheLifetime($this->lifeTime);
+
+        $nbArchives = count($query->getArrayResult());
+
+        $interval = $user->getCreatedAt()->diff(new \DateTime('now'));
+        $nbDays = (int) $interval->format('%a') ?: 1;
+
+        return $this->translator->trans('footer.stats', [
+            '%user_creation%' => $user->getCreatedAt()->format('F jS, Y'),
+            '%nb_archives%' => $nbArchives,
+            '%per_day%' => round($nbArchives / $nbDays, 2),
+        ]);
+    }
+
     public function getName()
     {
         return 'wallabag_extension';
similarity index 53%
rename from src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php
rename to src/Wallabag/UserBundle/EventListener/CreateConfigListener.php
index 10586126fe35f43ef5ae45a1d1e635686259adb0..15f4ac3dee41faad596d6b56484d3cc1858b6e41 100644 (file)
@@ -1,39 +1,49 @@
 <?php
 
-namespace Wallabag\CoreBundle\EventListener;
+namespace Wallabag\UserBundle\EventListener;
 
 use Doctrine\ORM\EntityManager;
-use FOS\UserBundle\Event\FilterUserResponseEvent;
+use FOS\UserBundle\Event\UserEvent;
 use FOS\UserBundle\FOSUserEvents;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Wallabag\CoreBundle\Entity\Config;
 
-class RegistrationConfirmedListener implements EventSubscriberInterface
+/**
+ * This listener will create the associated configuration when a user register.
+ * This configuration will be created right after the registration (no matter if it needs an email validation).
+ */
+class CreateConfigListener implements EventSubscriberInterface
 {
     private $em;
     private $theme;
     private $itemsOnPage;
     private $rssLimit;
     private $language;
+    private $readingSpeed;
 
-    public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language)
+    public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language, $readingSpeed)
     {
         $this->em = $em;
         $this->theme = $theme;
         $this->itemsOnPage = $itemsOnPage;
         $this->rssLimit = $rssLimit;
         $this->language = $language;
+        $this->readingSpeed = $readingSpeed;
     }
 
     public static function getSubscribedEvents()
     {
         return [
-            FOSUserEvents::REGISTRATION_CONFIRMED => 'authenticate',
+            // when a user register using the normal form
+            FOSUserEvents::REGISTRATION_COMPLETED => 'createConfig',
+            // when we manually create a user using the command line
+            // OR when we create it from the config UI
+            FOSUserEvents::USER_CREATED => 'createConfig',
         ];
     }
 
-    public function authenticate(FilterUserResponseEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null)
+    public function createConfig(UserEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null)
     {
         if (!$event->getUser()->isEnabled()) {
             return;
@@ -44,6 +54,8 @@ class RegistrationConfirmedListener implements EventSubscriberInterface
         $config->setItemsPerPage($this->itemsOnPage);
         $config->setRssLimit($this->rssLimit);
         $config->setLanguage($this->language);
+        $config->setReadingSpeed($this->readingSpeed);
+
         $this->em->persist($config);
         $this->em->flush();
     }
index 05830555ee8cb9eee5818598930e3c14fe8ccba4..eb9c8e676e0cbd03b4f92eda2b502a1f5c88ad32 100644 (file)
@@ -20,3 +20,15 @@ services:
         factory: [ "@doctrine.orm.default_entity_manager", getRepository ]
         arguments:
             - WallabagUserBundle:User
+
+    wallabag_user.create_config:
+        class: Wallabag\UserBundle\EventListener\CreateConfigListener
+        arguments:
+            - "@doctrine.orm.entity_manager"
+            - "%wallabag_core.theme%"
+            - "%wallabag_core.items_on_page%"
+            - "%wallabag_core.rss_limit%"
+            - "%wallabag_core.language%"
+            - "%wallabag_core.reading_speed%"
+        tags:
+            - { name: kernel.event_subscriber }
index 7193f9b0e4331976f2768557425af73ec36faa2a..bb3ea9e2cfea3a00a88dab2ed18ba5fb6e26343f 100644 (file)
@@ -56,8 +56,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
 
         $crawler = $client->followRedirect();
 
-        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
-        $this->assertContains('flashes.config.notice.config_saved', $alert[0]);
+        $this->assertContains('flashes.config.notice.config_saved', $crawler->filter('body')->extract(['_text'])[0]);
     }
 
     public function testChangeReadingSpeed()
@@ -213,8 +212,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
 
         $crawler = $client->followRedirect();
 
-        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
-        $this->assertContains('flashes.config.notice.password_updated', $alert[0]);
+        $this->assertContains('flashes.config.notice.password_updated', $crawler->filter('body')->extract(['_text'])[0]);
     }
 
     public function dataForUserFailed()
@@ -382,8 +380,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
 
         $crawler = $client->followRedirect();
 
-        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
-        $this->assertContains('flashes.config.notice.user_added', $alert[0]);
+        $this->assertContains('flashes.config.notice.user_added', $crawler->filter('body')->extract(['_text'])[0]);
 
         $em = $client->getContainer()->get('doctrine.orm.entity_manager');
         $user = $em
@@ -474,8 +471,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
 
         $crawler = $client->followRedirect();
 
-        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
-        $this->assertContains('flashes.config.notice.rss_updated', $alert[0]);
+        $this->assertContains('flashes.config.notice.rss_updated', $crawler->filter('body')->extract(['_text'])[0]);
     }
 
     public function dataForRssFailed()
@@ -540,8 +536,32 @@ class ConfigControllerTest extends WallabagCoreTestCase
 
         $crawler = $client->followRedirect();
 
-        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
-        $this->assertContains('flashes.config.notice.tagging_rules_updated', $alert[0]);
+        $this->assertContains('flashes.config.notice.tagging_rules_updated', $crawler->filter('body')->extract(['_text'])[0]);
+
+        $editLink = $crawler->filter('.mode_edit')->last()->link();
+
+        $crawler = $client->click($editLink);
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+        $this->assertContains('?tagging-rule=', $client->getResponse()->headers->get('location'));
+
+        $crawler = $client->followRedirect();
+
+        $form = $crawler->filter('button[id=tagging_rule_save]')->form();
+
+        $data = [
+            'tagging_rule[rule]' => 'readingTime <= 30',
+            'tagging_rule[tags]' => 'short reading',
+        ];
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertContains('flashes.config.notice.tagging_rules_updated', $crawler->filter('body')->extract(['_text'])[0]);
+
+        $this->assertContains('readingTime <= 30', $crawler->filter('body')->extract(['_text'])[0]);
 
         $deleteLink = $crawler->filter('.delete')->last()->link();
 
@@ -549,8 +569,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
         $this->assertEquals(302, $client->getResponse()->getStatusCode());
 
         $crawler = $client->followRedirect();
-        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
-        $this->assertContains('flashes.config.notice.tagging_rules_deleted', $alert[0]);
+        $this->assertContains('flashes.config.notice.tagging_rules_deleted', $crawler->filter('body')->extract(['_text'])[0]);
     }
 
     public function dataForTaggingRuleFailed()
@@ -613,7 +632,23 @@ class ConfigControllerTest extends WallabagCoreTestCase
             ->getRepository('WallabagCoreBundle:TaggingRule')
             ->findAll()[0];
 
-        $crawler = $client->request('GET', '/tagging-rule/delete/'.$rule->getId());
+        $crawler = $client->request('GET', '/tagging-rule/edit/'.$rule->getId());
+
+        $this->assertEquals(403, $client->getResponse()->getStatusCode());
+        $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
+        $this->assertContains('You can not access this tagging rule', $body[0]);
+    }
+
+    public function testEditingTaggingRuleFromAnOtherUser()
+    {
+        $this->logInAs('bob');
+        $client = $this->getClient();
+
+        $rule = $client->getContainer()->get('doctrine.orm.entity_manager')
+            ->getRepository('WallabagCoreBundle:TaggingRule')
+            ->findAll()[0];
+
+        $crawler = $client->request('GET', '/tagging-rule/edit/'.$rule->getId());
 
         $this->assertEquals(403, $client->getResponse()->getStatusCode());
         $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
index e29b58b5795c35f3e29d4c56cf854f00f2af541e..2e6fccfb152fe8830efddad032b8b15e9e95bb17 100644 (file)
@@ -125,16 +125,14 @@ class UsernameRssTokenConverterTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue($converter->supports($params));
     }
 
-    /**
-     * @expectedException InvalidArgumentException
-     * @expectedExceptionMessage Route attribute is missing
-     */
     public function testApplyEmptyRequest()
     {
         $params = new ParamConverter([]);
         $converter = new UsernameRssTokenConverter();
 
-        $converter->apply(new Request(), $params);
+        $res = $converter->apply(new Request(), $params);
+
+        $this->assertFalse($res);
     }
 
     /**
index 8ec2a75a228b1c202117525e7353f152dd1b1a50..b1c8c946315f4995918fdfbeca37798b39a572a3 100644 (file)
@@ -8,7 +8,23 @@ class WallabagExtensionTest extends \PHPUnit_Framework_TestCase
 {
     public function testRemoveWww()
     {
-        $extension = new WallabagExtension();
+        $entryRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $tagRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\TagRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $extension = new WallabagExtension($entryRepository, $tagRepository, $tokenStorage, 0, $translator);
 
         $this->assertEquals('lemonde.fr', $extension->removeWww('www.lemonde.fr'));
         $this->assertEquals('lemonde.fr', $extension->removeWww('lemonde.fr'));
similarity index 83%
rename from tests/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListenerTest.php
rename to tests/Wallabag/UserBundle/EventListener/CreateConfigListenerTest.php
index e45722fa78565ecf04fc8071fa3229d8d78e76ce..0cebd3e43731a23dba09040ab0b984a9574e75f1 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Wallabag\CoreBundle\EventListener;
+namespace Tests\Wallabag\UserBundle\EventListener;
 
 use FOS\UserBundle\Event\FilterUserResponseEvent;
 use FOS\UserBundle\FOSUserEvents;
@@ -8,10 +8,10 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Wallabag\CoreBundle\Entity\Config;
-use Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener;
+use Wallabag\UserBundle\EventListener\CreateConfigListener;
 use Wallabag\UserBundle\Entity\User;
 
-class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
+class CreateConfigListenerTest extends \PHPUnit_Framework_TestCase
 {
     private $em;
     private $listener;
@@ -25,12 +25,13 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->listener = new RegistrationConfirmedListener(
+        $this->listener = new CreateConfigListener(
             $this->em,
             'baggy',
             20,
             50,
-            'fr'
+            'fr',
+            1
         );
 
         $this->dispatcher = new EventDispatcher();
@@ -55,7 +56,7 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
         $this->em->expects($this->never())->method('flush');
 
         $this->dispatcher->dispatch(
-            FOSUserEvents::REGISTRATION_CONFIRMED,
+            FOSUserEvents::REGISTRATION_COMPLETED,
             $event
         );
     }
@@ -76,6 +77,7 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
         $config->setItemsPerPage(20);
         $config->setRssLimit(50);
         $config->setLanguage('fr');
+        $config->setReadingSpeed(1);
 
         $this->em->expects($this->once())
             ->method('persist')
@@ -84,7 +86,7 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
             ->method('flush');
 
         $this->dispatcher->dispatch(
-            FOSUserEvents::REGISTRATION_CONFIRMED,
+            FOSUserEvents::REGISTRATION_COMPLETED,
             $event
         );
     }