]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #1612 from wallabag/v2-settings-page
authorNicolas Lœuillet <nicolas@loeuillet.org>
Thu, 4 Feb 2016 14:59:57 +0000 (15:59 +0100)
committerNicolas Lœuillet <nicolas@loeuillet.org>
Thu, 4 Feb 2016 14:59:57 +0000 (15:59 +0100)
Settings page

30 files changed:
app/config/parameters.yml.dist
app/config/tests/parameters.yml.dist.mysql
app/config/tests/parameters.yml.dist.pgsql
docs/en/user/import.rst
docs/img/user/export_wllbg_2.png [new file with mode: 0644]
src/Wallabag/ApiBundle/Controller/WallabagRestController.php
src/Wallabag/ApiBundle/DependencyInjection/Configuration.php
src/Wallabag/CoreBundle/Command/InstallCommand.php
src/Wallabag/CoreBundle/Controller/ConfigController.php
src/Wallabag/CoreBundle/Controller/EntryController.php
src/Wallabag/CoreBundle/Form/Type/EditEntryType.php
src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php [moved from src/Wallabag/CoreBundle/Filter/EntryFilterType.php with 98% similarity]
src/Wallabag/CoreBundle/Resources/config/services.yml
src/Wallabag/CoreBundle/Resources/public/themes/baggy/css/main.css
src/Wallabag/CoreBundle/Resources/views/themes/baggy/README.md [changed mode: 0755->0644]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Static/about.html.twig [changed mode: 0755->0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/README.md [changed mode: 0755->0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/Static/about.html.twig [changed mode: 0755->0644]
src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php [new file with mode: 0644]
src/Wallabag/ImportBundle/Import/PocketImport.php
src/Wallabag/ImportBundle/Import/WallabagV1Import.php
src/Wallabag/ImportBundle/Import/WallabagV2Import.php [new file with mode: 0644]
src/Wallabag/ImportBundle/Resources/config/services.yml
src/Wallabag/ImportBundle/Resources/views/WallabagV2/index.html.twig [new file with mode: 0644]
src/Wallabag/ImportBundle/Tests/Controller/ImportControllerTest.php
src/Wallabag/ImportBundle/Tests/Controller/WallabagV2ControllerTest.php [new file with mode: 0644]
src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php
src/Wallabag/ImportBundle/Tests/Import/WallabagV2ImportTest.php [new file with mode: 0644]
src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v2.json [new file with mode: 0644]
web/favicon.ico [new file with mode: 0644]

index 57cae9a062a66b3d8f8e55f84f872432ef8cbf33..79654e9e8bb95d3b876b27471268a59809f2bb7b 100644 (file)
@@ -35,7 +35,7 @@ parameters:
     locale:            en
 
     # A secret key that's used to generate certain security-related tokens
-    secret:            ThisTokenIsNotSoSecretChangeIt
+    secret:            ovmpmAWXRCabNlMgzlzFXDYmCFfzGv
 
     # two factor stuff
     twofactor_auth: true
index 2823a4243f30b3c23653fa500f7bee1f42679f02..dceb5dea0ec77e38a003a9934fdd66b02030b1e2 100644 (file)
@@ -12,7 +12,7 @@ parameters:
     test_database_driver: pdo_mysql
     test_database_host: localhost
     test_database_port: 3306
-    test_database_name: wallabag
+    test_database_name: wallabag_test
     test_database_user: root
     test_database_password: ~
     test_database_path: ~
index 5b55cb64305ea16c37ade9c7b843e02cd1298011..e07db6108bc1e5dd74595077dd039f0ef1399fdf 100644 (file)
@@ -12,7 +12,7 @@ parameters:
     test_database_driver: pdo_pgsql
     test_database_host: localhost
     test_database_port:
-    test_database_name: wallabag
+    test_database_name: wallabag_test
     test_database_user: travis
     test_database_password: ~
     test_database_path: ~
index 8f6cf4c142ccfc58427f7b8d89ad5205b2aaaff1..37f375b2d7c0f14acb2e6aa588963f5b97fab20c 100644 (file)
@@ -1,8 +1,8 @@
 Migrate to wallabag
 ===================
 
-From wallabag 1.x
------------------
+From wallabag
+-------------
 
 Export your data from your wallabag 1.x
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -15,6 +15,17 @@ On your config page, click on ``JSON export`` in the ``Export your wallabag data
 
 You will have a ``wallabag-export-1-1970-01-01.json`` file.
 
+Export your data from your wallabag 2.x
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On the export sidebar, click on ``JSON``.
+
+.. image:: ../../img/user/export_wllbg_2.png
+   :alt: Export from wallabag 2.x
+   :align: center
+
+You will have a ``Unread articles.json`` file.
+
 Import your data into wallabag 2.x
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -24,7 +35,7 @@ Click on  ``Import`` link in the menu, select your export file on your computer
    :alt: Import from wallabag 1.x
    :align: center
 
-All your wallabag 1.x articles will be imported.
+All your wallabag articles will be imported.
 
 From Pocket
 -----------
@@ -46,7 +57,7 @@ Import your data into wallabag 2.x
 
 Click on  ``Import`` link in the menu, on ``Import contents`` in Pocket section and then on ``Connect to Pocket and import data``.
 
-You need to authorize wallabag to interact with your Pocket account. Your data will be imported. Data import can be a demanding process for your server (we need to work on this import to improve it). 
+You need to authorize wallabag to interact with your Pocket account. Your data will be imported. Data import can be a demanding process for your server (we need to work on this import to improve it).
 
 From Instapaper
 ---------------
diff --git a/docs/img/user/export_wllbg_2.png b/docs/img/user/export_wllbg_2.png
new file mode 100644 (file)
index 0000000..db2d4cf
Binary files /dev/null and b/docs/img/user/export_wllbg_2.png differ
index d9035cac716440bc2d08111db6053a51c45e1070..84bc14a959c041520cbb0c2897949580b990cdf4 100644 (file)
@@ -9,6 +9,7 @@ use Nelmio\ApiDocBundle\Annotation\ApiDoc;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
 use Wallabag\CoreBundle\Entity\Entry;
 use Wallabag\CoreBundle\Entity\Tag;
 
@@ -73,7 +74,6 @@ class WallabagRestController extends FOSRestController
         $order = $request->query->get('order', 'desc');
         $page = (int) $request->query->get('page', 1);
         $perPage = (int) $request->query->get('perPage', 30);
-        $tags = $request->query->get('tags', []);
 
         $pager = $this->getDoctrine()
             ->getRepository('WallabagCoreBundle:Entry')
index cec4541244912411fd6a7df3c8c09b164133572a..f70a58358f51b31df5d04f11697de8925d31a64a 100644 (file)
@@ -20,10 +20,6 @@ class Configuration implements ConfigurationInterface
         $treeBuilder = new TreeBuilder();
         $rootNode = $treeBuilder->root('wallabag_api');
 
-        // Here you should define the parameters that are allowed to
-        // configure your bundle. See the documentation linked above for
-        // more information on that topic.
-
         return $treeBuilder;
     }
 }
index 937926925efd23f422fc0d9effabac5a3642bc05..e6a06eea3f47785a0710a11255698a9bf1a1eeba 100644 (file)
@@ -65,7 +65,6 @@ class InstallCommand extends ContainerAwareCommand
 
         $fulfilled = true;
 
-        // @TODO: find a better way to check requirements
         $label = '<comment>PCRE</comment>';
         if (extension_loaded('pcre')) {
             $status = '<info>OK!</info>';
index 25e698206ca3a918b2f9596e80998ea859815785..b7799746e66222a03f47882b9bb804228f463ba8 100644 (file)
@@ -199,7 +199,7 @@ class ConfigController extends Controller
      *
      * @return \Symfony\Component\HttpFoundation\RedirectResponse
      */
-    public function deleteTaggingRule(TaggingRule $rule)
+    public function deleteTaggingRuleAction(TaggingRule $rule)
     {
         if ($this->getUser()->getId() != $rule->getConfig()->getUser()->getId()) {
             throw $this->createAccessDeniedException('You can not access this tagging ryle.');
index 3e1b512ff3eb222a46b13cae9dfb3b5f5ed62eb3..ea77d138125fb63127cd0d4e90a719493847d442 100644 (file)
@@ -9,7 +9,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
 use Wallabag\CoreBundle\Entity\Entry;
-use Wallabag\CoreBundle\Filter\EntryFilterType;
+use Wallabag\CoreBundle\Form\Type\EntryFilterType;
 use Wallabag\CoreBundle\Form\Type\EditEntryType;
 use Wallabag\CoreBundle\Form\Type\NewEntryType;
 
@@ -81,7 +81,7 @@ class EntryController extends Controller
      *
      * @return \Symfony\Component\HttpFoundation\Response
      */
-    public function addEntryViaBookmarklet(Request $request)
+    public function addEntryViaBookmarkletAction(Request $request)
     {
         $entry = new Entry($this->getUser());
         $entry->setUrl($request->get('url'));
index 0cb29881834db98ebe0ffee1b20aca29f28e9696..2b1e1ef43c76a0c744a37ee6f985b3826ca70e4f 100644 (file)
@@ -16,11 +16,6 @@ class EditEntryType extends AbstractType
         $builder
             ->add('title', TextType::class, array('required' => true))
             ->add('is_public', CheckboxType::class, array('required' => false))
-            // @todo: add autocomplete
-            // ->add('tags', 'entity', array(
-            //     'class' => 'Wallabag\CoreBundle\Entity\Tag',
-            //     'choice_translation_domain' => true,
-            // ))
             ->add('save', SubmitType::class)
         ;
     }
similarity index 98%
rename from src/Wallabag/CoreBundle/Filter/EntryFilterType.php
rename to src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php
index c38be8320fb3de10748891175891329ad8b03363..ee10bc8b517135deac7303beea15fa7c00e2d11b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-namespace Wallabag\CoreBundle\Filter;
+namespace Wallabag\CoreBundle\Form\Type;
 
 use Doctrine\ORM\EntityRepository;
 use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface;
index 813f8a9610b42a5ccce4954006cc8a6961e06ff1..a8796fe4452d0fce1f55700c902430d9d18cdce5 100644 (file)
@@ -15,7 +15,7 @@ services:
             - { name: form.type }
 
     wallabag_core.filter.type.entry:
-        class: Wallabag\CoreBundle\Filter\EntryFilterType
+        class: Wallabag\CoreBundle\Form\Type\EntryFilterType
         arguments:
             - "@wallabag_core.entry_repository"
             - "@security.token_storage"
index d3f92926e846c89920075fdb31d08a773ffc7dfb..62f2964c0ccd77711543f2a42dcbfb6e28f3c7aa 100755 (executable)
@@ -564,7 +564,7 @@ img.preview {
   height: 100%;
   width: 100%;
   margin: 0;
-  margin-top: -30% !important; /* TODO: get rid of !important here; overridden by .messages selector */
+  margin-top: -30% !important;
   padding: 2em;
   display: none;
   border-left: 1px #EEE solid;
old mode 100755 (executable)
new mode 100644 (file)
index 1f0054a..3db0787
@@ -1,3 +1,3 @@
 # Baggy Theme
 
-theme created by Thomas LEBEAU alias Courgette http://thomaslebeau.fr/
\ No newline at end of file
+theme created by Thomas LEBEAU alias Courgette http://thomaslebeau.fr/
old mode 100755 (executable)
new mode 100644 (file)
index 534eea3..54e8a0e
@@ -2,4 +2,4 @@
 
 Theme created by Danilow (@modos189) Alexandr  http://modos189.ru/
 
-Used framework  http://materializecss.com/
\ No newline at end of file
+Used framework  http://materializecss.com/
diff --git a/src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php b/src/Wallabag/ImportBundle/Controller/WallabagV2Controller.php
new file mode 100644 (file)
index 0000000..2e6225f
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+namespace Wallabag\ImportBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Symfony\Component\HttpFoundation\Request;
+use Wallabag\ImportBundle\Form\Type\UploadImportType;
+
+class WallabagV2Controller extends Controller
+{
+    /**
+     * @Route("/wallabag-v2", name="import_wallabag_v2")
+     */
+    public function indexAction(Request $request)
+    {
+        $form = $this->createForm(UploadImportType::class);
+        $form->handleRequest($request);
+
+        $wallabag = $this->get('wallabag_import.wallabag_v2.import');
+
+        if ($form->isValid()) {
+            $file = $form->get('file')->getData();
+            $name = $this->getUser()->getId().'.json';
+
+            if (in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+                $res = $wallabag
+                    ->setUser($this->getUser())
+                    ->setFilepath($this->getParameter('wallabag_import.resource_dir').'/'.$name)
+                    ->import();
+
+                $message = 'Import failed, please try again.';
+
+                if (true === $res) {
+                    $summary = $wallabag->getSummary();
+                    $message = 'Import summary: '.$summary['imported'].' imported, '.$summary['skipped'].' already saved.';
+
+                    unlink($this->getParameter('wallabag_import.resource_dir').'/'.$name);
+                }
+
+                $this->get('session')->getFlashBag()->add(
+                    'notice',
+                    $message
+                );
+
+                return $this->redirect($this->generateUrl('homepage'));
+            } else {
+                $this->get('session')->getFlashBag()->add(
+                    'notice',
+                    'Error while processing import. Please verify your import file.'
+                );
+            }
+        }
+
+        return $this->render('WallabagImportBundle:WallabagV2:index.html.twig', [
+            'form' => $form->createView(),
+            'import' => $wallabag,
+        ]);
+    }
+}
index 0463a7399804d1b367cc251dbf65768b268ae3fc..22932238aeaa6c56f4982d90d5766f8e30f34ddc 100644 (file)
@@ -24,7 +24,6 @@ class PocketImport implements ImportInterface
     private $skippedEntries = 0;
     private $importedEntries = 0;
     protected $accessToken;
-    private $translator;
 
     public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, Config $craueConfig)
     {
@@ -178,9 +177,6 @@ class PocketImport implements ImportInterface
         $this->client = $client;
     }
 
-    /**
-     * @todo move that in a more global place
-     */
     private function assignTagsToEntry(Entry $entry, $tags)
     {
         foreach ($tags as $tag) {
index 6f8feaf36b2924c0bc2ea717103bfa59689ef5d7..0dac6203e6b0d0aacbd3354b1d075933afd8d13d 100644 (file)
@@ -11,12 +11,12 @@ use Wallabag\CoreBundle\Tools\Utils;
 
 class WallabagV1Import implements ImportInterface
 {
-    private $user;
-    private $em;
-    private $logger;
-    private $skippedEntries = 0;
-    private $importedEntries = 0;
-    private $filepath;
+    protected $user;
+    protected $em;
+    protected $logger;
+    protected $skippedEntries = 0;
+    protected $importedEntries = 0;
+    protected $filepath;
 
     public function __construct(EntityManager $em)
     {
@@ -72,13 +72,13 @@ class WallabagV1Import implements ImportInterface
     public function import()
     {
         if (!$this->user) {
-            $this->logger->error('WallabagV1Import: user is not defined');
+            $this->logger->error('WallabagImport: user is not defined');
 
             return false;
         }
 
         if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
-            $this->logger->error('WallabagV1Import: unable to read file', array('filepath' => $this->filepath));
+            $this->logger->error('WallabagImport: unable to read file', array('filepath' => $this->filepath));
 
             return false;
         }
@@ -120,7 +120,7 @@ class WallabagV1Import implements ImportInterface
     /**
      * @param $entries
      */
-    private function parseEntries($entries)
+    protected function parseEntries($entries)
     {
         $i = 1;
 
diff --git a/src/Wallabag/ImportBundle/Import/WallabagV2Import.php b/src/Wallabag/ImportBundle/Import/WallabagV2Import.php
new file mode 100644 (file)
index 0000000..979c671
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+
+namespace Wallabag\ImportBundle\Import;
+
+use Wallabag\CoreBundle\Entity\Entry;
+
+class WallabagV2Import extends WallabagV1Import implements ImportInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'wallabag v2';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getUrl()
+    {
+        return 'import_wallabag_v2';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDescription()
+    {
+        return 'This importer will import all your wallabag v2 articles. On the export sidebar, click on "JSON". You will have a "Unread articles.json" file.';
+    }
+
+    /**
+     * @param $entries
+     */
+    protected function parseEntries($entries)
+    {
+        $i = 1;
+
+        foreach ($entries as $importedEntry) {
+            $existingEntry = $this->em
+                ->getRepository('WallabagCoreBundle:Entry')
+                ->findByUrlAndUserId($importedEntry['url'], $this->user->getId());
+
+            if (false !== $existingEntry) {
+                ++$this->skippedEntries;
+                continue;
+            }
+
+            // @see ContentProxy->updateEntry
+            $entry = new Entry($this->user);
+            $entry->setUrl($importedEntry['url']);
+            $entry->setTitle($importedEntry['title']);
+            $entry->setArchived($importedEntry['is_archived']);
+            $entry->setStarred($importedEntry['is_starred']);
+            $entry->setContent($importedEntry['content']);
+            $entry->setReadingTime($importedEntry['reading_time']);
+            $entry->setDomainName($importedEntry['domain_name']);
+            $entry->setMimetype($importedEntry['mimetype']);
+            $entry->setLanguage($importedEntry['language']);
+            $entry->setPreviewPicture($importedEntry['preview_picture']);
+
+            $this->em->persist($entry);
+            ++$this->importedEntries;
+
+            // flush every 20 entries
+            if (($i % 20) === 0) {
+                $this->em->flush();
+            }
+            ++$i;
+        }
+
+        $this->em->flush();
+    }
+}
index dc53680802815be3b93dd04a9bab59bafbe38fd3..e0942b1ae1573eb453eec4fa33d6a6f166da32ed 100644 (file)
@@ -32,3 +32,12 @@ services:
             - [ setLogger, [ "@logger" ]]
         tags:
             -  { name: wallabag_import.import, alias: wallabag_v1 }
+
+    wallabag_import.wallabag_v2.import:
+        class: Wallabag\ImportBundle\Import\WallabagV2Import
+        arguments:
+            - "@doctrine.orm.entity_manager"
+        calls:
+            - [ setLogger, [ "@logger" ]]
+        tags:
+            -  { name: wallabag_import.import, alias: wallabag_v2 }
diff --git a/src/Wallabag/ImportBundle/Resources/views/WallabagV2/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/WallabagV2/index.html.twig
new file mode 100644 (file)
index 0000000..78fe67e
--- /dev/null
@@ -0,0 +1,2 @@
+{% extends "WallabagImportBundle:WallabagV1:index.html.twig" %}
+{% block title %}{% trans %}Import > Wallabag v2{% endtrans %}{% endblock %}
index 30009af4947915d59862145fa5fcc082258ba8e6..9f38fa8287ab043f83a5bd3a5bd7defad5fc46ab 100644 (file)
@@ -24,6 +24,6 @@ class ImportControllerTest extends WallabagCoreTestCase
         $crawler = $client->request('GET', '/import/');
 
         $this->assertEquals(200, $client->getResponse()->getStatusCode());
-        $this->assertEquals(2, $crawler->filter('blockquote')->count());
+        $this->assertEquals(3, $crawler->filter('blockquote')->count());
     }
 }
diff --git a/src/Wallabag/ImportBundle/Tests/Controller/WallabagV2ControllerTest.php b/src/Wallabag/ImportBundle/Tests/Controller/WallabagV2ControllerTest.php
new file mode 100644 (file)
index 0000000..a77c0f6
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+namespace Wallabag\ImportBundle\Tests\Controller;
+
+use Wallabag\CoreBundle\Tests\WallabagCoreTestCase;
+use Symfony\Component\HttpFoundation\File\UploadedFile;
+
+class WallabagV2ControllerTest extends WallabagCoreTestCase
+{
+    public function testImportWallabag()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/import/wallabag-v2');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+        $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
+        $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
+    }
+
+    public function testImportWallabagWithFile()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/import/wallabag-v2');
+        $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+        $file = new UploadedFile(__DIR__.'/../fixtures/wallabag-v2.json', 'wallabag-v2.json');
+
+        $data = array(
+            'upload_import_file[file]' => $file,
+        );
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(array('_text')));
+        $this->assertContains('Import summary', $alert[0]);
+    }
+
+    public function testImportWallabagWithEmptyFile()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/import/wallabag-v2');
+        $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+        $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
+
+        $data = array(
+            'upload_import_file[file]' => $file,
+        );
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(array('_text')));
+        $this->assertContains('Import failed, please try again', $alert[0]);
+    }
+}
index 90483480816d5c212d52f100dd4a75a69b4687c1..1cb5a233f7836dd528740e497ea6988c5bbc869f 100644 (file)
@@ -21,17 +21,17 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $pocket = new WallabagV1Import($this->em);
+        $wallabag = new WallabagV1Import($this->em);
 
         $this->logHandler = new TestHandler();
         $logger = new Logger('test', array($this->logHandler));
-        $pocket->setLogger($logger);
+        $wallabag->setLogger($logger);
 
         if (false === $unsetUser) {
-            $pocket->setUser($this->user);
+            $wallabag->setUser($this->user);
         }
 
-        return $pocket;
+        return $wallabag;
     }
 
     public function testInit()
@@ -77,7 +77,7 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
         $this->assertFalse($res);
 
         $records = $this->logHandler->getRecords();
-        $this->assertContains('WallabagV1Import: unable to read file', $records[0]['message']);
+        $this->assertContains('WallabagImport: unable to read file', $records[0]['message']);
         $this->assertEquals('ERROR', $records[0]['level_name']);
     }
 
@@ -91,7 +91,7 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
         $this->assertFalse($res);
 
         $records = $this->logHandler->getRecords();
-        $this->assertContains('WallabagV1Import: user is not defined', $records[0]['message']);
+        $this->assertContains('WallabagImport: user is not defined', $records[0]['message']);
         $this->assertEquals('ERROR', $records[0]['level_name']);
     }
 }
diff --git a/src/Wallabag/ImportBundle/Tests/Import/WallabagV2ImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/WallabagV2ImportTest.php
new file mode 100644 (file)
index 0000000..4ebe93b
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+
+namespace Wallabag\ImportBundle\Tests\Import;
+
+use Wallabag\ImportBundle\Import\WallabagV2Import;
+use Wallabag\UserBundle\Entity\User;
+use Monolog\Logger;
+use Monolog\Handler\TestHandler;
+
+class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
+{
+    protected $user;
+    protected $em;
+    protected $logHandler;
+
+    private function getWallabagV2Import($unsetUser = false)
+    {
+        $this->user = new User();
+
+        $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $wallabag = new WallabagV2Import($this->em);
+
+        $this->logHandler = new TestHandler();
+        $logger = new Logger('test', array($this->logHandler));
+        $wallabag->setLogger($logger);
+
+        if (false === $unsetUser) {
+            $wallabag->setUser($this->user);
+        }
+
+        return $wallabag;
+    }
+
+    public function testInit()
+    {
+        $wallabagV2Import = $this->getWallabagV2Import();
+
+        $this->assertEquals('wallabag v2', $wallabagV2Import->getName());
+        $this->assertNotEmpty($wallabagV2Import->getUrl());
+        $this->assertContains('This importer will import all your wallabag v2 articles.', $wallabagV2Import->getDescription());
+    }
+
+    public function testImport()
+    {
+        $wallabagV2Import = $this->getWallabagV2Import();
+        $wallabagV2Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2.json');
+
+        $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $entryRepo->expects($this->exactly(2))
+            ->method('findByUrlAndUserId')
+            ->will($this->onConsecutiveCalls(false, true, false));
+
+        $this->em
+            ->expects($this->any())
+            ->method('getRepository')
+            ->willReturn($entryRepo);
+
+        $res = $wallabagV2Import->import();
+
+        $this->assertTrue($res);
+        $this->assertEquals(['skipped' => 1, 'imported' => 1], $wallabagV2Import->getSummary());
+    }
+
+    public function testImportBadFile()
+    {
+        $wallabagV1Import = $this->getWallabagV2Import();
+        $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2.jsonx');
+
+        $res = $wallabagV1Import->import();
+
+        $this->assertFalse($res);
+
+        $records = $this->logHandler->getRecords();
+        $this->assertContains('WallabagImport: unable to read file', $records[0]['message']);
+        $this->assertEquals('ERROR', $records[0]['level_name']);
+    }
+
+    public function testImportUserNotDefined()
+    {
+        $wallabagV1Import = $this->getWallabagV2Import(true);
+        $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2.json');
+
+        $res = $wallabagV1Import->import();
+
+        $this->assertFalse($res);
+
+        $records = $this->logHandler->getRecords();
+        $this->assertContains('WallabagImport: user is not defined', $records[0]['message']);
+        $this->assertEquals('ERROR', $records[0]['level_name']);
+    }
+}
diff --git a/src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v2.json b/src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v2.json
new file mode 100644 (file)
index 0000000..49d782b
--- /dev/null
@@ -0,0 +1 @@
+[{"id":"23","title":"Site d'information fran\u00e7ais d'actualit\u00e9s ind\u00e9pendant et participatif en ligne | Mediapart","url":"https:\/\/www.mediapart.fr\/","is_archived":false,"is_starred":false,"content":"<div alt=\"li\">\u00c9dition <a href=\"https:\/\/blogs.mediapart.fr\/edition\/camedia-0\">CAM\u00e9dia<\/a>\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/edition\/camedia\/article\/180116\/deux-nouvelles-editions-pour-debattre-dans-le-club-sur-la-laicite-et-sur-la-democratie\">Deux nouvelles \u00e9ditions pour d\u00e9battre dans le club sur la la\u00efcit\u00e9 et sur la d\u00e9mocratie<\/a><\/h3>\n<p>18 janv. 2016 | Par <\/p>\n<p>CAM\u00e9dia apr\u00e8s un \u00e9change sur \u00ab\u00a0l'\u00e9thique du d\u00e9bat\u00a0\u00bb a lanc\u00e9 deux discussions , l'une sur le th\u00e8me de la la\u00efcit\u00e9, l'autre ( encore en cours) sur celui de la d\u00e9mocratie. Nous sommes heureux de pouvoir signaler la cr\u00e9ation de deux nouvelles \u00e9ditions participatives sur ces th\u00e8mes. Nous vous invitons \u00e0 les lire et \u00e0 participer \u00e0 leurs d\u00e9bats.<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/lucile-longre\/blog\/170116\/de-limportance-de-rever-eloge-du-merveilleux\">De l'importance de r\u00eaver, \u00e9loge du merveilleux<\/a><\/h3>\n<p>17 janv. 2016 | Par <\/p>\n<p>Je parlerai ici des r\u00eaves comme moteur de vie, de ces r\u00eaves qui vous rattachent et vous font esp\u00e9rer \u00e0 ce qu\u2019il y a de plus humain dans l\u2019homme, m\u00eame au milieu de la plus noire des d\u00e9tresses.<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/barbara-romagnan\/blog\/180116\/fins-dune-toute-puissance\">Fin(s) d'une toute-puissance<\/a><\/h3>\n<p>18 janv. 2016 | Par <\/p>\n<p>En ce d\u00e9but d\u2019ann\u00e9e, je recommande la lecture du dernier ouvrage de Guillaume Duval, La France ne sera jamais plus une grande puissance ? Tant mieux !<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/jean-pierre-thibaudat\/blog\/170116\/l-allier-departement-de-destruction-massive-du-tissu-culturel\">L\u2019Allier, d\u00e9partement de destruction massive du tissu culturel<\/a><\/h3>\n<p>18 janv. 2016 | Par <\/p>\n<p>Les temps sont durs pour les petites structures, les associations culturelles qui, de bourgades en villages, travaillent au c\u0153ur des r\u00e9gions. Leurs subventions sont souvent revues \u00e0 la baisse. Le d\u00e9partement de l\u2019Allier les a carr\u00e9ment supprim\u00e9es. Pour favoriser \u00ab l\u2019\u00e9v\u00e9nementiel \u00bb.<\/p>\n<\/div><div alt=\"li\">\u00c9dition <a href=\"https:\/\/blogs.mediapart.fr\/edition\/les-invites-de-mediapart\">Les invit\u00e9s de Mediapart<\/a>\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/edition\/les-invites-de-mediapart\/article\/180116\/la-democratie-deja-attaquee-par-la-cooperation-reglementaire-transatlantiqu\">La d\u00e9mocratie d\u00e9j\u00e0 attaqu\u00e9e par la coop\u00e9ration r\u00e9glementaire transatlantique<\/a><\/h3>\n<p>18 janv. 2016 | Par <\/p>\n<p>Lora Verheecke et David Lundy travaillent pour Corporate Europe Observatory, une ONG bas\u00e9e \u00e0 Bruxelles qui enqu\u00eate sur le pouvoir des lobbies des grandes entreprises sur la politique de l\u2019Union europ\u00e9enne. Ils r\u00e9v\u00e8lent que depuis 25 ans le projet de \u00ab coop\u00e9ration r\u00e9glementaire \u00bb men\u00e9 par l\u2019Union europ\u00e9enne et les \u00c9tats-Unis a \u00e9t\u00e9 domin\u00e9 par les grandes entreprises. ET que le TTIP cherche \u00e0 ent\u00e9riner ce projet.<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/jacqueline-derens\/blog\/180116\/2016-une-annee-test-pour-jacob-zuma-et-son-gouvernement\">2016, une ann\u00e9e test pour Jacob Zuma et son gouvernement<\/a><\/h3>\n<p>18 janv. 2016 | Par <\/p>\n<p>Les turbulences de l\u2019an pass\u00e9 ont toutes les chances de continuer \u00e0 troubler le climat politique et social de l\u2019Afrique du Sud en 2016. La situation exige des changements profonds dans la conduite des affaires du pays. Jacob Zuma tout en admettant la n\u00e9cessit\u00e9 de ces changements, est-il l\u2019homme de la situation ? Son gouvernement r\u00e9pondra-t-il aux attentes des citoyens sud-africains ?<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/marie-cosnay\/blog\/140116\/un-mal-fou-janvier-2016\">Un mal fou (janvier 2016)<\/a><\/h3>\n<p>14 janv. 2016 | Par <\/p>\n<p>J\u2019ai une fringale d\u2019aventure, d\u2019aventures \u00e0 venir. J\u2019ai la fringale de la fringale des aventures et soudain, rupture. Je n\u2019y arrive plus, tout est bloqu\u00e9, tout emp\u00each\u00e9. Faut dire que depuis un an environ, tout est devenu plus compliqu\u00e9. Ecrire va de moins en moins de soi.<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/jean-pierre-veran\/blog\/170116\/redoublement-le-changement-bas-bruit\">Redoublement : le changement \u00e0 bas bruit ?<\/a><\/h3>\n<p>17 janv. 2016 | Par <\/p>\n<p>S\u2019il est une caract\u00e9ristique de la forme scolaire fran\u00e7aise bien \u00e9tablie dans la culture des personnels, des \u00e9l\u00e8ves et des parents, c\u2019est bien le redoublement, cens\u00e9 sanctionner des r\u00e9sultats insuffisants pour envisager le passage dans la classe sup\u00e9rieure. Or, en ce domaine, l\u2019\u00e9volution est nette.<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/michel-de-pracontal\/blog\/160116\/samedi-sciences-196-des-chasseurs-de-mammouths-en-arctique-il-y-45-000-ans\">Samedi-sciences (196): des chasseurs de mammouths en Arctique il y a 45 000 ans<\/a><\/h3>\n<p>16 janv. 2016 | Par <a href=\"https:\/\/blogs.mediapart.fr\/michel-de-pracontal\" class=\"journalist\">Michel de Pracontal<\/a><\/p>\n<p>Les restes d\u2019un mammouth retrouv\u00e9s en Arctique sib\u00e9rien, dat\u00e9s de 45 000 ans, portent les traces de blessures inflig\u00e9es par des chasseurs humains. Les scientifiques pensaient jusqu\u2019ici que notre esp\u00e8ce ne s\u2019\u00e9tait pas aventur\u00e9e dans cette r\u00e9gion glaciale il y a plus de 30 000 ou 35 0000 ans. En r\u00e9alit\u00e9, des hommes ont r\u00e9ussi \u00e0 survivre en Arctique au moins 10 000 ans plus t\u00f4t que l\u2019on croyait.<\/p>\n<\/div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https:\/\/blogs.mediapart.fr\/alain-zolty\/blog\/140116\/de-la-democratie-du-citoyen-et-de-lethique\">De la d\u00e9mocratie, du citoyen et de l'\u00e9thique<\/a><\/h3>\n<p>14 janv. 2016 | Par <\/p>\n<p>Trois ouvrages sont parus au Seuil, qui font \u00e9tat de la n\u00e9cessit\u00e9 d\u2019int\u00e9grer le citoyen dans la gouvernance de la nation. Non pas \u00e0 titre consultatif mais dot\u00e9 d\u2019un pouvoir d\u00e9lib\u00e9ratif pour constituer une contre-force face aux clans politico-financiers qui dominent la vie publique.<\/p>\n<\/div>","mimetype":"text\/html","language":"fr","reading_time":3,"domain_name":"www.mediapart.fr","preview_picture":"https:\/\/www.mediapart.fr\/images\/social\/800\/mediapart.png","tags":[]},{"id":22,"title":"R\u00e9fugi\u00e9s: l'UE va cr\u00e9er 100\u00a0000\u00a0places d'accueil dans les Balkans","url":"http:\/\/www.liberation.fr\/planete\/2015\/10\/26\/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867","is_archived":false,"is_starred":false,"content":"<p>Pour un sommet sur les r\u00e9fugi\u00e9s qui devait se concentrer sur des <em>\u00abmesures op\u00e9rationnelles imm\u00e9diates\u00bb<\/em> dans les Balkans, la r\u00e9union, dimanche \u00e0 Bruxelles, de 11\u00a0chefs d\u2019Etat et de gouvernement, dont 8 Europ\u00e9ens, a \u00e9t\u00e9 agit\u00e9e. D\u00e8s leur arriv\u00e9e, Viktor\u00a0Orb\u00e1n (Hongrie) et\u00a0Al\u00e9xis Ts\u00edpras (Gr\u00e8ce) se sont jet\u00e9 des anath\u00e8mes. Le Premier ministre grec a d\u00e9nonc\u00e9 l\u2019attitude <em>\u00abnot in my backyard\u00bb<\/em> (pas de \u00e7a chez moi) de certains Etats europ\u00e9ens, alors que son pays est montr\u00e9 du doigt par d\u2019autres dirigeants, dont\u00a0Orb\u00e1n\u00a0: ils reprochent \u00e0 la Gr\u00e8ce de ne pas suffisamment contr\u00f4ler ses fronti\u00e8res avec la Turquie et ne pas montrer assez de z\u00e8le dans l\u2019enregistrement des demandeurs d\u2019asile.<\/p>\n<p>Le sommet, convoqu\u00e9 par la Commission europ\u00e9enne, sur suggestion de l\u2019Allemagne, aura au moins permis \u00e0 ces 11\u00a0Etats \u2013\u00a0Autriche, Bulgarie, Croatie, Allemagne, Gr\u00e8ce, Hongrie, Roumanie, Slov\u00e9nie c\u00f4t\u00e9 europ\u00e9en, et 3 pays \u00abnon UE\u00bb, Albanie, Mac\u00e9doine et Serbie\u00a0\u2013 de discuter ensemble.<\/p>\n<h3>400\u00a0policiers europ\u00e9ens en Slov\u00e9nie<\/h3>\n<p>L\u2019objectif, rappel\u00e9 par Angela Merkel, \u00e9tait de trouver une <em>\u00abr\u00e9ponse coordonn\u00e9e\u00bb<\/em> \u00e0 la crise des r\u00e9fugi\u00e9s. Quelques mesures ont \u00e9t\u00e9 annonc\u00e9es\u00a0: 100\u00a0000\u00a0places d\u2019accueil seront cr\u00e9\u00e9es, dont 50\u00a0000 en Gr\u00e8ce, et le reste le long de la route des Balkans.\u00a0400\u00a0officiers de police de pays europ\u00e9ens partiront en Slov\u00e9nie, actuellement submerg\u00e9e, pour aider au contr\u00f4le des fronti\u00e8res. Frontex, l\u2019agence europ\u00e9enne de surveillance des fronti\u00e8res, s\u2019impliquera aux fronti\u00e8res gr\u00e9co-mac\u00e9donienne et gr\u00e9co-albanaise pour des contr\u00f4les et identifications.<\/p>\n<p>Ce sommet est intervenu dans un contexte de fortes tensions, marqu\u00e9 par des fermetures de fronti\u00e8res bloquant les r\u00e9fugi\u00e9s dans des zones tampon. Ces obstacles ont \u00e9t\u00e9 partiellement lev\u00e9s ces derniers jours, les autorit\u00e9s tentant d\u2019organiser un \u00abcorridor\u00bb informel vers l\u2019Allemagne, qui pourtant durcit sa politique d\u2019accueil et souhaite d\u00e9sormais ralentir le flux. Mais la situation des r\u00e9fugi\u00e9s est catastrophique. L\u2019ONG Human Rights Watch craint que des r\u00e9fugi\u00e9s ne meurent dans les Balkans. Des groupes de centaines, voire de milliers de personnes, bloqu\u00e9s pr\u00e8s des postes-fronti\u00e8res, se retrouvent dans des conditions humanitaires intenables.<\/p>\n<p>Depuis mi-septembre, 250\u00a0000\u00a0personnes ont travers\u00e9 les Balkans. En une semaine, la Slov\u00e9nie a vu 60\u00a0000\u00a0r\u00e9fugi\u00e9s fouler le sol de son territoire. Dimanche, 15\u00a0000\u00a0personnes ont transit\u00e9 en Slov\u00e9nie.<\/p>\n<h3>Des zones tampon<\/h3>\n<p>L\u2019enjeu principal du sommet, aux yeux de nombreux Etats de l\u2019Union europ\u00e9enne, \u00e9tait aussi que les pays des Balkans <em>\u00abprennent leur part\u00bb<\/em> face \u00e0 la crise\u00a0: qu\u2019ils accueillent et enregistrent davantage de r\u00e9fugi\u00e9s. Ces Etats craignent que l\u2019Autriche ou l\u2019Allemagne ne ferment leurs fronti\u00e8res et fassent de leurs pays des <em>\u00abzones tampon\u00bb<\/em>, comme s\u2019en inqui\u00e9tait Boyko Borissov, Premier ministre bulgare.<\/p>\n<p><em>\u00ab\u00a0Aujourd\u2019hui, plusieurs Etats du nord de l\u2019Europe veulent que l\u2019on enregistre les migrants puis que l\u2019on d\u00e9termine leur \u00e9ligibilit\u00e9 au statut de r\u00e9fugi\u00e9,<\/em> explique Marc Pierini, du think tank Carnegie Europe. <em>La difficult\u00e9, c\u2019est que les gens sont en mouvement. Pour le faire, il faut se poser quelque part. La crainte des pays interm\u00e9diaires, donc ceux des Balkans, est qu\u2019on enregistre ces personnes sur leur territoire et qu\u2019ils soient contraints de rester sur leur sol. Donc les pays des Balkans ne sont pas d\u00e9sireux d\u2019accueillir ces r\u00e9fugi\u00e9s et ces derniers veulent avancer.\u00bb<\/em><\/p>\n<p>Le sommet a \u00e9labor\u00e9 quelques principes. L\u2019id\u00e9e g\u00e9n\u00e9rale est de rendre effective la \u00ablogique de hotspot\u00bb\u00a0: un enregistrement des demandeurs d\u2019asile \u00e0 leur point d\u2019entr\u00e9e dans l\u2019Union europ\u00e9enne, suivi de l\u2019expulsion de ceux qui ne correspondraient pas aux crit\u00e8res de la Convention de Gen\u00e8ve, et la r\u00e9partition des autres, via le m\u00e9canisme de relocalisation.<\/p>\n<p>Dans ce cadre, l\u2019enregistrement des demandeurs d\u2019asile est un \u00e9l\u00e9ment cl\u00e9. <em>\u00abPas d\u2019enregistrement, pas de droit\u00bb<\/em>, a pr\u00e9venu le pr\u00e9sident de la Commission europ\u00e9enne, Jean-Claude Juncker, dimanche soir. Les Etats ont tenu \u00e0 rappeler que les migrants qui refusent de demander l\u2019asile \u00e0 la fronti\u00e8re peuvent se voir refuser l\u2019entr\u00e9e dans un pays.<\/p>\n<p>Et les Etats <em>\u00abd\u00e9courageront les mouvements de r\u00e9fugi\u00e9s\u00bb<\/em> de fronti\u00e8re en fronti\u00e8re. La politique consistant \u00e0 laisser passer les migrants vers un autre pays est officiellement jug\u00e9e <em>\u00abinacceptable\u00bb<\/em>.<\/p>\n<h3>Se jeter dans la gueule du loup<\/h3>\n<p>Voil\u00e0 pour la th\u00e9orie. En pratique, la relocalisation ne devrait concerner que 160\u00a0000\u00a0r\u00e9fugi\u00e9s en deux\u00a0ans, alors que pr\u00e8s de 700\u00a0000\u00a0personnes sont arriv\u00e9es en Europe depuis le d\u00e9but de l\u2019ann\u00e9e. De plus, les Etats ne jouent pas le jeu. La semaine pass\u00e9e, seules 854\u00a0places de relocalisation avaient \u00e9t\u00e9 propos\u00e9es.<\/p>\n<p>Dans ce contexte, il est probable que les Etats des Balkans ne s\u2019impliqueront pas outre mesure dans les solutions propos\u00e9es, craignant de devoir \u00abgarder\u00bb les r\u00e9fugi\u00e9s alors que l\u2019Union europ\u00e9enne tarde \u00e0 mettre en \u0153uvre leur r\u00e9partition.<\/p>\n<p>Quant aux r\u00e9fugi\u00e9s, ils pr\u00e9f\u00e8rent traverser les fronti\u00e8res par eux-m\u00eames, plut\u00f4t que de se jeter dans ces \u00abhotspots\u00bb, consid\u00e9r\u00e9s comme la gueule du loup.<\/p>\n<a itemprop=\"name\" href=\"http:\/\/www.liberation.fr\/auteur\/15743-cedric-vallet\">C\u00e9dric Vallet<\/a>","mimetype":"text\/html","language":"fr","reading_time":4,"domain_name":"www.liberation.fr","preview_picture":"http:\/\/md1.libe.com\/photo\/820275-migrants-et-refugies-se-dirigent-vers-la-frontiere-entre-la-slovenie-et-l-autriche-le-23-octobre-201.jpg?modified_at=1445855324&amp;width=750","tags":[]}]
diff --git a/web/favicon.ico b/web/favicon.ico
new file mode 100644 (file)
index 0000000..0346558
Binary files /dev/null and b/web/favicon.ico differ