From 56ea1de99bff55ce4149ea8070eabf8183d6f4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Wed, 30 Sep 2015 11:43:25 +0200 Subject: first draft for json import, needed for wallabag v1 migration --- src/Wallabag/CoreBundle/Command/ImportCommand.php | 112 ++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/Wallabag/CoreBundle/Command/ImportCommand.php diff --git a/src/Wallabag/CoreBundle/Command/ImportCommand.php b/src/Wallabag/CoreBundle/Command/ImportCommand.php new file mode 100644 index 00000000..f27aeff7 --- /dev/null +++ b/src/Wallabag/CoreBundle/Command/ImportCommand.php @@ -0,0 +1,112 @@ +setName('import:json') + ->setDescription('Import entries from JSON file'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $now = new \DateTime(); + $output->writeln('Start : '.$now->format('d-m-Y G:i:s').' ---'); + + // Importing CSV on DB via Doctrine ORM + $this->import($input, $output); + + $now = new \DateTime(); + $output->writeln('End : '.$now->format('d-m-Y G:i:s').' ---'); + } + + protected function import(InputInterface $input, OutputInterface $output) + { + // Getting php array of data from CSV + $data = $this->get($input, $output); + + $em = $this->getContainer()->get('doctrine')->getManager(); + // Turning off doctrine default logs queries for saving memory + $em->getConnection()->getConfiguration()->setSQLLogger(null); + + // Define the size of record, the frequency for persisting the data and the current index of records + $size = count($data); + $batchSize = 20; + $i = 1; + + $progress = new ProgressBar($output, $size); + $progress->start(); + + $user = $em->getRepository('WallabagCoreBundle:User') + ->findOneById(1); + + foreach ($data as $object) { + $array = (array) $object; + $entry = $em->getRepository('WallabagCoreBundle:Entry') + ->findOneByUrl($array['url']); + + if (!is_object($entry)) { + $entry = new Entry($user); + $entry->setUrl($array['url']); + } + + $entry->setTitle($array['title']); + $entry->setArchived($array['is_read']); + $entry->setStarred($array['is_fav']); + $entry->setContent($array['content']); + $entry->setReadingTime(Utils::getReadingTime($array['content'])); + + $em->persist($entry); + + if (($i % $batchSize) === 0) { + $em->flush(); + $progress->advance($batchSize); + + $now = new \DateTime(); + $output->writeln(' of entries imported ... | '.$now->format('d-m-Y G:i:s')); + } + ++$i; + } + + $em->flush(); + $em->clear(); + $progress->finish(); + } + + protected function convert($filename) + { + if (!file_exists($filename) || !is_readable($filename)) { + return false; + } + + $header = null; + $data = array(); + + if (($handle = fopen($filename, 'r')) !== false) { + while (($row = fgets($handle)) !== false) { + $data = json_decode($row); + } + fclose($handle); + } + + return $data; + } + + protected function get(InputInterface $input, OutputInterface $output) + { + $fileName = 'web/uploads/import/import.json'; + $data = $this->convert($fileName); + + return $data; + } +} -- cgit v1.2.3 From a1bb1b3c2a0631ad41262ef92f6cce02c3d376bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Wed, 30 Sep 2015 14:22:38 +0200 Subject: userId is now set in parameters --- src/Wallabag/CoreBundle/Command/ImportCommand.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Wallabag/CoreBundle/Command/ImportCommand.php b/src/Wallabag/CoreBundle/Command/ImportCommand.php index f27aeff7..4a174202 100644 --- a/src/Wallabag/CoreBundle/Command/ImportCommand.php +++ b/src/Wallabag/CoreBundle/Command/ImportCommand.php @@ -3,6 +3,7 @@ namespace Wallabag\CoreBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Helper\ProgressBar; @@ -15,7 +16,12 @@ class ImportCommand extends ContainerAwareCommand { $this ->setName('import:json') - ->setDescription('Import entries from JSON file'); + ->setDescription('Import entries from JSON file') + ->addArgument( + 'userId', + InputArgument::REQUIRED, + 'user ID to populate' + ); } protected function execute(InputInterface $input, OutputInterface $output) @@ -32,6 +38,8 @@ class ImportCommand extends ContainerAwareCommand protected function import(InputInterface $input, OutputInterface $output) { + $userId = $input->getArgument('userId'); + // Getting php array of data from CSV $data = $this->get($input, $output); @@ -48,7 +56,7 @@ class ImportCommand extends ContainerAwareCommand $progress->start(); $user = $em->getRepository('WallabagCoreBundle:User') - ->findOneById(1); + ->findOneById($userId); foreach ($data as $object) { $array = (array) $object; -- cgit v1.2.3 From 8c3c77c1bd5c3763c127bfea52e908e77dc751b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Wed, 30 Sep 2015 15:10:46 +0200 Subject: create controller to launch import command --- src/Wallabag/CoreBundle/Command/ImportCommand.php | 19 +++++----- .../CoreBundle/Controller/ImportController.php | 40 ++++++++++++++++++++++ .../views/themes/material/layout.html.twig | 1 + 3 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/Wallabag/CoreBundle/Controller/ImportController.php diff --git a/src/Wallabag/CoreBundle/Command/ImportCommand.php b/src/Wallabag/CoreBundle/Command/ImportCommand.php index 4a174202..16c84229 100644 --- a/src/Wallabag/CoreBundle/Command/ImportCommand.php +++ b/src/Wallabag/CoreBundle/Command/ImportCommand.php @@ -3,6 +3,7 @@ namespace Wallabag\CoreBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Config\Definition\Exception\Exception; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -15,7 +16,7 @@ class ImportCommand extends ContainerAwareCommand protected function configure() { $this - ->setName('import:json') + ->setName('wallabag:import') ->setDescription('Import entries from JSON file') ->addArgument( 'userId', @@ -38,8 +39,6 @@ class ImportCommand extends ContainerAwareCommand protected function import(InputInterface $input, OutputInterface $output) { - $userId = $input->getArgument('userId'); - // Getting php array of data from CSV $data = $this->get($input, $output); @@ -52,12 +51,16 @@ class ImportCommand extends ContainerAwareCommand $batchSize = 20; $i = 1; + $user = $em->getRepository('WallabagCoreBundle:User') + ->findOneById($input->getArgument('userId')); + + if (!is_object($user)) { + throw new Exception('User not found'); + } + $progress = new ProgressBar($output, $size); $progress->start(); - $user = $em->getRepository('WallabagCoreBundle:User') - ->findOneById($userId); - foreach ($data as $object) { $array = (array) $object; $entry = $em->getRepository('WallabagCoreBundle:Entry') @@ -112,8 +115,8 @@ class ImportCommand extends ContainerAwareCommand protected function get(InputInterface $input, OutputInterface $output) { - $fileName = 'web/uploads/import/import.json'; - $data = $this->convert($fileName); + $filename = __DIR__.'/../../../../web/uploads/import/'.$input->getArgument('userId').'.json'; + $data = $this->convert($filename); return $data; } diff --git a/src/Wallabag/CoreBundle/Controller/ImportController.php b/src/Wallabag/CoreBundle/Controller/ImportController.php new file mode 100644 index 00000000..53211eec --- /dev/null +++ b/src/Wallabag/CoreBundle/Controller/ImportController.php @@ -0,0 +1,40 @@ +setContainer($this->container); + $input = new ArrayInput(array('userId' => $this->getUser()->getId())); + $return = $command->run($input, new NullOutput()); + + if ($return == 0) { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Import successful' + ); + } else { + $this->get('session')->getFlashBag()->add( + 'warning', + 'Import failed' + ); + } + + return $this->redirect('/'); + } +} diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig index f426e25b..6b8d7adf 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig @@ -45,6 +45,7 @@
  • {% trans %}all{% endtrans %}
  • {% trans %}tags{% endtrans %}
  • {% trans %}config{% endtrans %}
  • +
  • {% trans %}import{% endtrans %}
  • {% trans %}howto{% endtrans %}
  • {% trans %}logout{% endtrans %}
  • -- cgit v1.2.3 From d275bdf4d36f90ff61f1e6a714c9ef64d210596f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Thu, 22 Oct 2015 16:57:56 +0200 Subject: form to upload file --- app/config/config.yml | 2 + src/Wallabag/CoreBundle/Command/ImportCommand.php | 3 +- .../CoreBundle/Controller/ImportController.php | 56 +++++++++++++++------- .../DependencyInjection/Configuration.php | 13 +++++ .../DependencyInjection/WallabagCoreExtension.php | 1 + .../CoreBundle/Form/Type/UploadImportType.php | 29 +++++++++++ .../views/themes/material/Import/index.html.twig | 23 +++++++++ 7 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 src/Wallabag/CoreBundle/Form/Type/UploadImportType.php create mode 100644 src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig diff --git a/app/config/config.yml b/app/config/config.yml index 8403a458..421b2db5 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -30,6 +30,8 @@ wallabag_core: en: 'English' fr: 'Français' de: 'Deutsch' + import: + allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] # Twig Configuration twig: diff --git a/src/Wallabag/CoreBundle/Command/ImportCommand.php b/src/Wallabag/CoreBundle/Command/ImportCommand.php index 16c84229..6be6f5e1 100644 --- a/src/Wallabag/CoreBundle/Command/ImportCommand.php +++ b/src/Wallabag/CoreBundle/Command/ImportCommand.php @@ -51,7 +51,7 @@ class ImportCommand extends ContainerAwareCommand $batchSize = 20; $i = 1; - $user = $em->getRepository('WallabagCoreBundle:User') + $user = $em->getRepository('WallabagUserBundle:User') ->findOneById($input->getArgument('userId')); if (!is_object($user)) { @@ -116,6 +116,7 @@ class ImportCommand extends ContainerAwareCommand protected function get(InputInterface $input, OutputInterface $output) { $filename = __DIR__.'/../../../../web/uploads/import/'.$input->getArgument('userId').'.json'; + $data = $this->convert($filename); return $data; diff --git a/src/Wallabag/CoreBundle/Controller/ImportController.php b/src/Wallabag/CoreBundle/Controller/ImportController.php index 53211eec..33087710 100644 --- a/src/Wallabag/CoreBundle/Controller/ImportController.php +++ b/src/Wallabag/CoreBundle/Controller/ImportController.php @@ -8,6 +8,7 @@ use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\HttpFoundation\Request; use Wallabag\CoreBundle\Command\ImportCommand; +use Wallabag\CoreBundle\Form\Type\UploadImportType; class ImportController extends Controller { @@ -18,23 +19,46 @@ class ImportController extends Controller */ public function importAction(Request $request) { - $command = new ImportCommand(); - $command->setContainer($this->container); - $input = new ArrayInput(array('userId' => $this->getUser()->getId())); - $return = $command->run($input, new NullOutput()); - - if ($return == 0) { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Import successful' - ); - } else { - $this->get('session')->getFlashBag()->add( - 'warning', - 'Import failed' - ); + $importForm = $this->createForm(new UploadImportType()); + $importForm->handleRequest($request); + $user = $this->getUser(); + $importConfig = $this->container->getParameter('wallabag_core.import'); + + if ($importForm->isValid()) { + $file = $importForm->get('file')->getData(); + $name = $user->getId().'.json'; + $dir = __DIR__.'/../../../../web/uploads/import'; + + if (in_array($file->getMimeType(), $importConfig['allow_mimetypes']) && $file->move($dir, $name)) { + $command = new ImportCommand(); + $command->setContainer($this->container); + $input = new ArrayInput(array('userId' => $user->getId())); + $return = $command->run($input, new NullOutput()); + + if ($return == 0) { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Import successful' + ); + } else { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Import failed' + ); + } + + return $this->redirect('/'); + } else { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Error while processing import. Please verify your import file.' + ); + } } - return $this->redirect('/'); + return $this->render('WallabagCoreBundle:Import:index.html.twig', array( + 'form' => array( + 'import' => $importForm->createView(), ), + )); } } diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php index 32acd1f1..fb1941b8 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php @@ -4,6 +4,7 @@ namespace Wallabag\CoreBundle\DependencyInjection; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; class Configuration implements ConfigurationInterface { @@ -17,9 +18,21 @@ class Configuration implements ConfigurationInterface ->arrayNode('languages') ->prototype('scalar')->end() ->end() + ->arrayNode('import') + ->append($this->getAllowMimetypes()) + ->end() ->end() ; return $treeBuilder; } + + private function getAllowMimetypes() + { + $node = new ArrayNodeDefinition('allow_mimetypes'); + + $node->prototype('scalar')->end(); + + return $node; + } } diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php index 330cc957..e2a3ad55 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php @@ -14,6 +14,7 @@ class WallabagCoreExtension extends Extension $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); $container->setParameter('wallabag_core.languages', $config['languages']); + $container->setParameter('wallabag_core.import', $config['import']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Wallabag/CoreBundle/Form/Type/UploadImportType.php b/src/Wallabag/CoreBundle/Form/Type/UploadImportType.php new file mode 100644 index 00000000..b9a9c465 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/UploadImportType.php @@ -0,0 +1,29 @@ +add('file', 'file') + ->add('save', 'submit') + ; + } + + public function getDefaultOptions(array $options) + { + return array( + 'csrf_protection' => false, + ); + } + + public function getName() + { + return 'upload_import_file'; + } +} diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig new file mode 100644 index 00000000..2c8c158d --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig @@ -0,0 +1,23 @@ +{% extends "WallabagCoreBundle::layout.html.twig" %} + +{% block title %}{% trans %}import{% endtrans %}{% endblock %} + +{% block content %} + +
    +
    + {{ form_errors(form.import) }} +
    +
    + {{ form_errors(form.import.file) }} + {{ form_widget(form.import.file) }} + +
    +
    + + +
    +
    +{% endblock %} -- cgit v1.2.3 From 10b40f85d664da2b3ebcfd24d6e7145c9cd90d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Fri, 23 Oct 2015 10:14:22 +0200 Subject: add docs for Import feature --- docs/en/index.rst | 1 + docs/en/user/import.rst | 39 +++++++++++++++++++++ docs/img/user/export_wllbg_1.png | Bin 0 -> 10954 bytes docs/img/user/import_wllbg.png | Bin 0 -> 11803 bytes .../views/themes/material/Import/index.html.twig | 33 ++++++++++------- 5 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 docs/en/user/import.rst create mode 100644 docs/img/user/export_wllbg_1.png create mode 100644 docs/img/user/import_wllbg.png diff --git a/docs/en/index.rst b/docs/en/index.rst index 6ccfd44c..8cb1b479 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -24,6 +24,7 @@ The main documentation for the site is organized into a couple sections: user/login user/configuration user/first_article + user/import user/organize user/filters diff --git a/docs/en/user/import.rst b/docs/en/user/import.rst new file mode 100644 index 00000000..d326b06e --- /dev/null +++ b/docs/en/user/import.rst @@ -0,0 +1,39 @@ +Migrate to wallabag +=================== + +From wallabag 1.x +----------------- + +Export your data from your wallabag 1.x +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On your config page, click on ``JSON export`` in the ``Export your wallabag data`` section. + +.. image:: ../../img/user/export_wllbg_1.png + :alt: Export from wallabag 1.x + :align: center + +You will have a ``wallabag-export-1-1970-01-01.json`` file. + +Import your data into wallabag 2.x +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Click on ``Import`` link in the menu, select your export file on your computer and import it. + +.. image:: ../../img/user/import_wllbg.png + :alt: Import from wallabag 1.x + :align: center + +All your wallabag 1.x articles will be imported. + +From Pocket +----------- + +From Instapaper +--------------- + +From Readability +---------------- + +From HTML or JSON file +---------------------- diff --git a/docs/img/user/export_wllbg_1.png b/docs/img/user/export_wllbg_1.png new file mode 100644 index 00000000..f9d24517 Binary files /dev/null and b/docs/img/user/export_wllbg_1.png differ diff --git a/docs/img/user/import_wllbg.png b/docs/img/user/import_wllbg.png new file mode 100644 index 00000000..6eec07e4 Binary files /dev/null and b/docs/img/user/import_wllbg.png differ diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig index 2c8c158d..47004144 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig @@ -3,21 +3,28 @@ {% block title %}{% trans %}import{% endtrans %}{% endblock %} {% block content %} - -
    -
    - {{ form_errors(form.import) }} +
    +
    +
    -
    - {{ form_errors(form.import.file) }} - {{ form_widget(form.import.file) }} - +
    + + {{ form_errors(form.import) }} +
    +
    +

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    + {{ form_errors(form.import.file) }} + {{ form_widget(form.import.file) }} +
    +
    + + +
    - - - +
    +
    {% endblock %} -- cgit v1.2.3 From 1f4408de9ed08f3b0fda45a93f1585c80feeb21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Tue, 20 Oct 2015 13:58:13 +0200 Subject: 1st draft for Pocket import via API --- app/AppKernel.php | 1 + app/config/parameters.yml.dist | 3 + app/config/routing.yml | 5 + composer.json | 3 +- composer.lock | 66 +++++----- src/Wallabag/CoreBundle/Tools/Utils.php | 11 +- .../ImportBundle/Controller/PocketController.php | 139 +++++++++++++++++++++ .../Resources/views/Pocket/index.html.twig | 16 +++ src/Wallabag/ImportBundle/WallabagImportBundle.php | 9 ++ 9 files changed, 219 insertions(+), 34 deletions(-) create mode 100644 src/Wallabag/ImportBundle/Controller/PocketController.php create mode 100644 src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig create mode 100644 src/Wallabag/ImportBundle/WallabagImportBundle.php diff --git a/app/AppKernel.php b/app/AppKernel.php index 85edc14a..93b0201a 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -31,6 +31,7 @@ class AppKernel extends Kernel new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), new Scheb\TwoFactorBundle\SchebTwoFactorBundle(), new KPhoen\RulerZBundle\KPhoenRulerZBundle(), + new Wallabag\ImportBundle\WallabagImportBundle(), ); if (in_array($this->getEnvironment(), array('dev', 'test'))) { diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 149179c2..c0d57aa1 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -60,3 +60,6 @@ parameters: language: en from_email: no-reply@wallabag.org rss_limit: 50 + + # pocket import + pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 diff --git a/app/config/routing.yml b/app/config/routing.yml index 0f7b61fb..91a5705f 100644 --- a/app/config/routing.yml +++ b/app/config/routing.yml @@ -1,3 +1,8 @@ +wallabag_import: + resource: "@WallabagImportBundle/Controller/" + type: annotation + prefix: / + wallabag_api: resource: "@WallabagApiBundle/Resources/config/routing.yml" prefix: / diff --git a/composer.json b/composer.json index bf519faf..0ba42a3e 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,8 @@ "scheb/two-factor-bundle": "~1.4.0", "grandt/phpepub": "~4.0", "wallabag/php-mobi": "~1.0.0", - "kphoen/rulerz-bundle": "~0.10" + "kphoen/rulerz-bundle": "~0.10", + "guzzlehttp/guzzle": "^5.2.0" }, "require-dev": { "doctrine/doctrine-fixtures-bundle": "~2.2.0", diff --git a/composer.lock b/composer.lock index aee96198..076dfcac 100644 --- a/composer.lock +++ b/composer.lock @@ -117,16 +117,16 @@ }, { "name": "doctrine/cache", - "version": "v1.5.4", + "version": "v1.5.2", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136" + "reference": "47c7128262da274f590ae6f86eb137a7a64e82af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/47cdc76ceb95cc591d9c79a36dc3794975b5d136", - "reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136", + "url": "https://api.github.com/repos/doctrine/cache/zipball/47c7128262da274f590ae6f86eb137a7a64e82af", + "reference": "47c7128262da274f590ae6f86eb137a7a64e82af", "shasum": "" }, "require": { @@ -183,7 +183,7 @@ "cache", "caching" ], - "time": "2015-12-19 05:03:47" + "time": "2015-12-03 10:50:37" }, { "name": "doctrine/collections", @@ -981,17 +981,17 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "1.7.6", + "version": "1.7.4", "target-dir": "FOS/RestBundle", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "f95b2f141748e9a5e2ddae833f60c38417aee8c3" + "reference": "64ba918b1eb47acb5aa7fef1ce95623235b53775" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/f95b2f141748e9a5e2ddae833f60c38417aee8c3", - "reference": "f95b2f141748e9a5e2ddae833f60c38417aee8c3", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/64ba918b1eb47acb5aa7fef1ce95623235b53775", + "reference": "64ba918b1eb47acb5aa7fef1ce95623235b53775", "shasum": "" }, "require": { @@ -1063,7 +1063,7 @@ "keywords": [ "rest" ], - "time": "2015-12-20 13:45:30" + "time": "2015-12-05 14:55:07" }, { "name": "friendsofsymfony/user-bundle", @@ -2313,16 +2313,16 @@ }, { "name": "j0k3r/graby", - "version": "1.0.8", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/j0k3r/graby.git", - "reference": "bf152ccc6629bdd63b1e5e8b297c2912516b5f1e" + "reference": "c9f5543fad60dc4efd12195733f96bb4fdb0e6e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/j0k3r/graby/zipball/bf152ccc6629bdd63b1e5e8b297c2912516b5f1e", - "reference": "bf152ccc6629bdd63b1e5e8b297c2912516b5f1e", + "url": "https://api.github.com/repos/j0k3r/graby/zipball/c9f5543fad60dc4efd12195733f96bb4fdb0e6e0", + "reference": "c9f5543fad60dc4efd12195733f96bb4fdb0e6e0", "shasum": "" }, "require": { @@ -2365,20 +2365,20 @@ } ], "description": "Graby helps you extract article content from web pages", - "time": "2015-12-24 08:28:38" + "time": "2015-12-02 13:22:19" }, { "name": "j0k3r/graby-site-config", - "version": "1.0.11", + "version": "1.0.9", "source": { "type": "git", "url": "https://github.com/j0k3r/graby-site-config.git", - "reference": "ac198f308beabccc97bbd35ed0daeaac63fbf1e3" + "reference": "7666fed2a2cd211ef366f6fed9ccddd8e0b9e623" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/ac198f308beabccc97bbd35ed0daeaac63fbf1e3", - "reference": "ac198f308beabccc97bbd35ed0daeaac63fbf1e3", + "url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/7666fed2a2cd211ef366f6fed9ccddd8e0b9e623", + "reference": "7666fed2a2cd211ef366f6fed9ccddd8e0b9e623", "shasum": "" }, "require": { @@ -2401,7 +2401,7 @@ } ], "description": "Graby site config files", - "time": "2015-12-23 22:52:15" + "time": "2015-12-03 19:49:20" }, { "name": "j0k3r/php-readability", @@ -3138,7 +3138,9 @@ "authors": [ { "name": "S.C. Chen", - "email": "me578022@gmail.com" + "email": "me578022@gmail.com", + "homepage": "http://simplehtmldom.sourceforge.net/", + "role": "Lead Developer" } ], "description": "Composer package that gives you access to and (unlike all the others at this time) autoloads S.C. Chen's PHP Simple HTML DOM Parser Library", @@ -3765,16 +3767,16 @@ }, { "name": "scheb/two-factor-bundle", - "version": "v1.4.7", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/scheb/two-factor-bundle.git", - "reference": "ef6830dbbf62b22efd335db8f64bf0f51d4284a2" + "reference": "b0da3a85b181237c3bebde88c99b18745313360b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/two-factor-bundle/zipball/ef6830dbbf62b22efd335db8f64bf0f51d4284a2", - "reference": "ef6830dbbf62b22efd335db8f64bf0f51d4284a2", + "url": "https://api.github.com/repos/scheb/two-factor-bundle/zipball/b0da3a85b181237c3bebde88c99b18745313360b", + "reference": "b0da3a85b181237c3bebde88c99b18745313360b", "shasum": "" }, "require": { @@ -3810,7 +3812,7 @@ "two-factor", "two-step" ], - "time": "2015-08-25 19:58:00" + "time": "2015-11-15 13:31:23" }, { "name": "sensio/distribution-bundle", @@ -5437,16 +5439,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.21", + "version": "4.8.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ea76b17bced0500a28098626b84eda12dbcf119c" + "reference": "7438c43bc2bbb2febe1723eb595b1c49283a26ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c", - "reference": "ea76b17bced0500a28098626b84eda12dbcf119c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7438c43bc2bbb2febe1723eb595b1c49283a26ad", + "reference": "7438c43bc2bbb2febe1723eb595b1c49283a26ad", "shasum": "" }, "require": { @@ -5455,7 +5457,7 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "php": ">=5.3.3", + "php": "~5.3.3|~5.4|~5.5|~5.6", "phpspec/prophecy": "^1.3.1", "phpunit/php-code-coverage": "~2.1", "phpunit/php-file-iterator": "~1.4", @@ -5505,7 +5507,7 @@ "testing", "xunit" ], - "time": "2015-12-12 07:45:58" + "time": "2015-12-10 07:48:52" }, { "name": "phpunit/phpunit-mock-objects", diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php index a16baca9..b146d98b 100644 --- a/src/Wallabag/CoreBundle/Tools/Utils.php +++ b/src/Wallabag/CoreBundle/Tools/Utils.php @@ -26,6 +26,15 @@ class Utils return str_replace(array('+', '/'), '', $token); } + /** + * @param $words + * @return float + */ + public static function convertWordsToMinutes($words) + { + return floor($words / 200); + } + /** * For a given text, we calculate reading time for an article * based on 200 words per minute. @@ -36,6 +45,6 @@ class Utils */ public static function getReadingTime($text) { - return floor(str_word_count(strip_tags($text)) / 200); + return self::convertWordsToMinutes(str_word_count(strip_tags($text))); } } diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php new file mode 100644 index 00000000..ffd0c9ab --- /dev/null +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -0,0 +1,139 @@ +render('WallabagImportBundle:Pocket:index.html.twig', array()); + } + + /** + * Create a new Client. + * + * @return Client + */ + private function createClient() + { + return new Client([ + 'defaults' => [ + 'headers' => [ + 'content-type' => 'application/json', + 'X-Accept' => 'application/json', + ], + ], + ]); + } + + /** + * @Route("/auth-pocket", name="authpocket") + */ + public function authAction() + { + $client = $this->createClient(); + $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', + [ + 'body' => json_encode([ + 'consumer_key' => $this->container->getParameter('pocket_consumer_key'), + 'redirect_uri' => $this->generateUrl('import', array(), true), + ]), + ] + ); + + $response = $client->send($request); + $values = $response->json(); + $code = $values['code']; + + // store code in session for callback method + $session = $this->get('session'); + $session->set('pocketCode', $code); + + $url = 'https://getpocket.com/auth/authorize?request_token='.$code.'&redirect_uri='.$this->generateUrl('callbackpocket', array(), true); + + return $this->redirect($url, 301); + } + + /** + * @Route("/callback-pocket", name="callbackpocket") + */ + public function callbackAction() + { + $client = $this->createClient(); + + $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', + [ + 'body' => json_encode([ + 'consumer_key' => $this->container->getParameter('pocket_consumer_key'), + 'code' => $this->get('session')->get('pocketCode'), + ]), + ] + ); + + $response = $client->send($request); + $values = $response->json(); + $accessToken = $values['access_token']; + + $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', + [ + 'body' => json_encode([ + 'consumer_key' => $this->container->getParameter('pocket_consumer_key'), + 'access_token' => $accessToken, + 'detailType' => 'complete', + ]), + ] + ); + + $response = $client->send($request); + $entries = $response->json(); + + $this->parsePocketEntries($entries['list']); + + $this->get('session')->getFlashBag()->add( + 'notice', + count($entries['list']).' entries imported' + ); + + return $this->redirect($this->generateUrl('homepage')); + } + + /** + * @param $entries + */ + private function parsePocketEntries($entries) + { + $em = $this->getDoctrine()->getManager(); + + foreach ($entries as $entry) { + $newEntry = new Entry($this->getUser()); + $newEntry->setUrl($entry['given_url']); + $newEntry->setTitle(isset($entry['resolved_title']) ? $entry['resolved_title'] : (isset($entry['given_title']) ? $entry['given_title'] : 'Untitled')); + + if (isset($entry['excerpt'])) { + $newEntry->setContent($entry['excerpt']); + } + + if (isset($entry['has_image']) && $entry['has_image'] > 0) { + $newEntry->setPreviewPicture($entry['image']['src']); + } + + if (isset($entry['word_count'])) { + $newEntry->setReadingTime(Utils::convertWordsToMinutes($entry['word_count'])); + } + + $em->persist($newEntry); + } + + $em->flush(); + } +} diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig new file mode 100644 index 00000000..d47dd8d5 --- /dev/null +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -0,0 +1,16 @@ +{% extends "WallabagCoreBundle::layout.html.twig" %} +{% block title %}{% trans %}import{% endtrans %}{% endblock %} + +{% block content %} + +
    +
    +
    + {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %} +
    + +
    +
    +
    +
    +{% endblock %} diff --git a/src/Wallabag/ImportBundle/WallabagImportBundle.php b/src/Wallabag/ImportBundle/WallabagImportBundle.php new file mode 100644 index 00000000..d00f2fe9 --- /dev/null +++ b/src/Wallabag/ImportBundle/WallabagImportBundle.php @@ -0,0 +1,9 @@ + Date: Fri, 23 Oct 2015 14:01:27 +0200 Subject: refactor pocket import --- src/Wallabag/CoreBundle/Tools/Utils.php | 1 + .../ImportBundle/Controller/PocketController.php | 112 ++--------------- .../DependencyInjection/Configuration.php | 17 +++ .../WallabagImportExtension.php | 25 ++++ .../ImportBundle/Import/ImportInterface.php | 10 ++ src/Wallabag/ImportBundle/Import/PocketImport.php | 134 +++++++++++++++++++++ .../ImportBundle/Resources/config/services.yml | 8 ++ 7 files changed, 202 insertions(+), 105 deletions(-) create mode 100644 src/Wallabag/ImportBundle/DependencyInjection/Configuration.php create mode 100644 src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php create mode 100644 src/Wallabag/ImportBundle/Import/ImportInterface.php create mode 100644 src/Wallabag/ImportBundle/Import/PocketImport.php create mode 100644 src/Wallabag/ImportBundle/Resources/config/services.yml diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php index b146d98b..b501ce65 100644 --- a/src/Wallabag/CoreBundle/Tools/Utils.php +++ b/src/Wallabag/CoreBundle/Tools/Utils.php @@ -28,6 +28,7 @@ class Utils /** * @param $words + * * @return float */ public static function convertWordsToMinutes($words) diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index ffd0c9ab..76d8417b 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -4,10 +4,7 @@ namespace Wallabag\ImportBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; -use Symfony\Component\HttpFoundation\Request; -use GuzzleHttp\Client; -use Wallabag\CoreBundle\Entity\Entry; -use Wallabag\CoreBundle\Tools\Utils; +use Wallabag\ImportBundle\Import\PocketImport; class PocketController extends Controller { @@ -19,49 +16,15 @@ class PocketController extends Controller return $this->render('WallabagImportBundle:Pocket:index.html.twig', array()); } - /** - * Create a new Client. - * - * @return Client - */ - private function createClient() - { - return new Client([ - 'defaults' => [ - 'headers' => [ - 'content-type' => 'application/json', - 'X-Accept' => 'application/json', - ], - ], - ]); - } - /** * @Route("/auth-pocket", name="authpocket") */ public function authAction() { - $client = $this->createClient(); - $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', - [ - 'body' => json_encode([ - 'consumer_key' => $this->container->getParameter('pocket_consumer_key'), - 'redirect_uri' => $this->generateUrl('import', array(), true), - ]), - ] - ); - - $response = $client->send($request); - $values = $response->json(); - $code = $values['code']; - - // store code in session for callback method - $session = $this->get('session'); - $session->set('pocketCode', $code); + $pocket = new PocketImport($this->get('security.token_storage'), $this->get('session'), $this->getDoctrine()->getManager(), $this->container->getParameter('pocket_consumer_key')); + $authUrl = $pocket->oAuthRequest($this->generateUrl('import', array(), true), $this->generateUrl('callbackpocket', array(), true)); - $url = 'https://getpocket.com/auth/authorize?request_token='.$code.'&redirect_uri='.$this->generateUrl('callbackpocket', array(), true); - - return $this->redirect($url, 301); + return $this->redirect($authUrl, 301); } /** @@ -69,71 +32,10 @@ class PocketController extends Controller */ public function callbackAction() { - $client = $this->createClient(); - - $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', - [ - 'body' => json_encode([ - 'consumer_key' => $this->container->getParameter('pocket_consumer_key'), - 'code' => $this->get('session')->get('pocketCode'), - ]), - ] - ); - - $response = $client->send($request); - $values = $response->json(); - $accessToken = $values['access_token']; - - $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', - [ - 'body' => json_encode([ - 'consumer_key' => $this->container->getParameter('pocket_consumer_key'), - 'access_token' => $accessToken, - 'detailType' => 'complete', - ]), - ] - ); - - $response = $client->send($request); - $entries = $response->json(); - - $this->parsePocketEntries($entries['list']); - - $this->get('session')->getFlashBag()->add( - 'notice', - count($entries['list']).' entries imported' - ); + $pocket = new PocketImport($this->get('security.token_storage'), $this->get('session'), $this->getDoctrine()->getManager(), $this->container->getParameter('pocket_consumer_key')); + $accessToken = $pocket->oAuthAuthorize(); + $pocket->import($accessToken); return $this->redirect($this->generateUrl('homepage')); } - - /** - * @param $entries - */ - private function parsePocketEntries($entries) - { - $em = $this->getDoctrine()->getManager(); - - foreach ($entries as $entry) { - $newEntry = new Entry($this->getUser()); - $newEntry->setUrl($entry['given_url']); - $newEntry->setTitle(isset($entry['resolved_title']) ? $entry['resolved_title'] : (isset($entry['given_title']) ? $entry['given_title'] : 'Untitled')); - - if (isset($entry['excerpt'])) { - $newEntry->setContent($entry['excerpt']); - } - - if (isset($entry['has_image']) && $entry['has_image'] > 0) { - $newEntry->setPreviewPicture($entry['image']['src']); - } - - if (isset($entry['word_count'])) { - $newEntry->setReadingTime(Utils::convertWordsToMinutes($entry['word_count'])); - } - - $em->persist($newEntry); - } - - $em->flush(); - } } diff --git a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php new file mode 100644 index 00000000..bacaff31 --- /dev/null +++ b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php @@ -0,0 +1,17 @@ +root('wallabag_import'); + + return $treeBuilder; + } +} diff --git a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php new file mode 100644 index 00000000..4efcaace --- /dev/null +++ b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php @@ -0,0 +1,25 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } + + public function getAlias() + { + return 'wallabag_import'; + } +} diff --git a/src/Wallabag/ImportBundle/Import/ImportInterface.php b/src/Wallabag/ImportBundle/Import/ImportInterface.php new file mode 100644 index 00000000..88de3fa8 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/ImportInterface.php @@ -0,0 +1,10 @@ +user = $tokenStorage->getToken()->getUser(); + $this->session = $session; + $this->em = $em; + $this->consumerKey = $consumerKey; + } + + /** + * Create a new Client. + * + * @return Client + */ + private function createClient() + { + return new Client([ + 'defaults' => [ + 'headers' => [ + 'content-type' => 'application/json', + 'X-Accept' => 'application/json', + ], + ], + ]); + } + + /** + * @param $entries + */ + private function parsePocketEntries($entries) + { + foreach ($entries as $entry) { + $newEntry = new Entry($this->user); + $newEntry->setUrl($entry['given_url']); + $newEntry->setTitle(isset($entry['resolved_title']) ? $entry['resolved_title'] : (isset($entry['given_title']) ? $entry['given_title'] : 'Untitled')); + + if (isset($entry['excerpt'])) { + $newEntry->setContent($entry['excerpt']); + } + + if (isset($entry['has_image']) && $entry['has_image'] > 0) { + $newEntry->setPreviewPicture($entry['image']['src']); + } + + if (isset($entry['word_count'])) { + $newEntry->setReadingTime(Utils::convertWordsToMinutes($entry['word_count'])); + } + + $this->em->persist($newEntry); + } + + $this->em->flush(); + } + + public function oAuthRequest($redirectUri, $callbackUri) + { + $client = $this->createClient(); + $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', + [ + 'body' => json_encode([ + 'consumer_key' => $this->consumerKey, + 'redirect_uri' => $redirectUri, + ]), + ] + ); + + $response = $client->send($request); + $values = $response->json(); + + // store code in session for callback method + $this->session->set('pocketCode', $values['code']); + + return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; + } + + public function oAuthAuthorize() + { + $client = $this->createClient(); + + $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', + [ + 'body' => json_encode([ + 'consumer_key' => $this->consumerKey, + 'code' => $this->session->get('pocketCode'), + ]), + ] + ); + + $response = $client->send($request); + + return $response->json()['access_token']; + } + + public function import($accessToken) + { + $client = $this->createClient(); + + $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', + [ + 'body' => json_encode([ + 'consumer_key' => $this->consumerKey, + 'access_token' => $accessToken, + 'detailType' => 'complete', + ]), + ] + ); + + $response = $client->send($request); + $entries = $response->json(); + + $this->parsePocketEntries($entries['list']); + + $this->session->getFlashBag()->add( + 'notice', + count($entries['list']).' entries imported' + ); + } +} diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml new file mode 100644 index 00000000..82628f08 --- /dev/null +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -0,0 +1,8 @@ +services: + wallabag_import.import.pocket_import: + class: Wallabag\ImportBundle\Import\PocketImport + arguments: + - @security.token_storage + - @session + - @doctrine.orm.entity_manager + - %pocket_consumer_key% -- cgit v1.2.3 From 9c9c23cf0843405cd4b0de3bae8d428cb39b5720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Fri, 23 Oct 2015 14:04:43 +0200 Subject: forgot test parameters --- app/config/tests/parameters.yml.dist.mysql | 3 +++ app/config/tests/parameters.yml.dist.pgsql | 3 +++ app/config/tests/parameters.yml.dist.sqlite | 3 +++ 3 files changed, 9 insertions(+) diff --git a/app/config/tests/parameters.yml.dist.mysql b/app/config/tests/parameters.yml.dist.mysql index 096ad8c7..c0e19fe7 100644 --- a/app/config/tests/parameters.yml.dist.mysql +++ b/app/config/tests/parameters.yml.dist.mysql @@ -60,3 +60,6 @@ parameters: language: en_US from_email: no-reply@wallabag.org rss_limit: 50 + + # pocket import + pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 diff --git a/app/config/tests/parameters.yml.dist.pgsql b/app/config/tests/parameters.yml.dist.pgsql index ca3f6ea2..d4dd9da5 100644 --- a/app/config/tests/parameters.yml.dist.pgsql +++ b/app/config/tests/parameters.yml.dist.pgsql @@ -60,3 +60,6 @@ parameters: language: en_US from_email: no-reply@wallabag.org rss_limit: 50 + + # pocket import + pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 diff --git a/app/config/tests/parameters.yml.dist.sqlite b/app/config/tests/parameters.yml.dist.sqlite index 92460bcf..5fbf4c70 100644 --- a/app/config/tests/parameters.yml.dist.sqlite +++ b/app/config/tests/parameters.yml.dist.sqlite @@ -60,3 +60,6 @@ parameters: language: en_US from_email: no-reply@wallabag.org rss_limit: 50 + + # pocket import + pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 -- cgit v1.2.3 From 557e549db7932e9101f60bfda64238a235a0ce3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Fri, 23 Oct 2015 14:09:19 +0200 Subject: service call --- src/Wallabag/ImportBundle/Controller/PocketController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index 76d8417b..9602c282 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -21,7 +21,7 @@ class PocketController extends Controller */ public function authAction() { - $pocket = new PocketImport($this->get('security.token_storage'), $this->get('session'), $this->getDoctrine()->getManager(), $this->container->getParameter('pocket_consumer_key')); + $pocket = $this->get('wallabag_import.import.pocket_import'); $authUrl = $pocket->oAuthRequest($this->generateUrl('import', array(), true), $this->generateUrl('callbackpocket', array(), true)); return $this->redirect($authUrl, 301); @@ -32,7 +32,7 @@ class PocketController extends Controller */ public function callbackAction() { - $pocket = new PocketImport($this->get('security.token_storage'), $this->get('session'), $this->getDoctrine()->getManager(), $this->container->getParameter('pocket_consumer_key')); + $pocket = $this->get('wallabag_import.import.pocket_import'); $accessToken = $pocket->oAuthAuthorize(); $pocket->import($accessToken); -- cgit v1.2.3 From d51b38ed309c9aead938e8c8963c05c6d82b4ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Fri, 23 Oct 2015 14:45:50 +0200 Subject: create ImportController to list importers --- .../ImportBundle/Controller/ImportController.php | 17 +++++++++++++++++ .../ImportBundle/Controller/PocketController.php | 9 ++++----- src/Wallabag/ImportBundle/Import/ImportInterface.php | 2 ++ src/Wallabag/ImportBundle/Import/PocketImport.php | 10 ++++++++++ .../ImportBundle/Resources/views/Import/index.html.twig | 16 ++++++++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 src/Wallabag/ImportBundle/Controller/ImportController.php create mode 100644 src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php new file mode 100644 index 00000000..3569793b --- /dev/null +++ b/src/Wallabag/ImportBundle/Controller/ImportController.php @@ -0,0 +1,17 @@ +render('WallabagImportBundle:Import:index.html.twig', array()); + } +} diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index 9602c282..f851c81c 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -4,20 +4,19 @@ namespace Wallabag\ImportBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; -use Wallabag\ImportBundle\Import\PocketImport; class PocketController extends Controller { /** - * @Route("/import", name="import") + * @Route("/import/pocket", name="pocket") */ - public function importAction() + public function indexAction() { return $this->render('WallabagImportBundle:Pocket:index.html.twig', array()); } /** - * @Route("/auth-pocket", name="authpocket") + * @Route("/import/pocket/auth", name="authpocket") */ public function authAction() { @@ -28,7 +27,7 @@ class PocketController extends Controller } /** - * @Route("/callback-pocket", name="callbackpocket") + * @Route("/import/pocket/callback", name="callbackpocket") */ public function callbackAction() { diff --git a/src/Wallabag/ImportBundle/Import/ImportInterface.php b/src/Wallabag/ImportBundle/Import/ImportInterface.php index 88de3fa8..f07a120c 100644 --- a/src/Wallabag/ImportBundle/Import/ImportInterface.php +++ b/src/Wallabag/ImportBundle/Import/ImportInterface.php @@ -4,6 +4,8 @@ namespace Wallabag\ImportBundle\Import; interface ImportInterface { + public function getName(); + public function getDescription(); public function oAuthRequest($redirectUri, $callbackUri); public function oAuthAuthorize(); public function import($accessToken); diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 413c9ccc..81af8e57 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -23,6 +23,16 @@ class PocketImport implements ImportInterface $this->consumerKey = $consumerKey; } + public function getName() + { + return 'Pocket'; + } + + public function getDescription() + { + return 'This importer will import all your Pocket data.'; + } + /** * Create a new Client. * diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig new file mode 100644 index 00000000..bdd57e5e --- /dev/null +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -0,0 +1,16 @@ +{% extends "WallabagCoreBundle::layout.html.twig" %} +{% block title %}{% trans %}import{% endtrans %}{% endblock %} + +{% block content %} + +
    +
    +
    + {% trans %}Welcome on wallabag importer. Please select your previous service that you want to migrate.{% endtrans %} + +
    +
    +
    +{% endblock %} -- cgit v1.2.3 From 87f23b005c5f68f7463333a74317efa4eb9a9565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Mon, 26 Oct 2015 10:55:35 +0100 Subject: assign tags to entries and add lastPocketImport attribute to user --- src/Wallabag/ImportBundle/Import/PocketImport.php | 76 ++++++++++++++++++---- .../Resources/views/Pocket/index.html.twig | 2 +- src/Wallabag/UserBundle/Entity/User.php | 23 +++++++ 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 81af8e57..6b93c180 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -6,6 +6,7 @@ use Doctrine\ORM\EntityManager; use GuzzleHttp\Client; use Symfony\Component\HttpFoundation\Session\Session; use Wallabag\CoreBundle\Entity\Entry; +use Wallabag\CoreBundle\Entity\Tag; use Wallabag\CoreBundle\Tools\Utils; class PocketImport implements ImportInterface @@ -50,31 +51,80 @@ class PocketImport implements ImportInterface ]); } + /** + * Returns the good title for current entry. + * + * @param $pocketEntry + * + * @return string + */ + private function guessTitle($pocketEntry) + { + if (isset($pocketEntry['resolved_title']) && $pocketEntry['resolved_title'] != '') { + return $pocketEntry['resolved_title']; + } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') { + return $pocketEntry['given_title']; + } else { + return 'Untitled'; + } + } + + private function assignTagsToEntry(Entry $entry, $tags) + { + foreach ($tags as $tag) { + $label = trim($tag['tag']); + $tagEntity = $this->em + ->getRepository('WallabagCoreBundle:Tag') + ->findOneByLabelAndUserId($label, $this->user->getId()); + + if (is_object($tagEntity)) { + $entry->addTag($tagEntity); + } else { + $newTag = new Tag($this->user); + $newTag->setLabel($label); + $entry->addTag($newTag); + } + $this->em->flush(); + } + } + /** * @param $entries */ private function parsePocketEntries($entries) { - foreach ($entries as $entry) { - $newEntry = new Entry($this->user); - $newEntry->setUrl($entry['given_url']); - $newEntry->setTitle(isset($entry['resolved_title']) ? $entry['resolved_title'] : (isset($entry['given_title']) ? $entry['given_title'] : 'Untitled')); + foreach ($entries as $pocketEntry) { + $entry = new Entry($this->user); + $entry->setUrl($pocketEntry['given_url']); + if ($pocketEntry['status'] == 1) { + $entry->setArchived(true); + } + if ($pocketEntry['favorite'] == 1) { + $entry->setStarred(true); + } + + $entry->setTitle($this->guessTitle($pocketEntry)); + + if (isset($pocketEntry['excerpt'])) { + $entry->setContent($pocketEntry['excerpt']); + } - if (isset($entry['excerpt'])) { - $newEntry->setContent($entry['excerpt']); + if (isset($pocketEntry['has_image']) && $pocketEntry['has_image'] > 0) { + $entry->setPreviewPicture($pocketEntry['image']['src']); } - if (isset($entry['has_image']) && $entry['has_image'] > 0) { - $newEntry->setPreviewPicture($entry['image']['src']); + if (isset($pocketEntry['word_count'])) { + $entry->setReadingTime(Utils::convertWordsToMinutes($pocketEntry['word_count'])); } - if (isset($entry['word_count'])) { - $newEntry->setReadingTime(Utils::convertWordsToMinutes($entry['word_count'])); + if (!empty($pocketEntry['tags'])) { + $this->assignTagsToEntry($entry, $pocketEntry['tags']); } - $this->em->persist($newEntry); + $this->em->persist($entry); } + $this->user->setLastPocketImport(new \DateTime()); $this->em->flush(); } @@ -120,6 +170,7 @@ class PocketImport implements ImportInterface public function import($accessToken) { $client = $this->createClient(); + $since = (!is_null($this->user->getLastPocketImport()) ? $this->user->getLastPocketImport()->getTimestamp() : ''); $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', [ @@ -127,6 +178,9 @@ class PocketImport implements ImportInterface 'consumer_key' => $this->consumerKey, 'access_token' => $accessToken, 'detailType' => 'complete', + 'state' => 'all', + 'sort' => 'oldest', + 'since' => $since, ]), ] ); diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig index d47dd8d5..e6abc17b 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -8,7 +8,7 @@
    {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %}
    - +
    diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index e6528420..4851999f 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php @@ -84,6 +84,13 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf */ private $trusted; + /** + * @var date + * + * @ORM\Column(name="last_pocket_import", type="datetime", nullable=true) + */ + private $lastPocketImport; + public function __construct() { parent::__construct(); @@ -240,4 +247,20 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf return false; } + + /** + * @return date + */ + public function getLastPocketImport() + { + return $this->lastPocketImport; + } + + /** + * @param date $lastPocketImport + */ + public function setLastPocketImport($lastPocketImport) + { + $this->lastPocketImport = $lastPocketImport; + } } -- cgit v1.2.3 From dda57bb9443817e3a080d5d25343f5a7e15dd14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Mon, 26 Oct 2015 14:38:24 +0100 Subject: fix #1502 avoid duplicate entry and store pocket url in config --- app/config/config.yml | 8 +++ .../CoreBundle/Controller/EntryController.php | 14 +++++ .../DependencyInjection/Configuration.php | 17 +++++++ .../WallabagImportExtension.php | 1 + src/Wallabag/ImportBundle/Import/PocketImport.php | 59 +++++++++++++++++----- .../ImportBundle/Resources/config/services.yml | 1 + src/Wallabag/UserBundle/Entity/User.php | 23 --------- 7 files changed, 87 insertions(+), 36 deletions(-) diff --git a/app/config/config.yml b/app/config/config.yml index 421b2db5..88b1a59f 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -33,6 +33,14 @@ wallabag_core: import: allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] +wallabag_import: + importers: + pocket_urls: + oauth_request: https://getpocket.com/v3/oauth/request + auth_authorize: https://getpocket.com/auth/authorize + oauth_authorize: https://getpocket.com/v3/oauth/authorize + get: https://getpocket.com/v3/get + # Twig Configuration twig: debug: "%kernel.debug%" diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index fa580133..de2eedcb 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php @@ -41,6 +41,7 @@ class EntryController extends Controller */ public function addEntryFormAction(Request $request) { + $em = $this->getDoctrine()->getManager(); $entry = new Entry($this->getUser()); $form = $this->createForm(new NewEntryType(), $entry); @@ -48,6 +49,19 @@ class EntryController extends Controller $form->handleRequest($request); if ($form->isValid()) { + $existingEntry = $em + ->getRepository('WallabagCoreBundle:Entry') + ->findOneByUrl($entry->getUrl()); + + if (!is_null($existingEntry)) { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Entry already saved on '.$existingEntry->getCreatedAt()->format('d-m-Y') + ); + + return $this->redirect($this->generateUrl('view', array('id' => $existingEntry->getId()))); + } + $this->updateEntry($entry); $this->get('session')->getFlashBag()->add( 'notice', diff --git a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php index bacaff31..3c14104e 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php @@ -2,6 +2,7 @@ namespace Wallabag\ImportBundle\DependencyInjection; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -12,6 +13,22 @@ class Configuration implements ConfigurationInterface $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('wallabag_import'); + $rootNode + ->children() + ->arrayNode('importers') + ->append($this->getURLs()) + ->end() + ->end() + ; + return $treeBuilder; } + + private function getURLs() + { + $node = new ArrayNodeDefinition('pocket_urls'); + $node->prototype('scalar')->end(); + + return $node; + } } diff --git a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php index 4efcaace..07dc378d 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php @@ -13,6 +13,7 @@ class WallabagImportExtension extends Extension { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); + $container->setParameter('wallabag_import.pocket', $config['importers']['pocket_urls']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 6b93c180..51f73f4c 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -15,13 +15,19 @@ class PocketImport implements ImportInterface private $session; private $em; private $consumerKey; + private $skippedEntries; + private $importedEntries; + private $pocketURL; - public function __construct($tokenStorage, Session $session, EntityManager $em, $consumerKey) + public function __construct($tokenStorage, Session $session, EntityManager $em, $consumerKey, $pocketURL) { $this->user = $tokenStorage->getToken()->getUser(); $this->session = $session; $this->em = $em; $this->consumerKey = $consumerKey; + $this->skippedEntries = 0; + $this->importedEntries = 0; + $this->pocketURL = $pocketURL; } public function getName() @@ -64,9 +70,25 @@ class PocketImport implements ImportInterface return $pocketEntry['resolved_title']; } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') { return $pocketEntry['given_title']; - } else { - return 'Untitled'; } + + return 'Untitled'; + } + + /** + * Returns the good URL for current entry. + * + * @param $pocketEntry + * + * @return string + */ + private function guessURL($pocketEntry) + { + if (isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '') { + return $pocketEntry['resolved_url']; + } + + return $pocketEntry['given_url']; } private function assignTagsToEntry(Entry $entry, $tags) @@ -95,7 +117,20 @@ class PocketImport implements ImportInterface { foreach ($entries as $pocketEntry) { $entry = new Entry($this->user); - $entry->setUrl($pocketEntry['given_url']); + $url = $this->guessURL($pocketEntry); + + $existingEntry = $this->em + ->getRepository('WallabagCoreBundle:Entry') + ->findOneByUrl($url); + + if (!is_null($existingEntry)) { + ++$this->skippedEntries; + continue; + } + + $entry->setUrl($url); + $entry->setDomainName(parse_url($url, PHP_URL_HOST)); + if ($pocketEntry['status'] == 1) { $entry->setArchived(true); } @@ -118,20 +153,20 @@ class PocketImport implements ImportInterface } if (!empty($pocketEntry['tags'])) { - $this->assignTagsToEntry($entry, $pocketEntry['tags']); + // $this->assignTagsToEntry($entry, $pocketEntry['tags']); } $this->em->persist($entry); + ++$this->importedEntries; } - $this->user->setLastPocketImport(new \DateTime()); $this->em->flush(); } public function oAuthRequest($redirectUri, $callbackUri) { $client = $this->createClient(); - $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', + $request = $client->createRequest('POST', $this->pocketURL['oauth_request'], [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, @@ -146,14 +181,14 @@ class PocketImport implements ImportInterface // store code in session for callback method $this->session->set('pocketCode', $values['code']); - return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; + return $this->pocketURL['auth_authorize'].'?request_token='.$values['code'].'&redirect_uri='.$callbackUri; } public function oAuthAuthorize() { $client = $this->createClient(); - $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', + $request = $client->createRequest('POST', $this->pocketURL['oauth_authorize'], [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, @@ -170,9 +205,8 @@ class PocketImport implements ImportInterface public function import($accessToken) { $client = $this->createClient(); - $since = (!is_null($this->user->getLastPocketImport()) ? $this->user->getLastPocketImport()->getTimestamp() : ''); - $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', + $request = $client->createRequest('POST', $this->pocketURL['get'], [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, @@ -180,7 +214,6 @@ class PocketImport implements ImportInterface 'detailType' => 'complete', 'state' => 'all', 'sort' => 'oldest', - 'since' => $since, ]), ] ); @@ -192,7 +225,7 @@ class PocketImport implements ImportInterface $this->session->getFlashBag()->add( 'notice', - count($entries['list']).' entries imported' + $this->importedEntries.' entries imported, '.$this->skippedEntries.' already saved.' ); } } diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index 82628f08..8f224d88 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -6,3 +6,4 @@ services: - @session - @doctrine.orm.entity_manager - %pocket_consumer_key% + - %wallabag_import.pocket% diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index 4851999f..e6528420 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php @@ -84,13 +84,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf */ private $trusted; - /** - * @var date - * - * @ORM\Column(name="last_pocket_import", type="datetime", nullable=true) - */ - private $lastPocketImport; - public function __construct() { parent::__construct(); @@ -247,20 +240,4 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf return false; } - - /** - * @return date - */ - public function getLastPocketImport() - { - return $this->lastPocketImport; - } - - /** - * @param date $lastPocketImport - */ - public function setLastPocketImport($lastPocketImport) - { - $this->lastPocketImport = $lastPocketImport; - } } -- cgit v1.2.3 From 303768dfe9b85f87d043eb225c5c8c3a88d8c051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Mon, 26 Oct 2015 15:49:44 +0100 Subject: - remove importers configuration - add check on userId for findOneByURL for entries --- app/config/config.yml | 8 -------- .../CoreBundle/Controller/EntryController.php | 8 ++++---- .../CoreBundle/Repository/EntryRepository.php | 17 +++++++++++++++ .../DependencyInjection/Configuration.php | 17 --------------- .../WallabagImportExtension.php | 1 - src/Wallabag/ImportBundle/Import/PocketImport.php | 24 +++++++++------------- .../ImportBundle/Resources/config/services.yml | 1 - 7 files changed, 31 insertions(+), 45 deletions(-) diff --git a/app/config/config.yml b/app/config/config.yml index 88b1a59f..421b2db5 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -33,14 +33,6 @@ wallabag_core: import: allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] -wallabag_import: - importers: - pocket_urls: - oauth_request: https://getpocket.com/v3/oauth/request - auth_authorize: https://getpocket.com/auth/authorize - oauth_authorize: https://getpocket.com/v3/oauth/authorize - get: https://getpocket.com/v3/get - # Twig Configuration twig: debug: "%kernel.debug%" diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index de2eedcb..9097810c 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php @@ -51,15 +51,15 @@ class EntryController extends Controller if ($form->isValid()) { $existingEntry = $em ->getRepository('WallabagCoreBundle:Entry') - ->findOneByUrl($entry->getUrl()); + ->findOneByUrlAndUserId($entry->getUrl(), $this->getUser()->getId()); - if (!is_null($existingEntry)) { + if (count($existingEntry) > 0) { $this->get('session')->getFlashBag()->add( 'notice', - 'Entry already saved on '.$existingEntry->getCreatedAt()->format('d-m-Y') + 'Entry already saved on '.$existingEntry[0]->getCreatedAt()->format('d-m-Y') ); - return $this->redirect($this->generateUrl('view', array('id' => $existingEntry->getId()))); + return $this->redirect($this->generateUrl('view', array('id' => $existingEntry[0]->getId()))); } $this->updateEntry($entry); diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index ca71970b..502e9da0 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php @@ -223,4 +223,21 @@ class EntryRepository extends EntityRepository ->getQuery() ->getResult(); } + + /** + * Find an entry by its url and its owner. + * + * @param $url + * @param $userId + * + * @return array + */ + public function findOneByUrlAndUserId($url, $userId) + { + return $this->createQueryBuilder('e') + ->where('e.url = :url')->setParameter('url', $url) + ->andWhere('e.user = :user_id')->setParameter('user_id', $userId) + ->getQuery() + ->getResult(); + } } diff --git a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php index 3c14104e..bacaff31 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php @@ -2,7 +2,6 @@ namespace Wallabag\ImportBundle\DependencyInjection; -use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -13,22 +12,6 @@ class Configuration implements ConfigurationInterface $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('wallabag_import'); - $rootNode - ->children() - ->arrayNode('importers') - ->append($this->getURLs()) - ->end() - ->end() - ; - return $treeBuilder; } - - private function getURLs() - { - $node = new ArrayNodeDefinition('pocket_urls'); - $node->prototype('scalar')->end(); - - return $node; - } } diff --git a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php index 07dc378d..4efcaace 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php @@ -13,7 +13,6 @@ class WallabagImportExtension extends Extension { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $container->setParameter('wallabag_import.pocket', $config['importers']['pocket_urls']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 51f73f4c..dd1c34ab 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -15,19 +15,15 @@ class PocketImport implements ImportInterface private $session; private $em; private $consumerKey; - private $skippedEntries; - private $importedEntries; - private $pocketURL; + private $skippedEntries = 0; + private $importedEntries = 0; - public function __construct($tokenStorage, Session $session, EntityManager $em, $consumerKey, $pocketURL) + public function __construct($tokenStorage, Session $session, EntityManager $em, $consumerKey) { $this->user = $tokenStorage->getToken()->getUser(); $this->session = $session; $this->em = $em; $this->consumerKey = $consumerKey; - $this->skippedEntries = 0; - $this->importedEntries = 0; - $this->pocketURL = $pocketURL; } public function getName() @@ -121,9 +117,9 @@ class PocketImport implements ImportInterface $existingEntry = $this->em ->getRepository('WallabagCoreBundle:Entry') - ->findOneByUrl($url); + ->findOneByUrlAndUserId($url, $this->user->getId()); - if (!is_null($existingEntry)) { + if (count($existingEntry) > 0) { ++$this->skippedEntries; continue; } @@ -153,7 +149,7 @@ class PocketImport implements ImportInterface } if (!empty($pocketEntry['tags'])) { - // $this->assignTagsToEntry($entry, $pocketEntry['tags']); + $this->assignTagsToEntry($entry, $pocketEntry['tags']); } $this->em->persist($entry); @@ -166,7 +162,7 @@ class PocketImport implements ImportInterface public function oAuthRequest($redirectUri, $callbackUri) { $client = $this->createClient(); - $request = $client->createRequest('POST', $this->pocketURL['oauth_request'], + $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, @@ -181,14 +177,14 @@ class PocketImport implements ImportInterface // store code in session for callback method $this->session->set('pocketCode', $values['code']); - return $this->pocketURL['auth_authorize'].'?request_token='.$values['code'].'&redirect_uri='.$callbackUri; + return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; } public function oAuthAuthorize() { $client = $this->createClient(); - $request = $client->createRequest('POST', $this->pocketURL['oauth_authorize'], + $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, @@ -206,7 +202,7 @@ class PocketImport implements ImportInterface { $client = $this->createClient(); - $request = $client->createRequest('POST', $this->pocketURL['get'], + $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index 8f224d88..82628f08 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -6,4 +6,3 @@ services: - @session - @doctrine.orm.entity_manager - %pocket_consumer_key% - - %wallabag_import.pocket% -- cgit v1.2.3 From 27a8708b673bb0a28a520131d94ce17c7d3b9f96 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Thu, 24 Dec 2015 14:06:55 +0100 Subject: Update deps --- composer.lock | 80 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/composer.lock b/composer.lock index 076dfcac..a3ac7e8c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "91da706ef4b39a73704c3e2154c1a227", - "content-hash": "81a3c2c84d78471bfb526b2b572182f7", + "hash": "7f1939f54201ee0e068eddde41454261", + "content-hash": "9b7801951c4ea69565ee8f4914071c25", "packages": [ { "name": "behat/transliterator", @@ -117,16 +117,16 @@ }, { "name": "doctrine/cache", - "version": "v1.5.2", + "version": "v1.5.4", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "47c7128262da274f590ae6f86eb137a7a64e82af" + "reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/47c7128262da274f590ae6f86eb137a7a64e82af", - "reference": "47c7128262da274f590ae6f86eb137a7a64e82af", + "url": "https://api.github.com/repos/doctrine/cache/zipball/47cdc76ceb95cc591d9c79a36dc3794975b5d136", + "reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136", "shasum": "" }, "require": { @@ -183,7 +183,7 @@ "cache", "caching" ], - "time": "2015-12-03 10:50:37" + "time": "2015-12-19 05:03:47" }, { "name": "doctrine/collections", @@ -981,17 +981,17 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "1.7.4", + "version": "1.7.6", "target-dir": "FOS/RestBundle", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "64ba918b1eb47acb5aa7fef1ce95623235b53775" + "reference": "f95b2f141748e9a5e2ddae833f60c38417aee8c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/64ba918b1eb47acb5aa7fef1ce95623235b53775", - "reference": "64ba918b1eb47acb5aa7fef1ce95623235b53775", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/f95b2f141748e9a5e2ddae833f60c38417aee8c3", + "reference": "f95b2f141748e9a5e2ddae833f60c38417aee8c3", "shasum": "" }, "require": { @@ -1063,7 +1063,7 @@ "keywords": [ "rest" ], - "time": "2015-12-05 14:55:07" + "time": "2015-12-20 13:45:30" }, { "name": "friendsofsymfony/user-bundle", @@ -2044,16 +2044,16 @@ }, { "name": "hoa/stream", - "version": "0.15.10.26", + "version": "0.15.08.28", "source": { "type": "git", "url": "https://github.com/hoaproject/Stream.git", - "reference": "011ab91d942f1d7096deade4c8a10fe57d51c5b3" + "reference": "cbd0f4749e447f4d31001e7c898f5e794c5861cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Stream/zipball/011ab91d942f1d7096deade4c8a10fe57d51c5b3", - "reference": "011ab91d942f1d7096deade4c8a10fe57d51c5b3", + "url": "https://api.github.com/repos/hoaproject/Stream/zipball/cbd0f4749e447f4d31001e7c898f5e794c5861cb", + "reference": "cbd0f4749e447f4d31001e7c898f5e794c5861cb", "shasum": "" }, "require": { @@ -2098,7 +2098,7 @@ "stream", "wrapper" ], - "time": "2015-10-22 06:30:43" + "time": "2015-08-28 07:31:43" }, { "name": "hoa/ustring", @@ -2313,16 +2313,16 @@ }, { "name": "j0k3r/graby", - "version": "1.0.6", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/j0k3r/graby.git", - "reference": "c9f5543fad60dc4efd12195733f96bb4fdb0e6e0" + "reference": "bf152ccc6629bdd63b1e5e8b297c2912516b5f1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/j0k3r/graby/zipball/c9f5543fad60dc4efd12195733f96bb4fdb0e6e0", - "reference": "c9f5543fad60dc4efd12195733f96bb4fdb0e6e0", + "url": "https://api.github.com/repos/j0k3r/graby/zipball/bf152ccc6629bdd63b1e5e8b297c2912516b5f1e", + "reference": "bf152ccc6629bdd63b1e5e8b297c2912516b5f1e", "shasum": "" }, "require": { @@ -2365,20 +2365,20 @@ } ], "description": "Graby helps you extract article content from web pages", - "time": "2015-12-02 13:22:19" + "time": "2015-12-24 08:28:38" }, { "name": "j0k3r/graby-site-config", - "version": "1.0.9", + "version": "1.0.11", "source": { "type": "git", "url": "https://github.com/j0k3r/graby-site-config.git", - "reference": "7666fed2a2cd211ef366f6fed9ccddd8e0b9e623" + "reference": "ac198f308beabccc97bbd35ed0daeaac63fbf1e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/7666fed2a2cd211ef366f6fed9ccddd8e0b9e623", - "reference": "7666fed2a2cd211ef366f6fed9ccddd8e0b9e623", + "url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/ac198f308beabccc97bbd35ed0daeaac63fbf1e3", + "reference": "ac198f308beabccc97bbd35ed0daeaac63fbf1e3", "shasum": "" }, "require": { @@ -2401,7 +2401,7 @@ } ], "description": "Graby site config files", - "time": "2015-12-03 19:49:20" + "time": "2015-12-23 22:52:15" }, { "name": "j0k3r/php-readability", @@ -3138,9 +3138,7 @@ "authors": [ { "name": "S.C. Chen", - "email": "me578022@gmail.com", - "homepage": "http://simplehtmldom.sourceforge.net/", - "role": "Lead Developer" + "email": "me578022@gmail.com" } ], "description": "Composer package that gives you access to and (unlike all the others at this time) autoloads S.C. Chen's PHP Simple HTML DOM Parser Library", @@ -3767,16 +3765,16 @@ }, { "name": "scheb/two-factor-bundle", - "version": "v1.5.0", + "version": "v1.4.7", "source": { "type": "git", "url": "https://github.com/scheb/two-factor-bundle.git", - "reference": "b0da3a85b181237c3bebde88c99b18745313360b" + "reference": "ef6830dbbf62b22efd335db8f64bf0f51d4284a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/two-factor-bundle/zipball/b0da3a85b181237c3bebde88c99b18745313360b", - "reference": "b0da3a85b181237c3bebde88c99b18745313360b", + "url": "https://api.github.com/repos/scheb/two-factor-bundle/zipball/ef6830dbbf62b22efd335db8f64bf0f51d4284a2", + "reference": "ef6830dbbf62b22efd335db8f64bf0f51d4284a2", "shasum": "" }, "require": { @@ -3812,7 +3810,7 @@ "two-factor", "two-step" ], - "time": "2015-11-15 13:31:23" + "time": "2015-08-25 19:58:00" }, { "name": "sensio/distribution-bundle", @@ -5439,16 +5437,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.20", + "version": "4.8.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7438c43bc2bbb2febe1723eb595b1c49283a26ad" + "reference": "ea76b17bced0500a28098626b84eda12dbcf119c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7438c43bc2bbb2febe1723eb595b1c49283a26ad", - "reference": "7438c43bc2bbb2febe1723eb595b1c49283a26ad", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c", + "reference": "ea76b17bced0500a28098626b84eda12dbcf119c", "shasum": "" }, "require": { @@ -5457,7 +5455,7 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "php": "~5.3.3|~5.4|~5.5|~5.6", + "php": ">=5.3.3", "phpspec/prophecy": "^1.3.1", "phpunit/php-code-coverage": "~2.1", "phpunit/php-file-iterator": "~1.4", @@ -5507,7 +5505,7 @@ "testing", "xunit" ], - "time": "2015-12-10 07:48:52" + "time": "2015-12-12 07:45:58" }, { "name": "phpunit/phpunit-mock-objects", -- cgit v1.2.3 From 5a4bbcc9a76fcdf54a6af25fcf7b26c9053a0ba3 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Thu, 24 Dec 2015 15:19:50 +0100 Subject: Change the way to check for an existing entry The repository method return the entry found or false if nothing exists. --- src/Wallabag/CoreBundle/Controller/EntryController.php | 13 ++++++------- src/Wallabag/CoreBundle/Repository/EntryRepository.php | 14 +++++++++++--- src/Wallabag/CoreBundle/Resources/config/services.yml | 1 + src/Wallabag/ImportBundle/Import/PocketImport.php | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index 9097810c..37f7ab60 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php @@ -41,7 +41,6 @@ class EntryController extends Controller */ public function addEntryFormAction(Request $request) { - $em = $this->getDoctrine()->getManager(); $entry = new Entry($this->getUser()); $form = $this->createForm(new NewEntryType(), $entry); @@ -49,17 +48,17 @@ class EntryController extends Controller $form->handleRequest($request); if ($form->isValid()) { - $existingEntry = $em - ->getRepository('WallabagCoreBundle:Entry') - ->findOneByUrlAndUserId($entry->getUrl(), $this->getUser()->getId()); + // check for existing entry, if it exists, redirect to it with a message + $existingEntry = $this->get('wallabag_core.entry_repository') + ->existByUrlAndUserId($entry->getUrl(), $this->getUser()->getId()); - if (count($existingEntry) > 0) { + if (false !== $existingEntry) { $this->get('session')->getFlashBag()->add( 'notice', - 'Entry already saved on '.$existingEntry[0]->getCreatedAt()->format('d-m-Y') + 'Entry already saved on '.$existingEntry['createdAt']->format('d-m-Y') ); - return $this->redirect($this->generateUrl('view', array('id' => $existingEntry[0]->getId()))); + return $this->redirect($this->generateUrl('view', array('id' => $existingEntry['id']))); } $this->updateEntry($entry); diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index 502e9da0..b8e22eb8 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php @@ -226,18 +226,26 @@ class EntryRepository extends EntityRepository /** * Find an entry by its url and its owner. + * If it exists, return the entry otherwise return false. * * @param $url * @param $userId * - * @return array + * @return array|bool */ - public function findOneByUrlAndUserId($url, $userId) + public function existByUrlAndUserId($url, $userId) { - return $this->createQueryBuilder('e') + $res = $this->createQueryBuilder('e') + ->select('e.id, e.createdAt') ->where('e.url = :url')->setParameter('url', $url) ->andWhere('e.user = :user_id')->setParameter('user_id', $userId) ->getQuery() ->getResult(); + + if (count($res) > 1) { + return next($res); + } + + return false; } } diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index c92b4eb3..96b1c931 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml @@ -63,6 +63,7 @@ services: - @wallabag_core.tag_repository - @wallabag_core.entry_repository + # repository as a service wallabag_core.entry_repository: class: Wallabag\CoreBundle\Repository\EntryRepository factory: [ @doctrine.orm.default_entity_manager, getRepository ] diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index dd1c34ab..ef8f9eb5 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -117,9 +117,9 @@ class PocketImport implements ImportInterface $existingEntry = $this->em ->getRepository('WallabagCoreBundle:Entry') - ->findOneByUrlAndUserId($url, $this->user->getId()); + ->existByUrlAndUserId($url, $this->user->getId()); - if (count($existingEntry) > 0) { + if (false !== $existingEntry) { ++$this->skippedEntries; continue; } -- cgit v1.2.3 From 0aa344dc247c77376fcbf2112191f9f8b3dfc846 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Thu, 24 Dec 2015 15:22:56 +0100 Subject: Update url & service name Prefix ur with service namel: [service]_[route name] Add comment in Interface --- .../ImportBundle/Controller/PocketController.php | 15 ++++++---- .../ImportBundle/Import/ImportInterface.php | 33 ++++++++++++++++++++++ src/Wallabag/ImportBundle/Import/PocketImport.php | 9 +++++- .../ImportBundle/Resources/config/services.yml | 8 +++--- .../Resources/views/Import/index.html.twig | 2 +- .../Resources/views/Pocket/index.html.twig | 2 +- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index f851c81c..2ab062e7 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -8,7 +8,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class PocketController extends Controller { /** - * @Route("/import/pocket", name="pocket") + * @Route("/import/pocket", name="pocket_import") */ public function indexAction() { @@ -16,22 +16,25 @@ class PocketController extends Controller } /** - * @Route("/import/pocket/auth", name="authpocket") + * @Route("/import/pocket/auth", name="pocket_auth") */ public function authAction() { - $pocket = $this->get('wallabag_import.import.pocket_import'); - $authUrl = $pocket->oAuthRequest($this->generateUrl('import', array(), true), $this->generateUrl('callbackpocket', array(), true)); + $pocket = $this->get('wallabag_import.pocket.import'); + $authUrl = $pocket->oAuthRequest( + $this->generateUrl('import', array(), true), + $this->generateUrl('pocket_callback', array(), true) + ); return $this->redirect($authUrl, 301); } /** - * @Route("/import/pocket/callback", name="callbackpocket") + * @Route("/import/pocket/callback", name="pocket_callback") */ public function callbackAction() { - $pocket = $this->get('wallabag_import.import.pocket_import'); + $pocket = $this->get('wallabag_import.pocket.import'); $accessToken = $pocket->oAuthAuthorize(); $pocket->import($accessToken); diff --git a/src/Wallabag/ImportBundle/Import/ImportInterface.php b/src/Wallabag/ImportBundle/Import/ImportInterface.php index f07a120c..0f9b3256 100644 --- a/src/Wallabag/ImportBundle/Import/ImportInterface.php +++ b/src/Wallabag/ImportBundle/Import/ImportInterface.php @@ -4,9 +4,42 @@ namespace Wallabag\ImportBundle\Import; interface ImportInterface { + /** + * Name of the import. + * + * @return string + */ public function getName(); + + /** + * Description of the import. + * + * @return string + */ public function getDescription(); + + /** + * Return the oauth url to authenticate the client. + * + * @param string $redirectUri Redirect url in case of error + * @param string $callbackUri Url when the authentication is complete + * + * @return string + */ public function oAuthRequest($redirectUri, $callbackUri); + + /** + * Usually called by the previous callback to authorize the client. + * Then it return a token that can be used for next requests. + * + * @return string + */ public function oAuthAuthorize(); + + /** + * Import content using the user token. + * + * @param string $accessToken User access token + */ public function import($accessToken); } diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index ef8f9eb5..85bab0db 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -5,6 +5,7 @@ namespace Wallabag\ImportBundle\Import; use Doctrine\ORM\EntityManager; use GuzzleHttp\Client; use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Wallabag\CoreBundle\Entity\Entry; use Wallabag\CoreBundle\Entity\Tag; use Wallabag\CoreBundle\Tools\Utils; @@ -18,7 +19,7 @@ class PocketImport implements ImportInterface private $skippedEntries = 0; private $importedEntries = 0; - public function __construct($tokenStorage, Session $session, EntityManager $em, $consumerKey) + public function __construct(TokenStorageInterface $tokenStorage, Session $session, EntityManager $em, $consumerKey) { $this->user = $tokenStorage->getToken()->getUser(); $this->session = $session; @@ -26,11 +27,17 @@ class PocketImport implements ImportInterface $this->consumerKey = $consumerKey; } + /** + * {@inheritdoc} + */ public function getName() { return 'Pocket'; } + /** + * {@inheritdoc} + */ public function getDescription() { return 'This importer will import all your Pocket data.'; diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index 82628f08..d77779eb 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -1,8 +1,8 @@ services: - wallabag_import.import.pocket_import: + wallabag_import.pocket.import: class: Wallabag\ImportBundle\Import\PocketImport arguments: - - @security.token_storage - - @session - - @doctrine.orm.entity_manager + - "@security.token_storage" + - "@session" + - "@doctrine.orm.entity_manager" - %pocket_consumer_key% diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index bdd57e5e..fda21f2d 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -8,7 +8,7 @@
    {% trans %}Welcome on wallabag importer. Please select your previous service that you want to migrate.{% endtrans %}
    diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig index e6abc17b..df64e472 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -7,7 +7,7 @@
    {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %} -
    +
    -- cgit v1.2.3 From 7ec2897ee0ad190dcb9f77032d785f2f9661b754 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Thu, 24 Dec 2015 15:24:18 +0100 Subject: First test on PocketImport Giving ability to define the Client add abitliy to easliy test the import. --- composer.lock | 14 +- src/Wallabag/ImportBundle/Import/PocketImport.php | 151 ++++++++++----------- .../ImportBundle/Resources/config/services.yml | 11 ++ .../ImportBundle/Tests/Import/PocketImportTest.php | 117 ++++++++++++++++ 4 files changed, 209 insertions(+), 84 deletions(-) create mode 100644 src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php diff --git a/composer.lock b/composer.lock index a3ac7e8c..4cd8b034 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "7f1939f54201ee0e068eddde41454261", - "content-hash": "9b7801951c4ea69565ee8f4914071c25", + "hash": "fdba142656b2089b0e4cbddb45e2ad1f", + "content-hash": "a233f851c52683783b6a42be707c52b1", "packages": [ { "name": "behat/transliterator", @@ -2044,16 +2044,16 @@ }, { "name": "hoa/stream", - "version": "0.15.08.28", + "version": "0.15.10.26", "source": { "type": "git", "url": "https://github.com/hoaproject/Stream.git", - "reference": "cbd0f4749e447f4d31001e7c898f5e794c5861cb" + "reference": "011ab91d942f1d7096deade4c8a10fe57d51c5b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Stream/zipball/cbd0f4749e447f4d31001e7c898f5e794c5861cb", - "reference": "cbd0f4749e447f4d31001e7c898f5e794c5861cb", + "url": "https://api.github.com/repos/hoaproject/Stream/zipball/011ab91d942f1d7096deade4c8a10fe57d51c5b3", + "reference": "011ab91d942f1d7096deade4c8a10fe57d51c5b3", "shasum": "" }, "require": { @@ -2098,7 +2098,7 @@ "stream", "wrapper" ], - "time": "2015-08-28 07:31:43" + "time": "2015-10-22 06:30:43" }, { "name": "hoa/ustring", diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 85bab0db..e5c86f07 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -44,20 +44,83 @@ class PocketImport implements ImportInterface } /** - * Create a new Client. + * {@inheritdoc} + */ + public function oAuthRequest($redirectUri, $callbackUri) + { + $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', + [ + 'body' => json_encode([ + 'consumer_key' => $this->consumerKey, + 'redirect_uri' => $redirectUri, + ]), + ] + ); + + $response = $this->client->send($request); + $values = $response->json(); + + // store code in session for callback method + $this->session->set('pocketCode', $values['code']); + + return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; + } + + /** + * {@inheritdoc} + */ + public function oAuthAuthorize() + { + $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', + [ + 'body' => json_encode([ + 'consumer_key' => $this->consumerKey, + 'code' => $this->session->get('pocketCode'), + ]), + ] + ); + + $response = $this->client->send($request); + + return $response->json()['access_token']; + } + + /** + * {@inheritdoc} + */ + public function import($accessToken) + { + $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/get', + [ + 'body' => json_encode([ + 'consumer_key' => $this->consumerKey, + 'access_token' => $accessToken, + 'detailType' => 'complete', + 'state' => 'all', + 'sort' => 'oldest', + ]), + ] + ); + + $response = $this->client->send($request); + $entries = $response->json(); + + $this->parsePocketEntries($entries['list']); + + $this->session->getFlashBag()->add( + 'notice', + $this->importedEntries.' entries imported, '.$this->skippedEntries.' already saved.' + ); + } + + /** + * Set the Guzzle client. * - * @return Client + * @param Client $client */ - private function createClient() + public function setClient(Client $client) { - return new Client([ - 'defaults' => [ - 'headers' => [ - 'content-type' => 'application/json', - 'X-Accept' => 'application/json', - ], - ], - ]); + $this->client = $client; } /** @@ -165,70 +228,4 @@ class PocketImport implements ImportInterface $this->em->flush(); } - - public function oAuthRequest($redirectUri, $callbackUri) - { - $client = $this->createClient(); - $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', - [ - 'body' => json_encode([ - 'consumer_key' => $this->consumerKey, - 'redirect_uri' => $redirectUri, - ]), - ] - ); - - $response = $client->send($request); - $values = $response->json(); - - // store code in session for callback method - $this->session->set('pocketCode', $values['code']); - - return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; - } - - public function oAuthAuthorize() - { - $client = $this->createClient(); - - $request = $client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', - [ - 'body' => json_encode([ - 'consumer_key' => $this->consumerKey, - 'code' => $this->session->get('pocketCode'), - ]), - ] - ); - - $response = $client->send($request); - - return $response->json()['access_token']; - } - - public function import($accessToken) - { - $client = $this->createClient(); - - $request = $client->createRequest('POST', 'https://getpocket.com/v3/get', - [ - 'body' => json_encode([ - 'consumer_key' => $this->consumerKey, - 'access_token' => $accessToken, - 'detailType' => 'complete', - 'state' => 'all', - 'sort' => 'oldest', - ]), - ] - ); - - $response = $client->send($request); - $entries = $response->json(); - - $this->parsePocketEntries($entries['list']); - - $this->session->getFlashBag()->add( - 'notice', - $this->importedEntries.' entries imported, '.$this->skippedEntries.' already saved.' - ); - } } diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index d77779eb..ab516ca5 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -6,3 +6,14 @@ services: - "@session" - "@doctrine.orm.entity_manager" - %pocket_consumer_key% + calls: + - [ setClient, [ "@wallabag_import.pocket.client" ] ] + + wallabag_import.pocket.client: + class: GuzzleHttp\Client + arguments: + - + defaults: + headers: + content-type: "application/json" + X-Accept: "application/json" diff --git a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php new file mode 100644 index 00000000..4c718fa3 --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php @@ -0,0 +1,117 @@ +user = new User(); + + $this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface') + ->disableOriginalConstructor() + ->getMock(); + + $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface') + ->disableOriginalConstructor() + ->getMock(); + + $token->expects($this->once()) + ->method('getUser') + ->willReturn($this->user); + + $this->tokenStorage->expects($this->once()) + ->method('getToken') + ->willReturn($token); + + $this->session = new Session(new MockArraySessionStorage()); + + $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + + return new PocketImport( + $this->tokenStorage, + $this->session, + $this->em, + $consumerKey + ); + } + + public function testInit() + { + $pocketImport = $this->getPocketImport(); + + $this->assertEquals('Pocket', $pocketImport->getName()); + $this->assertEquals('This importer will import all your Pocket data.', $pocketImport->getDescription()); + } + + public function testOAuthRequest() + { + $client = new Client(); + + $mock = new Mock([ + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['code' => 'wunderbar']))), + ]); + + $client->getEmitter()->attach($mock); + + $pocketImport = $this->getPocketImport(); + $pocketImport->setClient($client); + + $url = $pocketImport->oAuthRequest('http://0.0.0.0./redirect', 'http://0.0.0.0./callback'); + + $this->assertEquals('https://getpocket.com/auth/authorize?request_token=wunderbar&redirect_uri=http://0.0.0.0./callback', $url); + $this->assertEquals('wunderbar', $this->session->get('pocketCode')); + } + + public function testOAuthAuthorize() + { + $client = new Client(); + + $mock = new Mock([ + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar']))), + ]); + + $client->getEmitter()->attach($mock); + + $pocketImport = $this->getPocketImport(); + $pocketImport->setClient($client); + + $accessToken = $pocketImport->oAuthAuthorize(); + + $this->assertEquals('wunderbar', $accessToken); + } + + public function testImport() + { + $client = new Client(); + + $mock = new Mock([ + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['list' => []]))), + ]); + + $client->getEmitter()->attach($mock); + + $pocketImport = $this->getPocketImport(); + $pocketImport->setClient($client); + + $pocketImport->import('wunderbar'); + + $this->assertEquals('0 entries imported, 0 already saved.', $this->session->getFlashBag()->get('notice')[0]); + } +} -- cgit v1.2.3 From 77a7752a592af9ac821621a34d9955533baf40a0 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Wed, 30 Dec 2015 10:06:45 +0100 Subject: Update after previous merge PR #1443 was merged into this branch to handle all import type in the same place. --- app/config/config.yml | 5 +- src/Wallabag/CoreBundle/Command/ImportCommand.php | 124 --------------------- .../CoreBundle/Controller/ImportController.php | 64 ----------- .../DependencyInjection/Configuration.php | 13 --- .../DependencyInjection/WallabagCoreExtension.php | 1 - .../CoreBundle/Form/Type/UploadImportType.php | 29 ----- .../views/themes/material/Import/index.html.twig | 30 ----- .../ImportBundle/Command/ImportCommand.php | 124 +++++++++++++++++++++ .../ImportBundle/Controller/ImportController.php | 48 +++++++- .../DependencyInjection/Configuration.php | 8 ++ .../WallabagImportExtension.php | 1 + .../ImportBundle/Form/Type/UploadImportType.php | 29 +++++ .../Resources/views/Import/index.html.twig | 26 +++++ 13 files changed, 237 insertions(+), 265 deletions(-) delete mode 100644 src/Wallabag/CoreBundle/Command/ImportCommand.php delete mode 100644 src/Wallabag/CoreBundle/Controller/ImportController.php delete mode 100644 src/Wallabag/CoreBundle/Form/Type/UploadImportType.php delete mode 100644 src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig create mode 100644 src/Wallabag/ImportBundle/Command/ImportCommand.php create mode 100644 src/Wallabag/ImportBundle/Form/Type/UploadImportType.php diff --git a/app/config/config.yml b/app/config/config.yml index 421b2db5..4d04d002 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -30,8 +30,9 @@ wallabag_core: en: 'English' fr: 'Français' de: 'Deutsch' - import: - allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] + +wallabag_import: + allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] # Twig Configuration twig: diff --git a/src/Wallabag/CoreBundle/Command/ImportCommand.php b/src/Wallabag/CoreBundle/Command/ImportCommand.php deleted file mode 100644 index 6be6f5e1..00000000 --- a/src/Wallabag/CoreBundle/Command/ImportCommand.php +++ /dev/null @@ -1,124 +0,0 @@ -setName('wallabag:import') - ->setDescription('Import entries from JSON file') - ->addArgument( - 'userId', - InputArgument::REQUIRED, - 'user ID to populate' - ); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $now = new \DateTime(); - $output->writeln('Start : '.$now->format('d-m-Y G:i:s').' ---'); - - // Importing CSV on DB via Doctrine ORM - $this->import($input, $output); - - $now = new \DateTime(); - $output->writeln('End : '.$now->format('d-m-Y G:i:s').' ---'); - } - - protected function import(InputInterface $input, OutputInterface $output) - { - // Getting php array of data from CSV - $data = $this->get($input, $output); - - $em = $this->getContainer()->get('doctrine')->getManager(); - // Turning off doctrine default logs queries for saving memory - $em->getConnection()->getConfiguration()->setSQLLogger(null); - - // Define the size of record, the frequency for persisting the data and the current index of records - $size = count($data); - $batchSize = 20; - $i = 1; - - $user = $em->getRepository('WallabagUserBundle:User') - ->findOneById($input->getArgument('userId')); - - if (!is_object($user)) { - throw new Exception('User not found'); - } - - $progress = new ProgressBar($output, $size); - $progress->start(); - - foreach ($data as $object) { - $array = (array) $object; - $entry = $em->getRepository('WallabagCoreBundle:Entry') - ->findOneByUrl($array['url']); - - if (!is_object($entry)) { - $entry = new Entry($user); - $entry->setUrl($array['url']); - } - - $entry->setTitle($array['title']); - $entry->setArchived($array['is_read']); - $entry->setStarred($array['is_fav']); - $entry->setContent($array['content']); - $entry->setReadingTime(Utils::getReadingTime($array['content'])); - - $em->persist($entry); - - if (($i % $batchSize) === 0) { - $em->flush(); - $progress->advance($batchSize); - - $now = new \DateTime(); - $output->writeln(' of entries imported ... | '.$now->format('d-m-Y G:i:s')); - } - ++$i; - } - - $em->flush(); - $em->clear(); - $progress->finish(); - } - - protected function convert($filename) - { - if (!file_exists($filename) || !is_readable($filename)) { - return false; - } - - $header = null; - $data = array(); - - if (($handle = fopen($filename, 'r')) !== false) { - while (($row = fgets($handle)) !== false) { - $data = json_decode($row); - } - fclose($handle); - } - - return $data; - } - - protected function get(InputInterface $input, OutputInterface $output) - { - $filename = __DIR__.'/../../../../web/uploads/import/'.$input->getArgument('userId').'.json'; - - $data = $this->convert($filename); - - return $data; - } -} diff --git a/src/Wallabag/CoreBundle/Controller/ImportController.php b/src/Wallabag/CoreBundle/Controller/ImportController.php deleted file mode 100644 index 33087710..00000000 --- a/src/Wallabag/CoreBundle/Controller/ImportController.php +++ /dev/null @@ -1,64 +0,0 @@ -createForm(new UploadImportType()); - $importForm->handleRequest($request); - $user = $this->getUser(); - $importConfig = $this->container->getParameter('wallabag_core.import'); - - if ($importForm->isValid()) { - $file = $importForm->get('file')->getData(); - $name = $user->getId().'.json'; - $dir = __DIR__.'/../../../../web/uploads/import'; - - if (in_array($file->getMimeType(), $importConfig['allow_mimetypes']) && $file->move($dir, $name)) { - $command = new ImportCommand(); - $command->setContainer($this->container); - $input = new ArrayInput(array('userId' => $user->getId())); - $return = $command->run($input, new NullOutput()); - - if ($return == 0) { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Import successful' - ); - } else { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Import failed' - ); - } - - return $this->redirect('/'); - } else { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Error while processing import. Please verify your import file.' - ); - } - } - - return $this->render('WallabagCoreBundle:Import:index.html.twig', array( - 'form' => array( - 'import' => $importForm->createView(), ), - )); - } -} diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php index fb1941b8..32acd1f1 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php @@ -4,7 +4,6 @@ namespace Wallabag\CoreBundle\DependencyInjection; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; -use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; class Configuration implements ConfigurationInterface { @@ -18,21 +17,9 @@ class Configuration implements ConfigurationInterface ->arrayNode('languages') ->prototype('scalar')->end() ->end() - ->arrayNode('import') - ->append($this->getAllowMimetypes()) - ->end() ->end() ; return $treeBuilder; } - - private function getAllowMimetypes() - { - $node = new ArrayNodeDefinition('allow_mimetypes'); - - $node->prototype('scalar')->end(); - - return $node; - } } diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php index e2a3ad55..330cc957 100644 --- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php +++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php @@ -14,7 +14,6 @@ class WallabagCoreExtension extends Extension $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); $container->setParameter('wallabag_core.languages', $config['languages']); - $container->setParameter('wallabag_core.import', $config['import']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Wallabag/CoreBundle/Form/Type/UploadImportType.php b/src/Wallabag/CoreBundle/Form/Type/UploadImportType.php deleted file mode 100644 index b9a9c465..00000000 --- a/src/Wallabag/CoreBundle/Form/Type/UploadImportType.php +++ /dev/null @@ -1,29 +0,0 @@ -add('file', 'file') - ->add('save', 'submit') - ; - } - - public function getDefaultOptions(array $options) - { - return array( - 'csrf_protection' => false, - ); - } - - public function getName() - { - return 'upload_import_file'; - } -} diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig deleted file mode 100644 index 47004144..00000000 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Import/index.html.twig +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "WallabagCoreBundle::layout.html.twig" %} - -{% block title %}{% trans %}import{% endtrans %}{% endblock %} - -{% block content %} -
    -
    -
    -
    -
    -
    - {{ form_errors(form.import) }} -
    -
    -

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    - {{ form_errors(form.import.file) }} - {{ form_widget(form.import.file) }} -
    -
    - - -
    -
    -
    -
    -
    -
    -{% endblock %} diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php new file mode 100644 index 00000000..3fb8927d --- /dev/null +++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php @@ -0,0 +1,124 @@ +setName('wallabag:import') + ->setDescription('Import entries from JSON file') + ->addArgument( + 'userId', + InputArgument::REQUIRED, + 'user ID to populate' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $now = new \DateTime(); + $output->writeln('Start : '.$now->format('d-m-Y G:i:s').' ---'); + + // Importing CSV on DB via Doctrine ORM + $this->import($input, $output); + + $now = new \DateTime(); + $output->writeln('End : '.$now->format('d-m-Y G:i:s').' ---'); + } + + protected function import(InputInterface $input, OutputInterface $output) + { + // Getting php array of data from CSV + $data = $this->get($input, $output); + + $em = $this->getContainer()->get('doctrine')->getManager(); + // Turning off doctrine default logs queries for saving memory + $em->getConnection()->getConfiguration()->setSQLLogger(null); + + // Define the size of record, the frequency for persisting the data and the current index of records + $size = count($data); + $batchSize = 20; + $i = 1; + + $user = $em->getRepository('WallabagUserBundle:User') + ->findOneById($input->getArgument('userId')); + + if (!is_object($user)) { + throw new Exception('User not found'); + } + + $progress = new ProgressBar($output, $size); + $progress->start(); + + foreach ($data as $object) { + $array = (array) $object; + $entry = $em->getRepository('WallabagCoreBundle:Entry') + ->findOneByUrl($array['url']); + + if (!is_object($entry)) { + $entry = new Entry($user); + $entry->setUrl($array['url']); + } + + $entry->setTitle($array['title']); + $entry->setArchived($array['is_read']); + $entry->setStarred($array['is_fav']); + $entry->setContent($array['content']); + $entry->setReadingTime(Utils::getReadingTime($array['content'])); + + $em->persist($entry); + + if (($i % $batchSize) === 0) { + $em->flush(); + $progress->advance($batchSize); + + $now = new \DateTime(); + $output->writeln(' of entries imported ... | '.$now->format('d-m-Y G:i:s')); + } + ++$i; + } + + $em->flush(); + $em->clear(); + $progress->finish(); + } + + protected function convert($filename) + { + if (!file_exists($filename) || !is_readable($filename)) { + return false; + } + + $header = null; + $data = array(); + + if (($handle = fopen($filename, 'r')) !== false) { + while (($row = fgets($handle)) !== false) { + $data = json_decode($row); + } + fclose($handle); + } + + return $data; + } + + protected function get(InputInterface $input, OutputInterface $output) + { + $filename = __DIR__.'/../../../../web/uploads/import/'.$input->getArgument('userId').'.json'; + + $data = $this->convert($filename); + + return $data; + } +} diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php index 3569793b..6ebd6a0a 100644 --- a/src/Wallabag/ImportBundle/Controller/ImportController.php +++ b/src/Wallabag/ImportBundle/Controller/ImportController.php @@ -4,14 +4,58 @@ namespace Wallabag\ImportBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\HttpFoundation\Request; +use Wallabag\ImportBundle\Command\ImportCommand; +use Wallabag\ImportBundle\Form\Type\UploadImportType; class ImportController extends Controller { /** * @Route("/import", name="import") */ - public function importAction() + public function importAction(Request $request) { - return $this->render('WallabagImportBundle:Import:index.html.twig', array()); + $importForm = $this->createForm(new UploadImportType()); + $importForm->handleRequest($request); + $user = $this->getUser(); + + if ($importForm->isValid()) { + $file = $importForm->get('file')->getData(); + $name = $user->getId().'.json'; + $dir = __DIR__.'/../../../../web/uploads/import'; + + if (in_array($file->getMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($dir, $name)) { + $command = new ImportCommand(); + $command->setContainer($this->container); + $input = new ArrayInput(array('userId' => $user->getId())); + $return = $command->run($input, new NullOutput()); + + if ($return == 0) { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Import successful' + ); + } else { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Import failed' + ); + } + + return $this->redirect('/'); + } else { + $this->get('session')->getFlashBag()->add( + 'notice', + 'Error while processing import. Please verify your import file.' + ); + } + } + + return $this->render('WallabagImportBundle:Import:index.html.twig', array( + 'form' => array( + 'import' => $importForm->createView(), ), + )); } } diff --git a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php index bacaff31..2ef35463 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php @@ -12,6 +12,14 @@ class Configuration implements ConfigurationInterface $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('wallabag_import'); + $rootNode + ->children() + ->arrayNode('allow_mimetypes') + ->prototype('scalar')->end() + ->end() + ->end() + ; + return $treeBuilder; } } diff --git a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php index 4efcaace..38163886 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php @@ -13,6 +13,7 @@ class WallabagImportExtension extends Extension { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); + $container->setParameter('wallabag_import.allow_mimetypes', $config['allow_mimetypes']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php b/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php new file mode 100644 index 00000000..5d894318 --- /dev/null +++ b/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php @@ -0,0 +1,29 @@ +add('file', 'file') + ->add('save', 'submit') + ; + } + + public function getDefaultOptions(array $options) + { + return array( + 'csrf_protection' => false, + ); + } + + public function getName() + { + return 'upload_import_file'; + } +} diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index fda21f2d..ee759a52 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -13,4 +13,30 @@
    + + +
    +
    +
    +
    +
    +
    + {{ form_errors(form.import) }} +
    +
    +

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    + {{ form_errors(form.import.file) }} + {{ form_widget(form.import.file) }} +
    +
    + + +
    +
    +
    +
    +
    +
    {% endblock %} -- cgit v1.2.3 From b4b592a0c0ee356e81775baf8f9976288d7b686c Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Wed, 30 Dec 2015 12:19:15 +0100 Subject: Fix the way to check for an existing entry Instead of requiring more than 1 entry (> 1) we have to check for at least one entry (> 0) --- src/Wallabag/CoreBundle/Repository/EntryRepository.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index b8e22eb8..c6763a40 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php @@ -242,8 +242,8 @@ class EntryRepository extends EntityRepository ->getQuery() ->getResult(); - if (count($res) > 1) { - return next($res); + if (count($res)) { + return current($res); } return false; -- cgit v1.2.3 From 252ebd60719d32ec954d0519c9edf2b52b03310c Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Wed, 30 Dec 2015 12:23:51 +0100 Subject: Rewrote Pocket Import For the moment, we won't do a queue system, just a plain synchronous import. We also use ContentProxy to grab content for each article from Pocket. Error from Pocket are now logged using the logger. The ImportInterface need to be simple and not related to oAuth (not all import will use that method). --- src/Wallabag/CoreBundle/Tools/Utils.php | 12 +- .../ImportBundle/Controller/ImportController.php | 48 +---- .../ImportBundle/Controller/PocketController.php | 45 ++-- .../ImportBundle/Import/ImportInterface.php | 29 +-- src/Wallabag/ImportBundle/Import/PocketImport.php | 154 ++++++++------ .../ImportBundle/Resources/config/services.yml | 21 +- .../Resources/views/Import/index.html.twig | 28 +-- .../Resources/views/Pocket/index.html.twig | 2 +- .../ImportBundle/Tests/Import/PocketImportTest.php | 228 +++++++++++++++++++-- 9 files changed, 357 insertions(+), 210 deletions(-) diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php index b501ce65..a16baca9 100644 --- a/src/Wallabag/CoreBundle/Tools/Utils.php +++ b/src/Wallabag/CoreBundle/Tools/Utils.php @@ -26,16 +26,6 @@ class Utils return str_replace(array('+', '/'), '', $token); } - /** - * @param $words - * - * @return float - */ - public static function convertWordsToMinutes($words) - { - return floor($words / 200); - } - /** * For a given text, we calculate reading time for an article * based on 200 words per minute. @@ -46,6 +36,6 @@ class Utils */ public static function getReadingTime($text) { - return self::convertWordsToMinutes(str_word_count(strip_tags($text))); + return floor(str_word_count(strip_tags($text)) / 200); } } diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php index 6ebd6a0a..2a0d6ab5 100644 --- a/src/Wallabag/ImportBundle/Controller/ImportController.php +++ b/src/Wallabag/ImportBundle/Controller/ImportController.php @@ -4,58 +4,14 @@ namespace Wallabag\ImportBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; -use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\HttpFoundation\Request; -use Wallabag\ImportBundle\Command\ImportCommand; -use Wallabag\ImportBundle\Form\Type\UploadImportType; class ImportController extends Controller { /** * @Route("/import", name="import") */ - public function importAction(Request $request) + public function importAction() { - $importForm = $this->createForm(new UploadImportType()); - $importForm->handleRequest($request); - $user = $this->getUser(); - - if ($importForm->isValid()) { - $file = $importForm->get('file')->getData(); - $name = $user->getId().'.json'; - $dir = __DIR__.'/../../../../web/uploads/import'; - - if (in_array($file->getMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($dir, $name)) { - $command = new ImportCommand(); - $command->setContainer($this->container); - $input = new ArrayInput(array('userId' => $user->getId())); - $return = $command->run($input, new NullOutput()); - - if ($return == 0) { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Import successful' - ); - } else { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Import failed' - ); - } - - return $this->redirect('/'); - } else { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Error while processing import. Please verify your import file.' - ); - } - } - - return $this->render('WallabagImportBundle:Import:index.html.twig', array( - 'form' => array( - 'import' => $importForm->createView(), ), - )); + return $this->render('WallabagImportBundle:Import:index.html.twig', []); } } diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index 2ab062e7..61eeba43 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -8,35 +8,56 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class PocketController extends Controller { /** - * @Route("/import/pocket", name="pocket_import") + * @Route("/import/pocket", name="import_pocket") */ public function indexAction() { - return $this->render('WallabagImportBundle:Pocket:index.html.twig', array()); + return $this->render('WallabagImportBundle:Pocket:index.html.twig', []); } /** - * @Route("/import/pocket/auth", name="pocket_auth") + * @Route("/import/pocket/auth", name="import_pocket_auth") */ public function authAction() { - $pocket = $this->get('wallabag_import.pocket.import'); - $authUrl = $pocket->oAuthRequest( - $this->generateUrl('import', array(), true), - $this->generateUrl('pocket_callback', array(), true) - ); + $requestToken = $this->get('wallabag_import.pocket.import') + ->getRequestToken($this->generateUrl('import', [], true)); + + $this->get('session')->set('import.pocket.code', $requestToken); - return $this->redirect($authUrl, 301); + return $this->redirect( + 'https://getpocket.com/auth/authorize?request_token='.$requestToken.'&redirect_uri='.$this->generateUrl('import_pocket_callback', [], true), + 301 + ); } /** - * @Route("/import/pocket/callback", name="pocket_callback") + * @Route("/import/pocket/callback", name="import_pocket_callback") */ public function callbackAction() { + $message = 'Import failed, please try again.'; $pocket = $this->get('wallabag_import.pocket.import'); - $accessToken = $pocket->oAuthAuthorize(); - $pocket->import($accessToken); + + // something bad happend on pocket side + if (false === $pocket->authorize($this->get('session')->get('import.pocket.code'))) { + $this->get('session')->getFlashBag()->add( + 'notice', + $message + ); + + return $this->redirect($this->generateUrl('import_pocket')); + } + + if (true === $pocket->import()) { + $summary = $pocket->getSummary(); + $message = $summary['imported'].' entrie(s) imported, '.$summary['skipped'].' already saved.'; + } + + $this->get('session')->getFlashBag()->add( + 'notice', + $message + ); return $this->redirect($this->generateUrl('homepage')); } diff --git a/src/Wallabag/ImportBundle/Import/ImportInterface.php b/src/Wallabag/ImportBundle/Import/ImportInterface.php index 0f9b3256..8cf238aa 100644 --- a/src/Wallabag/ImportBundle/Import/ImportInterface.php +++ b/src/Wallabag/ImportBundle/Import/ImportInterface.php @@ -2,7 +2,9 @@ namespace Wallabag\ImportBundle\Import; -interface ImportInterface +use Psr\Log\LoggerAwareInterface; + +interface ImportInterface extends LoggerAwareInterface { /** * Name of the import. @@ -19,27 +21,18 @@ interface ImportInterface public function getDescription(); /** - * Return the oauth url to authenticate the client. - * - * @param string $redirectUri Redirect url in case of error - * @param string $callbackUri Url when the authentication is complete - * - * @return string - */ - public function oAuthRequest($redirectUri, $callbackUri); - - /** - * Usually called by the previous callback to authorize the client. - * Then it return a token that can be used for next requests. + * Import content using the user token. * - * @return string + * @return bool */ - public function oAuthAuthorize(); + public function import(); /** - * Import content using the user token. + * Return an array with summary info about the import, with keys: + * - skipped + * - imported. * - * @param string $accessToken User access token + * @return array */ - public function import($accessToken); + public function getSummary(); } diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index e5c86f07..1710d9d3 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -2,29 +2,39 @@ namespace Wallabag\ImportBundle\Import; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use Doctrine\ORM\EntityManager; use GuzzleHttp\Client; -use Symfony\Component\HttpFoundation\Session\Session; +use GuzzleHttp\Exception\RequestException; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Wallabag\CoreBundle\Entity\Entry; use Wallabag\CoreBundle\Entity\Tag; -use Wallabag\CoreBundle\Tools\Utils; +use Wallabag\CoreBundle\Helper\ContentProxy; class PocketImport implements ImportInterface { private $user; - private $session; private $em; + private $contentProxy; + private $logger; private $consumerKey; private $skippedEntries = 0; private $importedEntries = 0; + protected $accessToken; - public function __construct(TokenStorageInterface $tokenStorage, Session $session, EntityManager $em, $consumerKey) + public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, $consumerKey) { $this->user = $tokenStorage->getToken()->getUser(); - $this->session = $session; $this->em = $em; + $this->contentProxy = $contentProxy; $this->consumerKey = $consumerKey; + $this->logger = new NullLogger(); + } + + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; } /** @@ -44,9 +54,13 @@ class PocketImport implements ImportInterface } /** - * {@inheritdoc} + * Return the oauth url to authenticate the client. + * + * @param string $redirectUri Redirect url in case of error + * + * @return string request_token for callback method */ - public function oAuthRequest($redirectUri, $callbackUri) + public function getRequestToken($redirectUri) { $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/request', [ @@ -57,44 +71,59 @@ class PocketImport implements ImportInterface ] ); - $response = $this->client->send($request); - $values = $response->json(); + try { + $response = $this->client->send($request); + } catch (RequestException $e) { + $this->logger->error(sprintf('PocketImport: Failed to request token: %s', $e->getMessage()), ['exception' => $e]); - // store code in session for callback method - $this->session->set('pocketCode', $values['code']); + return false; + } - return 'https://getpocket.com/auth/authorize?request_token='.$values['code'].'&redirect_uri='.$callbackUri; + return $response->json()['code']; } /** - * {@inheritdoc} + * Usually called by the previous callback to authorize the client. + * Then it return a token that can be used for next requests. + * + * @param string $code request_token from getRequestToken + * + * @return bool */ - public function oAuthAuthorize() + public function authorize($code) { $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/oauth/authorize', [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, - 'code' => $this->session->get('pocketCode'), + 'code' => $code, ]), ] ); - $response = $this->client->send($request); + try { + $response = $this->client->send($request); + } catch (RequestException $e) { + $this->logger->error(sprintf('PocketImport: Failed to authorize client: %s', $e->getMessage()), ['exception' => $e]); - return $response->json()['access_token']; + return false; + } + + $this->accessToken = $response->json()['access_token']; + + return true; } /** * {@inheritdoc} */ - public function import($accessToken) + public function import() { $request = $this->client->createRequest('POST', 'https://getpocket.com/v3/get', [ 'body' => json_encode([ 'consumer_key' => $this->consumerKey, - 'access_token' => $accessToken, + 'access_token' => $this->accessToken, 'detailType' => 'complete', 'state' => 'all', 'sort' => 'oldest', @@ -102,61 +131,45 @@ class PocketImport implements ImportInterface ] ); - $response = $this->client->send($request); + try { + $response = $this->client->send($request); + } catch (RequestException $e) { + $this->logger->error(sprintf('PocketImport: Failed to import: %s', $e->getMessage()), ['exception' => $e]); + + return false; + } + $entries = $response->json(); $this->parsePocketEntries($entries['list']); - $this->session->getFlashBag()->add( - 'notice', - $this->importedEntries.' entries imported, '.$this->skippedEntries.' already saved.' - ); + return true; } /** - * Set the Guzzle client. - * - * @param Client $client + * {@inheritdoc} */ - public function setClient(Client $client) + public function getSummary() { - $this->client = $client; + return [ + 'skipped' => $this->skippedEntries, + 'imported' => $this->importedEntries, + ]; } /** - * Returns the good title for current entry. - * - * @param $pocketEntry + * Set the Guzzle client. * - * @return string + * @param Client $client */ - private function guessTitle($pocketEntry) + public function setClient(Client $client) { - if (isset($pocketEntry['resolved_title']) && $pocketEntry['resolved_title'] != '') { - return $pocketEntry['resolved_title']; - } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') { - return $pocketEntry['given_title']; - } - - return 'Untitled'; + $this->client = $client; } /** - * Returns the good URL for current entry. - * - * @param $pocketEntry - * - * @return string + * @todo move that in a more global place */ - private function guessURL($pocketEntry) - { - if (isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '') { - return $pocketEntry['resolved_url']; - } - - return $pocketEntry['given_url']; - } - private function assignTagsToEntry(Entry $entry, $tags) { foreach ($tags as $tag) { @@ -177,13 +190,16 @@ class PocketImport implements ImportInterface } /** + * @see https://getpocket.com/developer/docs/v3/retrieve + * * @param $entries */ private function parsePocketEntries($entries) { foreach ($entries as $pocketEntry) { $entry = new Entry($this->user); - $url = $this->guessURL($pocketEntry); + + $url = isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '' ? $pocketEntry['resolved_url'] : $pocketEntry['given_url']; $existingEntry = $this->em ->getRepository('WallabagCoreBundle:Entry') @@ -194,31 +210,33 @@ class PocketImport implements ImportInterface continue; } - $entry->setUrl($url); - $entry->setDomainName(parse_url($url, PHP_URL_HOST)); + $entry = $this->contentProxy->updateEntry($entry, $url); + // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted if ($pocketEntry['status'] == 1) { $entry->setArchived(true); } + + // 0 or 1 - 1 If the item is favorited if ($pocketEntry['favorite'] == 1) { $entry->setStarred(true); } - $entry->setTitle($this->guessTitle($pocketEntry)); - - if (isset($pocketEntry['excerpt'])) { - $entry->setContent($pocketEntry['excerpt']); + $title = 'Untitled'; + if (isset($pocketEntry['resolved_title']) && $pocketEntry['resolved_title'] != '') { + $title = $pocketEntry['resolved_title']; + } elseif (isset($pocketEntry['given_title']) && $pocketEntry['given_title'] != '') { + $title = $pocketEntry['given_title']; } - if (isset($pocketEntry['has_image']) && $pocketEntry['has_image'] > 0) { - $entry->setPreviewPicture($pocketEntry['image']['src']); - } + $entry->setTitle($title); - if (isset($pocketEntry['word_count'])) { - $entry->setReadingTime(Utils::convertWordsToMinutes($pocketEntry['word_count'])); + // 0, 1, or 2 - 1 if the item has images in it - 2 if the item is an image + if (isset($pocketEntry['has_image']) && $pocketEntry['has_image'] > 0 && isset($pocketEntry['images'][1])) { + $entry->setPreviewPicture($pocketEntry['images'][1]['src']); } - if (!empty($pocketEntry['tags'])) { + if (isset($pocketEntry['tags']) && !empty($pocketEntry['tags'])) { $this->assignTagsToEntry($entry, $pocketEntry['tags']); } diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index ab516ca5..f421821c 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -1,14 +1,4 @@ services: - wallabag_import.pocket.import: - class: Wallabag\ImportBundle\Import\PocketImport - arguments: - - "@security.token_storage" - - "@session" - - "@doctrine.orm.entity_manager" - - %pocket_consumer_key% - calls: - - [ setClient, [ "@wallabag_import.pocket.client" ] ] - wallabag_import.pocket.client: class: GuzzleHttp\Client arguments: @@ -17,3 +7,14 @@ services: headers: content-type: "application/json" X-Accept: "application/json" + + wallabag_import.pocket.import: + class: Wallabag\ImportBundle\Import\PocketImport + arguments: + - "@security.token_storage" + - "@doctrine.orm.entity_manager" + - "@wallabag_core.content_proxy" + - %pocket_consumer_key% + calls: + - [ setClient, [ "@wallabag_import.pocket.client" ] ] + - [ setLogger, [ "@logger" ]] diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index ee759a52..b068283a 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -8,35 +8,9 @@
    {% trans %}Welcome on wallabag importer. Please select your previous service that you want to migrate.{% endtrans %}
    - - -
    -
    -
    -
    -
    -
    - {{ form_errors(form.import) }} -
    -
    -

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    - {{ form_errors(form.import.file) }} - {{ form_widget(form.import.file) }} -
    -
    - - -
    -
    -
    -
    -
    -
    {% endblock %} diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig index df64e472..940fe4cc 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -7,7 +7,7 @@
    {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %} -
    +
    diff --git a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php index 4c718fa3..cf706fa9 100644 --- a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php +++ b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php @@ -4,19 +4,28 @@ namespace Wallabag\ImportBundle\Tests\Import; use Wallabag\UserBundle\Entity\User; use Wallabag\ImportBundle\Import\PocketImport; -use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use GuzzleHttp\Client; use GuzzleHttp\Subscriber\Mock; use GuzzleHttp\Message\Response; use GuzzleHttp\Stream\Stream; +use Monolog\Logger; +use Monolog\Handler\TestHandler; + +class PocketImportMock extends PocketImport +{ + public function getAccessToken() + { + return $this->accessToken; + } +} class PocketImportTest extends \PHPUnit_Framework_TestCase { protected $token; protected $user; - protected $session; protected $em; + protected $contentProxy; + protected $logHandler; private function getPocketImport($consumerKey = 'ConsumerKey') { @@ -30,6 +39,10 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); + $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy') + ->disableOriginalConstructor() + ->getMock(); + $token->expects($this->once()) ->method('getUser') ->willReturn($this->user); @@ -38,18 +51,22 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase ->method('getToken') ->willReturn($token); - $this->session = new Session(new MockArraySessionStorage()); - $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager') ->disableOriginalConstructor() ->getMock(); - return new PocketImport( + $pocket = new PocketImportMock( $this->tokenStorage, - $this->session, $this->em, + $this->contentProxy, $consumerKey ); + + $this->logHandler = new TestHandler(); + $logger = new Logger('test', array($this->logHandler)); + $pocket->setLogger($logger); + + return $pocket; } public function testInit() @@ -65,7 +82,7 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase $client = new Client(); $mock = new Mock([ - new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['code' => 'wunderbar']))), + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['code' => 'wunderbar_code']))), ]); $client->getEmitter()->attach($mock); @@ -73,10 +90,31 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase $pocketImport = $this->getPocketImport(); $pocketImport->setClient($client); - $url = $pocketImport->oAuthRequest('http://0.0.0.0./redirect', 'http://0.0.0.0./callback'); + $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect'); - $this->assertEquals('https://getpocket.com/auth/authorize?request_token=wunderbar&redirect_uri=http://0.0.0.0./callback', $url); - $this->assertEquals('wunderbar', $this->session->get('pocketCode')); + $this->assertEquals('wunderbar_code', $code); + } + + public function testOAuthRequestBadResponse() + { + $client = new Client(); + + $mock = new Mock([ + new Response(403), + ]); + + $client->getEmitter()->attach($mock); + + $pocketImport = $this->getPocketImport(); + $pocketImport->setClient($client); + + $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect'); + + $this->assertFalse($code); + + $records = $this->logHandler->getRecords(); + $this->assertContains('PocketImport: Failed to request token', $records[0]['message']); + $this->assertEquals('ERROR', $records[0]['level_name']); } public function testOAuthAuthorize() @@ -84,7 +122,7 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase $client = new Client(); $mock = new Mock([ - new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar']))), + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))), ]); $client->getEmitter()->attach($mock); @@ -92,26 +130,182 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase $pocketImport = $this->getPocketImport(); $pocketImport->setClient($client); - $accessToken = $pocketImport->oAuthAuthorize(); + $res = $pocketImport->authorize('wunderbar_code'); - $this->assertEquals('wunderbar', $accessToken); + $this->assertTrue($res); + $this->assertEquals('wunderbar_token', $pocketImport->getAccessToken()); } + public function testOAuthAuthorizeBadResponse() + { + $client = new Client(); + + $mock = new Mock([ + new Response(403), + ]); + + $client->getEmitter()->attach($mock); + + $pocketImport = $this->getPocketImport(); + $pocketImport->setClient($client); + + $res = $pocketImport->authorize('wunderbar_code'); + + $this->assertFalse($res); + + $records = $this->logHandler->getRecords(); + $this->assertContains('PocketImport: Failed to authorize client', $records[0]['message']); + $this->assertEquals('ERROR', $records[0]['level_name']); + } + + /** + * Will sample results from https://getpocket.com/developer/docs/v3/retrieve. + */ public function testImport() { $client = new Client(); $mock = new Mock([ - new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['list' => []]))), + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))), + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(' + { + "status": 1, + "list": { + "229279689": { + "item_id": "229279689", + "resolved_id": "229279689", + "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview", + "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland", + "favorite": "1", + "status": "1", + "resolved_title": "The Massive Ryder Cup Preview", + "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview", + "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.", + "is_article": "1", + "has_video": "1", + "has_image": "1", + "word_count": "3197", + "images": { + "1": { + "item_id": "229279689", + "image_id": "1", + "src": "http://a.espncdn.com/combiner/i?img=/photo/2012/0927/grant_g_ryder_cr_640.jpg&w=640&h=360", + "width": "0", + "height": "0", + "credit": "Jamie Squire/Getty Images", + "caption": "" + } + }, + "videos": { + "1": { + "item_id": "229279689", + "video_id": "1", + "src": "http://www.youtube.com/v/Er34PbFkVGk?version=3&hl=en_US&rel=0", + "width": "420", + "height": "315", + "type": "1", + "vid": "Er34PbFkVGk" + } + }, + "tags": { + "grantland": { + "item_id": "1147652870", + "tag": "grantland" + }, + "Ryder Cup": { + "item_id": "1147652870", + "tag": "Ryder Cup" + } + } + }, + "229279690": { + "item_id": "229279689", + "resolved_id": "229279689", + "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview", + "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland", + "favorite": "1", + "status": "1", + "resolved_title": "The Massive Ryder Cup Preview", + "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview", + "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.", + "is_article": "1", + "has_video": "0", + "has_image": "0", + "word_count": "3197" + } + } + } + ')), + ]); + + $client->getEmitter()->attach($mock); + + $pocketImport = $this->getPocketImport(); + + $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository') + ->disableOriginalConstructor() + ->getMock(); + + $entryRepo->expects($this->exactly(2)) + ->method('existByUrlAndUserId') + ->will($this->onConsecutiveCalls(false, true)); + + $tag = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Tag') + ->disableOriginalConstructor() + ->getMock(); + + $tagRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\TagRepository') + ->disableOriginalConstructor() + ->getMock(); + + $tagRepo->expects($this->exactly(2)) + ->method('findOneByLabelAndUserId') + ->will($this->onConsecutiveCalls(false, $tag)); + + $this->em + ->expects($this->any()) + ->method('getRepository') + ->will($this->onConsecutiveCalls($entryRepo, $tagRepo, $tagRepo, $entryRepo)); + + $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry') + ->disableOriginalConstructor() + ->getMock(); + + $this->contentProxy + ->expects($this->once()) + ->method('updateEntry') + ->willReturn($entry); + + $pocketImport->setClient($client); + $pocketImport->authorize('wunderbar_code'); + + $res = $pocketImport->import(); + + $this->assertTrue($res); + $this->assertEquals(['skipped' => 1, 'imported' => 1], $pocketImport->getSummary()); + } + + public function testImportBadResponse() + { + $client = new Client(); + + $mock = new Mock([ + new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))), + new Response(403), ]); $client->getEmitter()->attach($mock); $pocketImport = $this->getPocketImport(); $pocketImport->setClient($client); + $pocketImport->authorize('wunderbar_code'); + + $res = $pocketImport->import(); - $pocketImport->import('wunderbar'); + $this->assertFalse($res); - $this->assertEquals('0 entries imported, 0 already saved.', $this->session->getFlashBag()->get('notice')[0]); + $records = $this->logHandler->getRecords(); + $this->assertContains('PocketImport: Failed to import', $records[0]['message']); + $this->assertEquals('ERROR', $records[0]['level_name']); } } -- cgit v1.2.3 From b1d05721cf37ab94ec1a6837fe79cf19474dd0ff Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Wed, 30 Dec 2015 13:26:30 +0100 Subject: Rewrote Wallabag v1 import --- app/config/config.yml | 1 + .../ImportBundle/Command/ImportCommand.php | 107 +++------------- .../ImportBundle/Controller/PocketController.php | 2 +- .../Controller/WallabagV1Controller.php | 58 +++++++++ .../DependencyInjection/Configuration.php | 2 + .../WallabagImportExtension.php | 1 + src/Wallabag/ImportBundle/Import/PocketImport.php | 7 +- .../ImportBundle/Import/WallabagV1Import.php | 137 +++++++++++++++++++++ .../ImportBundle/Resources/config/services.yml | 7 ++ .../Resources/views/Import/index.html.twig | 1 + .../Resources/views/WallabagV1/index.html.twig | 30 +++++ .../Tests/Import/WallabagV1ImportTest.php | 96 +++++++++++++++ .../ImportBundle/Tests/fixtures/wallabag-v1.json | 50 ++++++++ web/uploads/import/.gitkeep | 0 14 files changed, 405 insertions(+), 94 deletions(-) create mode 100644 src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php create mode 100644 src/Wallabag/ImportBundle/Import/WallabagV1Import.php create mode 100644 src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig create mode 100644 src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php create mode 100644 src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v1.json create mode 100644 web/uploads/import/.gitkeep diff --git a/app/config/config.yml b/app/config/config.yml index 4d04d002..e50f9b52 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -33,6 +33,7 @@ wallabag_core: wallabag_import: allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] + resource_dir: "%kernel.root_dir%/../web/uploads/import" # Twig Configuration twig: diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php index 3fb8927d..dfbfc2f7 100644 --- a/src/Wallabag/ImportBundle/Command/ImportCommand.php +++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php @@ -7,118 +7,47 @@ use Symfony\Component\Config\Definition\Exception\Exception; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Helper\ProgressBar; -use Wallabag\CoreBundle\Entity\Entry; -use Wallabag\CoreBundle\Tools\Utils; class ImportCommand extends ContainerAwareCommand { protected function configure() { $this - ->setName('wallabag:import') - ->setDescription('Import entries from JSON file') - ->addArgument( - 'userId', - InputArgument::REQUIRED, - 'user ID to populate' - ); + ->setName('wallabag:import-v1') + ->setDescription('Import entries from a JSON export from a wallabag v1 instance') + ->addArgument('userId', InputArgument::REQUIRED, 'User ID to populate') + ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') + ; } protected function execute(InputInterface $input, OutputInterface $output) { - $now = new \DateTime(); - $output->writeln('Start : '.$now->format('d-m-Y G:i:s').' ---'); - - // Importing CSV on DB via Doctrine ORM - $this->import($input, $output); - - $now = new \DateTime(); - $output->writeln('End : '.$now->format('d-m-Y G:i:s').' ---'); - } - - protected function import(InputInterface $input, OutputInterface $output) - { - // Getting php array of data from CSV - $data = $this->get($input, $output); + $output->writeln('Start : '.(new \DateTime())->format('d-m-Y G:i:s').' ---'); $em = $this->getContainer()->get('doctrine')->getManager(); // Turning off doctrine default logs queries for saving memory $em->getConnection()->getConfiguration()->setSQLLogger(null); - // Define the size of record, the frequency for persisting the data and the current index of records - $size = count($data); - $batchSize = 20; - $i = 1; - - $user = $em->getRepository('WallabagUserBundle:User') - ->findOneById($input->getArgument('userId')); + $user = $em->getRepository('WallabagUserBundle:User')->findOneById($input->getArgument('userId')); if (!is_object($user)) { - throw new Exception('User not found'); + throw new Exception(sprintf('User with id "%s" not found', $input->getArgument('userId'))); } - $progress = new ProgressBar($output, $size); - $progress->start(); + $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v1.import'); + $res = $wallabag + ->setUser($user) + ->setFilepath($input->getArgument('filepath')) + ->import(); - foreach ($data as $object) { - $array = (array) $object; - $entry = $em->getRepository('WallabagCoreBundle:Entry') - ->findOneByUrl($array['url']); - - if (!is_object($entry)) { - $entry = new Entry($user); - $entry->setUrl($array['url']); - } - - $entry->setTitle($array['title']); - $entry->setArchived($array['is_read']); - $entry->setStarred($array['is_fav']); - $entry->setContent($array['content']); - $entry->setReadingTime(Utils::getReadingTime($array['content'])); - - $em->persist($entry); - - if (($i % $batchSize) === 0) { - $em->flush(); - $progress->advance($batchSize); - - $now = new \DateTime(); - $output->writeln(' of entries imported ... | '.$now->format('d-m-Y G:i:s')); - } - ++$i; + if (true === $res) { + $summary = $wallabag->getSummary(); + $output->writeln(''.$summary['imported'].' imported'); + $output->writeln(''.$summary['skipped'].' already saved'); } - $em->flush(); $em->clear(); - $progress->finish(); - } - - protected function convert($filename) - { - if (!file_exists($filename) || !is_readable($filename)) { - return false; - } - - $header = null; - $data = array(); - - if (($handle = fopen($filename, 'r')) !== false) { - while (($row = fgets($handle)) !== false) { - $data = json_decode($row); - } - fclose($handle); - } - - return $data; - } - - protected function get(InputInterface $input, OutputInterface $output) - { - $filename = __DIR__.'/../../../../web/uploads/import/'.$input->getArgument('userId').'.json'; - - $data = $this->convert($filename); - return $data; + $output->writeln('End : '.(new \DateTime())->format('d-m-Y G:i:s').' ---'); } } diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index 61eeba43..ebcee099 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -51,7 +51,7 @@ class PocketController extends Controller if (true === $pocket->import()) { $summary = $pocket->getSummary(); - $message = $summary['imported'].' entrie(s) imported, '.$summary['skipped'].' already saved.'; + $message = 'Import summary: '.$summary['imported'].' imported, '.$summary['skipped'].' already saved.'; } $this->get('session')->getFlashBag()->add( diff --git a/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php b/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php new file mode 100644 index 00000000..de200184 --- /dev/null +++ b/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php @@ -0,0 +1,58 @@ +createForm(new UploadImportType()); + $importForm->handleRequest($request); + $user = $this->getUser(); + + if ($importForm->isValid()) { + $file = $importForm->get('file')->getData(); + $name = $user->getId().'.json'; + + if (in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) { + $wallabag = $this->get('wallabag_import.wallabag_v1.import'); + $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:WallabagV1:index.html.twig', [ + 'form' => $importForm->createView(), + ]); + } +} diff --git a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php index 2ef35463..39df9d3f 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/Configuration.php @@ -17,6 +17,8 @@ class Configuration implements ConfigurationInterface ->arrayNode('allow_mimetypes') ->prototype('scalar')->end() ->end() + ->scalarNode('resource_dir') + ->end() ->end() ; diff --git a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php index 38163886..3f23c36b 100644 --- a/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php +++ b/src/Wallabag/ImportBundle/DependencyInjection/WallabagImportExtension.php @@ -14,6 +14,7 @@ class WallabagImportExtension extends Extension $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); $container->setParameter('wallabag_import.allow_mimetypes', $config['allow_mimetypes']); + $container->setParameter('wallabag_import.resource_dir', $config['resource_dir']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 1710d9d3..aeccc7bd 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -141,7 +141,7 @@ class PocketImport implements ImportInterface $entries = $response->json(); - $this->parsePocketEntries($entries['list']); + $this->parseEntries($entries['list']); return true; } @@ -194,11 +194,9 @@ class PocketImport implements ImportInterface * * @param $entries */ - private function parsePocketEntries($entries) + private function parseEntries($entries) { foreach ($entries as $pocketEntry) { - $entry = new Entry($this->user); - $url = isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '' ? $pocketEntry['resolved_url'] : $pocketEntry['given_url']; $existingEntry = $this->em @@ -210,6 +208,7 @@ class PocketImport implements ImportInterface continue; } + $entry = new Entry($this->user); $entry = $this->contentProxy->updateEntry($entry, $url); // 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php new file mode 100644 index 00000000..7b012674 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php @@ -0,0 +1,137 @@ +em = $em; + $this->logger = new NullLogger(); + } + + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * We define the user in a custom call because on the import command there is no logged in user. + * So we can't retrieve user from the `security.token_storage` service. + * + * @param User $user + */ + public function setUser(User $user) + { + $this->user = $user; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'Wallabag v1'; + } + + /** + * {@inheritdoc} + */ + public function getDescription() + { + return 'This importer will import all your wallabag v1 articles.'; + } + + /** + * {@inheritdoc} + */ + public function import() + { + if (!$this->user) { + $this->logger->error('WallabagV1Import: 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)); + + return false; + } + + $this->parseEntries(json_decode(file_get_contents($this->filepath), true)); + + return true; + } + + /** + * {@inheritdoc} + */ + public function getSummary() + { + return [ + 'skipped' => $this->skippedEntries, + 'imported' => $this->importedEntries, + ]; + } + + /** + * Set file path to the json file. + * + * @param string $filepath + */ + public function setFilepath($filepath) + { + $this->filepath = $filepath; + + return $this; + } + + /** + * @param $entries + */ + private function parseEntries($entries) + { + foreach ($entries as $importedEntry) { + $existingEntry = $this->em + ->getRepository('WallabagCoreBundle:Entry') + ->existByUrlAndUserId($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_read']); + $entry->setStarred($importedEntry['is_fav']); + $entry->setContent($importedEntry['content']); + $entry->setReadingTime(Utils::getReadingTime($importedEntry['content'])); + $entry->setDomainName(parse_url($importedEntry['url'], PHP_URL_HOST)); + + $this->em->persist($entry); + ++$this->importedEntries; + } + + $this->em->flush(); + } +} diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index f421821c..e73ec0c8 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -18,3 +18,10 @@ services: calls: - [ setClient, [ "@wallabag_import.pocket.client" ] ] - [ setLogger, [ "@logger" ]] + + wallabag_import.wallabag_v1.import: + class: Wallabag\ImportBundle\Import\WallabagV1Import + arguments: + - "@doctrine.orm.entity_manager" + calls: + - [ setLogger, [ "@logger" ]] diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index b068283a..bd51f730 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -9,6 +9,7 @@ {% trans %}Welcome on wallabag importer. Please select your previous service that you want to migrate.{% endtrans %}
    diff --git a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig new file mode 100644 index 00000000..328ab473 --- /dev/null +++ b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig @@ -0,0 +1,30 @@ +{% extends "WallabagCoreBundle::layout.html.twig" %} +{% block title %}{% trans %}import{% endtrans %}{% endblock %} + +{% block content %} + +
    +
    +
    +
    +
    + {{ form_start(form, {'method': 'POST'}) }} + {{ form_errors(form) }} +
    +
    +

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    + {{ form_errors(form.file) }} + {{ form_widget(form.file) }} +
    +
    + + + +
    +
    +
    +
    +
    +{% endblock %} diff --git a/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php new file mode 100644 index 00000000..fc66d402 --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php @@ -0,0 +1,96 @@ +user = new User(); + + $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + + $pocket = new WallabagV1Import($this->em); + + $this->logHandler = new TestHandler(); + $logger = new Logger('test', array($this->logHandler)); + $pocket->setLogger($logger); + + if (false === $unsetUser) { + $pocket->setUser($this->user); + } + + return $pocket; + } + + public function testInit() + { + $wallabagV1Import = $this->getWallabagV1Import(); + + $this->assertEquals('Wallabag v1', $wallabagV1Import->getName()); + $this->assertEquals('This importer will import all your wallabag v1 articles.', $wallabagV1Import->getDescription()); + } + + public function testImport() + { + $wallabagV1Import = $this->getWallabagV1Import(); + $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v1.json'); + + $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository') + ->disableOriginalConstructor() + ->getMock(); + + $entryRepo->expects($this->exactly(3)) + ->method('existByUrlAndUserId') + ->will($this->onConsecutiveCalls(false, true, false)); + + $this->em + ->expects($this->any()) + ->method('getRepository') + ->willReturn($entryRepo); + + $res = $wallabagV1Import->import(); + + $this->assertTrue($res); + $this->assertEquals(['skipped' => 1, 'imported' => 2], $wallabagV1Import->getSummary()); + } + + public function testImportBadFile() + { + $wallabagV1Import = $this->getWallabagV1Import(); + $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx'); + + $res = $wallabagV1Import->import(); + + $this->assertFalse($res); + + $records = $this->logHandler->getRecords(); + $this->assertContains('WallabagV1Import: unable to read file', $records[0]['message']); + $this->assertEquals('ERROR', $records[0]['level_name']); + } + + public function testImportUserNotDefined() + { + $wallabagV1Import = $this->getWallabagV1Import(true); + $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v1.json'); + + $res = $wallabagV1Import->import(); + + $this->assertFalse($res); + + $records = $this->logHandler->getRecords(); + $this->assertContains('WallabagV1Import: user is not defined', $records[0]['message']); + $this->assertEquals('ERROR', $records[0]['level_name']); + } +} diff --git a/src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v1.json b/src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v1.json new file mode 100644 index 00000000..534343f8 --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/fixtures/wallabag-v1.json @@ -0,0 +1,50 @@ +[ + { + "0": "1", + "1": "Framabag, un nouveau service libre et gratuit", + "2": "http://www.framablog.org/index.php/post/2014/02/05/Framabag-service-libre-gratuit-interview-developpeur", + "3": "0", + "4": "0", + "5": "\n

    Une interview de Nicolas, son développeur.

    \n

    Il ne vous a sûrement pas échappé que notre consommation de contenus du Web est terriblement chronophage et particulièrement frustrante tout à la fois : non seulement nous passons beaucoup (trop ?) de temps en ligne à explorer les mines aurifères de la toile, y détectant pépites et filons, mais nous sommes surtout constamment en manque. Même si nous ne sommes pas dans le zapping frénétique si facilement dénoncé par les doctes psychologues qui pontifient sur les dangers du numérique pour les jeunes cervelles, il nous vient souvent le goût amer de l’inachevé : pas le temps de tout lire (TL;DR est devenu le clin d’œil mi-figue mi-raisin d’une génération de lecteurs pressés), pas trop le temps de réfléchir non plus hélas, pas le temps de suivre la ribambelle de liens associés à un article…

    \n

    Pour nous donner bonne conscience, nous rangeons scrupuleusement un marque-page de plus dans un sous-dossier qui en comporte déjà 256, nous notons un élément de plus dans la toujours ridiculement longue toudouliste, bref nous remettons à plus tard, c’est-à-dire le plus souvent aux introuvables calendes grecques, le soin de lire vraiment un article jugé intéressant, de regarder une vidéo signalée par les rézossocios, de lire un chapitre entier d’un ouvrage disponible en ligne…

    \n

    Alors bien sûr, à défaut de nous donner tout le temps qui serait nécessaire, des solutions existent pour nous permettre de « lire plus tard » en sauvegardant le précieux pollen de nos butinages de site en site, et d’en faire ultérieurement votre miel ; c’est bel et bon mais les ruches sont un peu distantes, ça s’appelle le cloud (nos amis techies m’ont bien expliqué mais j’ai seulement compris que des trucs à moi sont sur des machines lointaines, ça ne me rassure pas trop) et elles sont souvent propriétaires, ne laissant entrer que les utilisateurs consommateurs payants et qui consentent à leurs conditions. Sans compter que de gros bourdons viennent profiter plus ou moins discrètement de toutes ces traces de nous-mêmes qui permettent de monétiser notre profil : si je collecte sur ces services (ne les nommons pas, justement) une série d’articles sur l’idée de Nature chez Diderot, je recevrai diverses sollicitations pour devenir client de la boutique Nature & Découverte du boulevard Diderot. Et si d’aventure les programmes de la NSA moulinent sur le service, je serai peut-être un jour dans une liste des militants naturistes indésirables sur les vols de la PanAm (je ne sais plus trop si je plaisante là, finalement…)

    \n

    La bonne idée : « se constituer un réservoir de documents sélectionnés à parcourir plus tard » appelait donc une autre bonne idée, celle d’avoir le contrôle de ce réservoir, de notre collection personnelle. C’est Nicolas Lœuillet, ci-dessous interviewé, qui s’y est collé avec une belle application appelée euh… oui, appelée Wallabag.

    \n

    Framasoft soutient d’autant plus son initiative qu’on lui a cherché des misères pour une histoire de nom et qu’il est possible d’installer soi-même une copie de Wallabag sur son propre site.

    \n

    Le petit plus de Framasoft, réseau toujours désireux de vous proposer des alternatives libératrices, c’est de vous proposer (sur inscription préalable) un accès au Framabag, autrement dit votre Wallabag sur un serveur Frama* avec notre garantie de confidentialité. Comme pour le Framanews, nous vous accueillons volontiers dans la limite de nos capacités, en vous invitant à vous lancer dans votre auto-hébergement de Wallabag.
    Cet article est trop long ? Mettez-le dans votre Framabag et hop.

    \n

    Framablog : Salut Nicolas… Tu peux te présenter brièvement ?

    \n

    Salut ! Développeur PHP depuis quelques années maintenant (10 ans), j’ai voulu me remettre à niveau techniquement parlant (depuis 3 ans, j’ai pas mal lâché le clavier). Pour mes besoins persos, j’ai donc créé un petit projet pour remplacer une solution propriétaire existante. Sans aucune prétention, j’ai hébergé ce projet sur Github et comme c’est la seule solution open source de ce type, le nombre de personnes intéressées a augmenté …

    \n

    Les utilisateurs de services Framasoft ne le savent pas forcément, mais tu as déjà pas mal participé à la FramaGalaxie, non ?

    \n

    En effet. J’ai commencé un plugin pour Framanews, ttrss-purge-accounts, qui permet de nettoyer la base de données de comptes plus utilisés. Mais ce plugin a besoin d’être terminé à 100% pour être intégré au sein de Framanews (et donc de Tiny Tiny RSS), si quelqu’un souhaite m’aider, il n’y a aucun souci.
    J’ai aussi fait 1 ou 2 apparitions dans des traductions pour Framablog. Rien d’extraordinaire, je ne suis pas bilingue, ça me permet de m’entraîner.

    \n

    Parlons de suite de ce qui fâche : ton application Wallabag, elle s’appellait pas “Poche”, avant ? Tu nous racontes l’histoire ?

    \n

    Euh en effet … Déjà, pourquoi poche ? Parce que l’un des trois « ténors » sur le marché s’appelle Pocket. Comme mon appli n’était destinée qu’à mon usage personnel au départ, je ne me suis pas torturé bien longtemps.

    \n

    Cet été, on a failli changer de nom, quand il y a eu de plus en plus d’utilisateurs. Et puis on s’est dit que poche, c’était pas mal, ça sonnait bien français et puis avec les quelques dizaines d’utilisateurs, on ne gênerait personne.

    \n

    C’est sans compter avec les sociétés américaines et leur fâcheuse manie de vouloir envoyer leurs avocats à tout bout de champ. Le 23 janvier, j’ai reçu un email de la part du cabinet d’avocats de Pocket me demandant de changer le nom, le logo, de ne plus utiliser le terme “read-it-later” (« lisez le plus tard ») et de ne plus dire que Pocket n’est pas gratuit (tout est parti d’un tweet où je qualifie Pocket de « non free » à savoir non libre). Bref, même si je semblais dans mon droit, j’ai quand même pris la décision de changer de nom et Wallabag est né, suite aux dizaines de propositions de nom reçues. C’est un mélange entre le wallaby (de la famille des kangourous, qui stockent dans leur poche ce qui leur est cher) et bag (les termes sac / sacoche / besace sont énormément revenus). Mais maintenant, on va de l’avant, plus de temps à perdre avec ça, on a du pain sur la planche.
    \"wallaby crédit photo William Warby qui autorise explicitement toute réutilisation.

    \n

    Bon, alors explique-moi ce que je vais pouvoir faire avec Framabag…

    \n

    Alors Framabag, ça te permet de te créer un compte gratuitement et librement pour pouvoir utiliser Wallabag. Seule ton adresse email est nécessaire, on se charge d’installer et de mettre à jour Wallabag pour toi. Tu peux d’ailleurs profiter d’autres services proposés par Framasoft ici.

    \n

    À ce jour, il y a 834 comptes créés sur Framabag.

    \n

    Vous avez vraiment conçu ce service afin qu’on puisse l’utiliser avec un maximum d’outils, non ?

    \n

    Autour de l’application web, il existe déjà des applications pour smartphones (Android et Windows Phone), des extensions Firefox et Google Chrome.

    \n

    Comme Wallabag possède des flux RSS, c’est facile de lire les articles sauvegardés sur sa liseuse (si celle-ci permet de lire des flux RSS). Calibre (« logiciel de lecture, de gestion de bibliothèques et de conversion de fichiers numériques de type ebook ou livre électronique »,nous dit ubuntu-fr.org) intègre depuis quelques semaines maintenant la possibilité de récupérer les articles non lus, pratique pour faire un fichier ePub !

    \n

    D’autres applications web permettent l’intégration avec Wallabag (FreshRSS, Leed et Tiny Tiny RSS pour les agrégateurs de flux). L’API qui sera disponible dans la prochaine version de Wallabag permettra encore plus d’interactivité.

    \n

    Y a-t-il un mode de lecture hors ligne ou est-ce que c’est prévu pour les prochaines versions ?

    \n

    Il y a un pseudo mode hors ligne, disponible avec l’application Android. On peut récupérer (via un flux RSS) les articles non lus que l’on a sauvegardés. Une fois déconnecté, on peut continuer à lire sur son smartphone ou sa tablette les articles. Par contre, il manque des fonctionnalités : quand tu marques un article comme lu, ce n’est pas synchronisé avec la version web de Wallabag. J’espère que je suis presque clair dans mes explications.

    \n

    Pour la v2, qui est déjà en cours de développement, où je suis bien aidé par Vincent Jousse, on aura la possibilité d’avoir un vrai mode hors ligne.

    \n

    Alors si on veut aider / participer / trifouiller le code / vous envoyer des retours, on fait comment ?

    \n

    On peut aider de plusieurs façons :

    \n
    • utiliser wallabag et nous remonter les problèmes rencontrés ;
    • \n
    • participer au développement de l’application https://github.com/wallabag/wallabag Si Silex / Symfony2 / HTML5 / etc. te parlent, n’hésite pas !
    • \n
    • comme tout projet, le gros point noir est le manque de documentation. Elle est dispo ici mais il manque plein de choses et tout n’est pas à jour ;
    • \n
    • parler de Wallabag autour de vous ;
    • \n
    • il existe un compte Flattr.
    • \n

    Le mot de la fin…?

    \n

    Merci à Framasoft d’accueillir et de soutenir Wallabag !

    \n

    La route est encore bien longue pour ne plus utiliser de solutions propriétaires, mais on devrait y arriver, non ?

    \n

    \"framasoft
    hackez Gégé !

    \n", + "6": "1", + "id": "1", + "title": "Framabag, un nouveau service libre et gratuit", + "url": "http://www.framablog.org/index.php/post/2014/02/05/Framabag-service-libre-gratuit-interview-developpeur", + "is_read": "0", + "is_fav": "0", + "content": "\n

    Une interview de Nicolas, son développeur.

    \n

    Il ne vous a sûrement pas échappé que notre consommation de contenus du Web est terriblement chronophage et particulièrement frustrante tout à la fois : non seulement nous passons beaucoup (trop ?) de temps en ligne à explorer les mines aurifères de la toile, y détectant pépites et filons, mais nous sommes surtout constamment en manque. Même si nous ne sommes pas dans le zapping frénétique si facilement dénoncé par les doctes psychologues qui pontifient sur les dangers du numérique pour les jeunes cervelles, il nous vient souvent le goût amer de l’inachevé : pas le temps de tout lire (TL;DR est devenu le clin d’œil mi-figue mi-raisin d’une génération de lecteurs pressés), pas trop le temps de réfléchir non plus hélas, pas le temps de suivre la ribambelle de liens associés à un article…

    \n

    Pour nous donner bonne conscience, nous rangeons scrupuleusement un marque-page de plus dans un sous-dossier qui en comporte déjà 256, nous notons un élément de plus dans la toujours ridiculement longue toudouliste, bref nous remettons à plus tard, c’est-à-dire le plus souvent aux introuvables calendes grecques, le soin de lire vraiment un article jugé intéressant, de regarder une vidéo signalée par les rézossocios, de lire un chapitre entier d’un ouvrage disponible en ligne…

    \n

    Alors bien sûr, à défaut de nous donner tout le temps qui serait nécessaire, des solutions existent pour nous permettre de « lire plus tard » en sauvegardant le précieux pollen de nos butinages de site en site, et d’en faire ultérieurement votre miel ; c’est bel et bon mais les ruches sont un peu distantes, ça s’appelle le cloud (nos amis techies m’ont bien expliqué mais j’ai seulement compris que des trucs à moi sont sur des machines lointaines, ça ne me rassure pas trop) et elles sont souvent propriétaires, ne laissant entrer que les utilisateurs consommateurs payants et qui consentent à leurs conditions. Sans compter que de gros bourdons viennent profiter plus ou moins discrètement de toutes ces traces de nous-mêmes qui permettent de monétiser notre profil : si je collecte sur ces services (ne les nommons pas, justement) une série d’articles sur l’idée de Nature chez Diderot, je recevrai diverses sollicitations pour devenir client de la boutique Nature & Découverte du boulevard Diderot. Et si d’aventure les programmes de la NSA moulinent sur le service, je serai peut-être un jour dans une liste des militants naturistes indésirables sur les vols de la PanAm (je ne sais plus trop si je plaisante là, finalement…)

    \n

    La bonne idée : « se constituer un réservoir de documents sélectionnés à parcourir plus tard » appelait donc une autre bonne idée, celle d’avoir le contrôle de ce réservoir, de notre collection personnelle. C’est Nicolas Lœuillet, ci-dessous interviewé, qui s’y est collé avec une belle application appelée euh… oui, appelée Wallabag.

    \n

    Framasoft soutient d’autant plus son initiative qu’on lui a cherché des misères pour une histoire de nom et qu’il est possible d’installer soi-même une copie de Wallabag sur son propre site.

    \n

    Le petit plus de Framasoft, réseau toujours désireux de vous proposer des alternatives libératrices, c’est de vous proposer (sur inscription préalable) un accès au Framabag, autrement dit votre Wallabag sur un serveur Frama* avec notre garantie de confidentialité. Comme pour le Framanews, nous vous accueillons volontiers dans la limite de nos capacités, en vous invitant à vous lancer dans votre auto-hébergement de Wallabag.
    Cet article est trop long ? Mettez-le dans votre Framabag et hop.

    \n

    Framablog : Salut Nicolas… Tu peux te présenter brièvement ?

    \n

    Salut ! Développeur PHP depuis quelques années maintenant (10 ans), j’ai voulu me remettre à niveau techniquement parlant (depuis 3 ans, j’ai pas mal lâché le clavier). Pour mes besoins persos, j’ai donc créé un petit projet pour remplacer une solution propriétaire existante. Sans aucune prétention, j’ai hébergé ce projet sur Github et comme c’est la seule solution open source de ce type, le nombre de personnes intéressées a augmenté …

    \n

    Les utilisateurs de services Framasoft ne le savent pas forcément, mais tu as déjà pas mal participé à la FramaGalaxie, non ?

    \n

    En effet. J’ai commencé un plugin pour Framanews, ttrss-purge-accounts, qui permet de nettoyer la base de données de comptes plus utilisés. Mais ce plugin a besoin d’être terminé à 100% pour être intégré au sein de Framanews (et donc de Tiny Tiny RSS), si quelqu’un souhaite m’aider, il n’y a aucun souci.
    J’ai aussi fait 1 ou 2 apparitions dans des traductions pour Framablog. Rien d’extraordinaire, je ne suis pas bilingue, ça me permet de m’entraîner.

    \n

    Parlons de suite de ce qui fâche : ton application Wallabag, elle s’appellait pas “Poche”, avant ? Tu nous racontes l’histoire ?

    \n

    Euh en effet … Déjà, pourquoi poche ? Parce que l’un des trois « ténors » sur le marché s’appelle Pocket. Comme mon appli n’était destinée qu’à mon usage personnel au départ, je ne me suis pas torturé bien longtemps.

    \n

    Cet été, on a failli changer de nom, quand il y a eu de plus en plus d’utilisateurs. Et puis on s’est dit que poche, c’était pas mal, ça sonnait bien français et puis avec les quelques dizaines d’utilisateurs, on ne gênerait personne.

    \n

    C’est sans compter avec les sociétés américaines et leur fâcheuse manie de vouloir envoyer leurs avocats à tout bout de champ. Le 23 janvier, j’ai reçu un email de la part du cabinet d’avocats de Pocket me demandant de changer le nom, le logo, de ne plus utiliser le terme “read-it-later” (« lisez le plus tard ») et de ne plus dire que Pocket n’est pas gratuit (tout est parti d’un tweet où je qualifie Pocket de « non free » à savoir non libre). Bref, même si je semblais dans mon droit, j’ai quand même pris la décision de changer de nom et Wallabag est né, suite aux dizaines de propositions de nom reçues. C’est un mélange entre le wallaby (de la famille des kangourous, qui stockent dans leur poche ce qui leur est cher) et bag (les termes sac / sacoche / besace sont énormément revenus). Mais maintenant, on va de l’avant, plus de temps à perdre avec ça, on a du pain sur la planche.
    \"wallaby crédit photo William Warby qui autorise explicitement toute réutilisation.

    \n

    Bon, alors explique-moi ce que je vais pouvoir faire avec Framabag…

    \n

    Alors Framabag, ça te permet de te créer un compte gratuitement et librement pour pouvoir utiliser Wallabag. Seule ton adresse email est nécessaire, on se charge d’installer et de mettre à jour Wallabag pour toi. Tu peux d’ailleurs profiter d’autres services proposés par Framasoft ici.

    \n

    À ce jour, il y a 834 comptes créés sur Framabag.

    \n

    Vous avez vraiment conçu ce service afin qu’on puisse l’utiliser avec un maximum d’outils, non ?

    \n

    Autour de l’application web, il existe déjà des applications pour smartphones (Android et Windows Phone), des extensions Firefox et Google Chrome.

    \n

    Comme Wallabag possède des flux RSS, c’est facile de lire les articles sauvegardés sur sa liseuse (si celle-ci permet de lire des flux RSS). Calibre (« logiciel de lecture, de gestion de bibliothèques et de conversion de fichiers numériques de type ebook ou livre électronique »,nous dit ubuntu-fr.org) intègre depuis quelques semaines maintenant la possibilité de récupérer les articles non lus, pratique pour faire un fichier ePub !

    \n

    D’autres applications web permettent l’intégration avec Wallabag (FreshRSS, Leed et Tiny Tiny RSS pour les agrégateurs de flux). L’API qui sera disponible dans la prochaine version de Wallabag permettra encore plus d’interactivité.

    \n

    Y a-t-il un mode de lecture hors ligne ou est-ce que c’est prévu pour les prochaines versions ?

    \n

    Il y a un pseudo mode hors ligne, disponible avec l’application Android. On peut récupérer (via un flux RSS) les articles non lus que l’on a sauvegardés. Une fois déconnecté, on peut continuer à lire sur son smartphone ou sa tablette les articles. Par contre, il manque des fonctionnalités : quand tu marques un article comme lu, ce n’est pas synchronisé avec la version web de Wallabag. J’espère que je suis presque clair dans mes explications.

    \n

    Pour la v2, qui est déjà en cours de développement, où je suis bien aidé par Vincent Jousse, on aura la possibilité d’avoir un vrai mode hors ligne.

    \n

    Alors si on veut aider / participer / trifouiller le code / vous envoyer des retours, on fait comment ?

    \n

    On peut aider de plusieurs façons :

    \n
    • utiliser wallabag et nous remonter les problèmes rencontrés ;
    • \n
    • participer au développement de l’application https://github.com/wallabag/wallabag Si Silex / Symfony2 / HTML5 / etc. te parlent, n’hésite pas !
    • \n
    • comme tout projet, le gros point noir est le manque de documentation. Elle est dispo ici mais il manque plein de choses et tout n’est pas à jour ;
    • \n
    • parler de Wallabag autour de vous ;
    • \n
    • il existe un compte Flattr.
    • \n

    Le mot de la fin…?

    \n

    Merci à Framasoft d’accueillir et de soutenir Wallabag !

    \n

    La route est encore bien longue pour ne plus utiliser de solutions propriétaires, mais on devrait y arriver, non ?

    \n

    \"framasoft
    hackez Gégé !

    \n", + "user_id": "1" + }, + { + "0": "2", + "1": "wallabag/wallabag", + "2": "https://github.com/wallabag/wallabag", + "3": "1", + "4": "0", + "5": "README.md

    wallabag is a self hostable application allowing you to not miss any content anymore. Click, save, read it when you can. It extracts content so that you can read it when you have time.

    \n

    More informations on our website: wallabag.org

    \n

    License

    \n

    Copyright © 2010-2014 Nicolas Lœuillet nicolas@loeuillet.org This work is free. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See the COPYING file for more details.

    \n", + "6": "1", + "id": "2", + "title": "wallabag/wallabag", + "url": "https://github.com/wallabag/wallabag", + "is_read": "1", + "is_fav": "0", + "content": "README.md

    wallabag is a self hostable application allowing you to not miss any content anymore. Click, save, read it when you can. It extracts content so that you can read it when you have time.

    \n

    More informations on our website: wallabag.org

    \n

    License

    \n

    Copyright © 2010-2014 Nicolas Lœuillet nicolas@loeuillet.org This work is free. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See the COPYING file for more details.

    \n", + "user_id": "1" + }, + { + "0": "3", + "1": "a self hostable application for saving web pages | wallabag", + "2": "https://www.wallabag.org/", + "3": "1", + "4": "0", + "5": "\n
    \n
    \n

    wallabag (formerly poche) is a self hostable application for saving web pages. Unlike other services, wallabag is free (as in freedom) and open source.

    \n
    \n\n
    \n
    \n
    \n

    With this application you will not miss content anymore. Click, save, read it when you want. It saves the content you select so that you can read it when you have time.

    \n
    \n\n
    \n
    \n
    \n

    How it works

    \n

    Thanks to the bookmarklet or third-party applications, you save an article in your wallabag to read it later. Then, when you open your wallabag, you can comfortably read your articles.

    \n

    How to use wallabag

    \n

    There are two ways to use wallabag: you can install it on your web server or you can create an account at Framabag (we install and upgrade wallabag for you).

    \n
    \n\n
    \n", + "6": "1", + "id": "3", + "title": "a self hostable application for saving web pages | wallabag", + "url": "https://www.wallabag.org/", + "is_read": "1", + "is_fav": "0", + "content": "\n
    \n
    \n

    wallabag (formerly poche) is a self hostable application for saving web pages. Unlike other services, wallabag is free (as in freedom) and open source.

    \n
    \n\n
    \n
    \n
    \n

    With this application you will not miss content anymore. Click, save, read it when you want. It saves the content you select so that you can read it when you have time.

    \n
    \n\n
    \n
    \n
    \n

    How it works

    \n

    Thanks to the bookmarklet or third-party applications, you save an article in your wallabag to read it later. Then, when you open your wallabag, you can comfortably read your articles.

    \n

    How to use wallabag

    \n

    There are two ways to use wallabag: you can install it on your web server or you can create an account at Framabag (we install and upgrade wallabag for you).

    \n
    \n\n
    \n", + "user_id": "1" + } +] diff --git a/web/uploads/import/.gitkeep b/web/uploads/import/.gitkeep new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 7019c7cf6c6af39c0f458769e20c3f9306477943 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Thu, 31 Dec 2015 11:24:46 +0100 Subject: Add tagged services for import - list services in /import - add url to import service - ImportBundle routing are now prefixed by /import - optimize flush in each import (flushing each 20 contents) - improve design of each import - add more tests --- app/config/routing.yml | 2 +- .../views/themes/material/public/css/main.css | 6 +- .../ImportBundle/Controller/ImportController.php | 6 +- .../ImportBundle/Controller/PocketController.php | 10 ++-- .../Controller/WallabagV1Controller.php | 21 +++---- .../ImportBundle/Form/Type/UploadImportType.php | 7 --- src/Wallabag/ImportBundle/Import/ImportChain.php | 34 +++++++++++ .../ImportBundle/Import/ImportCompilerPass.php | 33 +++++++++++ .../ImportBundle/Import/ImportInterface.php | 7 +++ src/Wallabag/ImportBundle/Import/PocketImport.php | 18 +++++- .../ImportBundle/Import/WallabagV1Import.php | 26 +++++++- .../ImportBundle/Resources/config/services.yml | 7 +++ .../Resources/views/Import/index.html.twig | 12 ++-- .../Resources/views/Pocket/index.html.twig | 10 ++-- .../Resources/views/WallabagV1/index.html.twig | 16 +++-- .../Tests/Controller/ImportControllerTest.php | 29 +++++++++ .../Tests/Controller/PocketControllerTest.php | 42 +++++++++++++ .../Tests/Controller/WallabagV1ControllerTest.php | 69 ++++++++++++++++++++++ .../ImportBundle/Tests/Import/ImportChainTest.php | 21 +++++++ .../Tests/Import/ImportCompilerPassTest.php | 47 +++++++++++++++ .../ImportBundle/Tests/Import/PocketImportTest.php | 3 +- .../Tests/Import/WallabagV1ImportTest.php | 3 +- src/Wallabag/ImportBundle/Tests/fixtures/test.html | 0 src/Wallabag/ImportBundle/Tests/fixtures/test.txt | 0 src/Wallabag/ImportBundle/WallabagImportBundle.php | 8 +++ 25 files changed, 394 insertions(+), 43 deletions(-) create mode 100644 src/Wallabag/ImportBundle/Import/ImportChain.php create mode 100644 src/Wallabag/ImportBundle/Import/ImportCompilerPass.php create mode 100644 src/Wallabag/ImportBundle/Tests/Controller/ImportControllerTest.php create mode 100644 src/Wallabag/ImportBundle/Tests/Controller/PocketControllerTest.php create mode 100644 src/Wallabag/ImportBundle/Tests/Controller/WallabagV1ControllerTest.php create mode 100644 src/Wallabag/ImportBundle/Tests/Import/ImportChainTest.php create mode 100644 src/Wallabag/ImportBundle/Tests/Import/ImportCompilerPassTest.php create mode 100644 src/Wallabag/ImportBundle/Tests/fixtures/test.html create mode 100644 src/Wallabag/ImportBundle/Tests/fixtures/test.txt diff --git a/app/config/routing.yml b/app/config/routing.yml index 91a5705f..1ca2f677 100644 --- a/app/config/routing.yml +++ b/app/config/routing.yml @@ -1,7 +1,7 @@ wallabag_import: resource: "@WallabagImportBundle/Controller/" type: annotation - prefix: / + prefix: /import wallabag_api: resource: "@WallabagApiBundle/Resources/config/routing.yml" diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css index d6031530..516f6fdf 100755 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css @@ -497,4 +497,8 @@ footer [class^="icon-"]:hover, footer [class*=" icon-"]:hover { /* force height on non-input field in the settings page */ div.settings div.input-field div, div.settings div.input-field ul { margin-top: 40px; -} \ No newline at end of file +} +/* but avoid to kill all file input */ +div.settings div.file-field div { + margin-top: inherit; +} diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php index 2a0d6ab5..c1486e38 100644 --- a/src/Wallabag/ImportBundle/Controller/ImportController.php +++ b/src/Wallabag/ImportBundle/Controller/ImportController.php @@ -8,10 +8,12 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class ImportController extends Controller { /** - * @Route("/import", name="import") + * @Route("/", name="import") */ public function importAction() { - return $this->render('WallabagImportBundle:Import:index.html.twig', []); + return $this->render('WallabagImportBundle:Import:index.html.twig', [ + 'imports' => $this->get('wallabag_import.chain')->getAll(), + ]); } } diff --git a/src/Wallabag/ImportBundle/Controller/PocketController.php b/src/Wallabag/ImportBundle/Controller/PocketController.php index ebcee099..a0853383 100644 --- a/src/Wallabag/ImportBundle/Controller/PocketController.php +++ b/src/Wallabag/ImportBundle/Controller/PocketController.php @@ -8,15 +8,17 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class PocketController extends Controller { /** - * @Route("/import/pocket", name="import_pocket") + * @Route("/pocket", name="import_pocket") */ public function indexAction() { - return $this->render('WallabagImportBundle:Pocket:index.html.twig', []); + return $this->render('WallabagImportBundle:Pocket:index.html.twig', [ + 'import' => $this->get('wallabag_import.pocket.import'), + ]); } /** - * @Route("/import/pocket/auth", name="import_pocket_auth") + * @Route("/pocket/auth", name="import_pocket_auth") */ public function authAction() { @@ -32,7 +34,7 @@ class PocketController extends Controller } /** - * @Route("/import/pocket/callback", name="import_pocket_callback") + * @Route("/pocket/callback", name="import_pocket_callback") */ public function callbackAction() { diff --git a/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php b/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php index de200184..e50a6c35 100644 --- a/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php +++ b/src/Wallabag/ImportBundle/Controller/WallabagV1Controller.php @@ -10,20 +10,20 @@ use Wallabag\ImportBundle\Form\Type\UploadImportType; class WallabagV1Controller extends Controller { /** - * @Route("/import/wallabag-v1", name="import_wallabag_v1") + * @Route("/wallabag-v1", name="import_wallabag_v1") */ public function indexAction(Request $request) { - $importForm = $this->createForm(new UploadImportType()); - $importForm->handleRequest($request); - $user = $this->getUser(); + $form = $this->createForm(new UploadImportType()); + $form->handleRequest($request); - if ($importForm->isValid()) { - $file = $importForm->get('file')->getData(); - $name = $user->getId().'.json'; + $wallabag = $this->get('wallabag_import.wallabag_v1.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)) { - $wallabag = $this->get('wallabag_import.wallabag_v1.import'); $res = $wallabag ->setUser($this->getUser()) ->setFilepath($this->getParameter('wallabag_import.resource_dir').'/'.$name) @@ -34,7 +34,7 @@ class WallabagV1Controller extends Controller $summary = $wallabag->getSummary(); $message = 'Import summary: '.$summary['imported'].' imported, '.$summary['skipped'].' already saved.'; - @unlink($this->getParameter('wallabag_import.resource_dir').'/'.$name); + unlink($this->getParameter('wallabag_import.resource_dir').'/'.$name); } $this->get('session')->getFlashBag()->add( @@ -52,7 +52,8 @@ class WallabagV1Controller extends Controller } return $this->render('WallabagImportBundle:WallabagV1:index.html.twig', [ - 'form' => $importForm->createView(), + 'form' => $form->createView(), + 'import' => $wallabag, ]); } } diff --git a/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php b/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php index 5d894318..415890f3 100644 --- a/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php +++ b/src/Wallabag/ImportBundle/Form/Type/UploadImportType.php @@ -15,13 +15,6 @@ class UploadImportType extends AbstractType ; } - public function getDefaultOptions(array $options) - { - return array( - 'csrf_protection' => false, - ); - } - public function getName() { return 'upload_import_file'; diff --git a/src/Wallabag/ImportBundle/Import/ImportChain.php b/src/Wallabag/ImportBundle/Import/ImportChain.php new file mode 100644 index 00000000..9dd77956 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/ImportChain.php @@ -0,0 +1,34 @@ +imports = []; + } + + /** + * Add an import to the chain. + * + * @param ImportInterface $import + * @param string $alias + */ + public function addImport(ImportInterface $import, $alias) + { + $this->imports[$alias] = $import; + } + + /** + * Get all imports. + * + * @return array + */ + public function getAll() + { + return $this->imports; + } +} diff --git a/src/Wallabag/ImportBundle/Import/ImportCompilerPass.php b/src/Wallabag/ImportBundle/Import/ImportCompilerPass.php new file mode 100644 index 00000000..a363a566 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/ImportCompilerPass.php @@ -0,0 +1,33 @@ +hasDefinition('wallabag_import.chain')) { + return; + } + + $definition = $container->getDefinition( + 'wallabag_import.chain' + ); + + $taggedServices = $container->findTaggedServiceIds( + 'wallabag_import.import' + ); + foreach ($taggedServices as $id => $tagAttributes) { + foreach ($tagAttributes as $attributes) { + $definition->addMethodCall( + 'addImport', + [new Reference($id), $attributes['alias']] + ); + } + } + } +} diff --git a/src/Wallabag/ImportBundle/Import/ImportInterface.php b/src/Wallabag/ImportBundle/Import/ImportInterface.php index 8cf238aa..25dc0d85 100644 --- a/src/Wallabag/ImportBundle/Import/ImportInterface.php +++ b/src/Wallabag/ImportBundle/Import/ImportInterface.php @@ -13,6 +13,13 @@ interface ImportInterface extends LoggerAwareInterface */ public function getName(); + /** + * Url to start the import. + * + * @return string + */ + public function getUrl(); + /** * Description of the import. * diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index aeccc7bd..b1c5bb00 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -45,12 +45,20 @@ class PocketImport implements ImportInterface return 'Pocket'; } + /** + * {@inheritdoc} + */ + public function getUrl() + { + return 'import_pocket'; + } + /** * {@inheritdoc} */ public function getDescription() { - return 'This importer will import all your Pocket data.'; + return 'This importer will import all your Pocket data. Pocket doesn\'t allow us to retrieve content from their service, so the readable content of each article will be re-fetched by Wallabag.'; } /** @@ -196,6 +204,8 @@ class PocketImport implements ImportInterface */ private function parseEntries($entries) { + $i = 1; + foreach ($entries as $pocketEntry) { $url = isset($pocketEntry['resolved_url']) && $pocketEntry['resolved_url'] != '' ? $pocketEntry['resolved_url'] : $pocketEntry['given_url']; @@ -241,6 +251,12 @@ class PocketImport implements ImportInterface $this->em->persist($entry); ++$this->importedEntries; + + // flush every 20 entries + if (($i % 20) === 0) { + $em->flush(); + } + ++$i; } $this->em->flush(); diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php index 7b012674..aff5af40 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php @@ -50,12 +50,20 @@ class WallabagV1Import implements ImportInterface return 'Wallabag v1'; } + /** + * {@inheritdoc} + */ + public function getUrl() + { + return 'import_wallabag_v1'; + } + /** * {@inheritdoc} */ public function getDescription() { - return 'This importer will import all your wallabag v1 articles.'; + return 'This importer will import all your wallabag v1 articles. On your config page, click on "JSON export" in the "Export your wallabag data" section. You will have a "wallabag-export-1-xxxx-xx-xx.json" file.'; } /** @@ -75,7 +83,13 @@ class WallabagV1Import implements ImportInterface return false; } - $this->parseEntries(json_decode(file_get_contents($this->filepath), true)); + $data = json_decode(file_get_contents($this->filepath), true); + + if (empty($data)) { + return false; + } + + $this->parseEntries($data); return true; } @@ -108,6 +122,8 @@ class WallabagV1Import implements ImportInterface */ private function parseEntries($entries) { + $i = 1; + foreach ($entries as $importedEntry) { $existingEntry = $this->em ->getRepository('WallabagCoreBundle:Entry') @@ -130,6 +146,12 @@ class WallabagV1Import implements ImportInterface $this->em->persist($entry); ++$this->importedEntries; + + // flush every 20 entries + if (($i % 20) === 0) { + $em->flush(); + } + ++$i; } $this->em->flush(); diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index e73ec0c8..e4dde100 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -1,4 +1,7 @@ services: + wallabag_import.chain: + class: Wallabag\ImportBundle\Import\ImportChain + wallabag_import.pocket.client: class: GuzzleHttp\Client arguments: @@ -18,6 +21,8 @@ services: calls: - [ setClient, [ "@wallabag_import.pocket.client" ] ] - [ setLogger, [ "@logger" ]] + tags: + - { name: wallabag_import.import, alias: pocket } wallabag_import.wallabag_v1.import: class: Wallabag\ImportBundle\Import\WallabagV1Import @@ -25,3 +30,5 @@ services: - "@doctrine.orm.entity_manager" calls: - [ setLogger, [ "@logger" ]] + tags: + - { name: wallabag_import.import, alias: wallabag_v1 } diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index bd51f730..27baa1e3 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -1,15 +1,19 @@ {% extends "WallabagCoreBundle::layout.html.twig" %} -{% block title %}{% trans %}import{% endtrans %}{% endblock %} +{% block title %}{% trans %}Import{% endtrans %}{% endblock %} {% block content %} -
    {% trans %}Welcome on wallabag importer. Please select your previous service that you want to migrate.{% endtrans %}
    diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig index 940fe4cc..9803896c 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -1,14 +1,16 @@ {% extends "WallabagCoreBundle::layout.html.twig" %} -{% block title %}{% trans %}import{% endtrans %}{% endblock %} +{% block title %}{% trans %}Import > Pocket{% endtrans %}{% endblock %} {% block content %} -
    - {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %} +
    {{ import.description|raw }}
    +

    {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %}

    - +
    diff --git a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig index 328ab473..23d3e146 100644 --- a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig @@ -1,20 +1,26 @@ {% extends "WallabagCoreBundle::layout.html.twig" %} -{% block title %}{% trans %}import{% endtrans %}{% endblock %} +{% block title %}{% trans %}Import > Wallabag v1{% endtrans %}{% endblock %} {% block content %} -
    +
    {{ import.description|raw }}
    +

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    {{ form_start(form, {'method': 'POST'}) }} {{ form_errors(form) }}
    -
    -

    {% trans %}Please select your wallabag export and click on the below button to upload and import it.{% endtrans %}

    +
    {{ form_errors(form.file) }} - {{ form_widget(form.file) }} +
    + File + {{ form_widget(form.file) }} +
    +
    + +
    diff --git a/src/Wallabag/ImportBundle/Tests/Controller/ImportControllerTest.php b/src/Wallabag/ImportBundle/Tests/Controller/ImportControllerTest.php new file mode 100644 index 00000000..30009af4 --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Controller/ImportControllerTest.php @@ -0,0 +1,29 @@ +getClient(); + + $client->request('GET', '/import/'); + + $this->assertEquals(302, $client->getResponse()->getStatusCode()); + $this->assertContains('login', $client->getResponse()->headers->get('location')); + } + + public function testImportList() + { + $this->logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/'); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals(2, $crawler->filter('blockquote')->count()); + } +} diff --git a/src/Wallabag/ImportBundle/Tests/Controller/PocketControllerTest.php b/src/Wallabag/ImportBundle/Tests/Controller/PocketControllerTest.php new file mode 100644 index 00000000..c2acd68c --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Controller/PocketControllerTest.php @@ -0,0 +1,42 @@ +logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/pocket'); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals(1, $crawler->filter('button[type=submit]')->count()); + } + + public function testImportPocketAuth() + { + $this->logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/pocket/auth'); + + $this->assertEquals(301, $client->getResponse()->getStatusCode()); + $this->assertContains('getpocket.com/auth/authorize', $client->getResponse()->headers->get('location')); + } + + public function testImportPocketCallbackWithBadToken() + { + $this->logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/pocket/callback'); + + $this->assertEquals(302, $client->getResponse()->getStatusCode()); + $this->assertContains('import/pocket', $client->getResponse()->headers->get('location')); + $this->assertEquals('Import failed, please try again.', $client->getContainer()->get('session')->getFlashBag()->peek('notice')[0]); + } +} diff --git a/src/Wallabag/ImportBundle/Tests/Controller/WallabagV1ControllerTest.php b/src/Wallabag/ImportBundle/Tests/Controller/WallabagV1ControllerTest.php new file mode 100644 index 00000000..e12ea429 --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Controller/WallabagV1ControllerTest.php @@ -0,0 +1,69 @@ +logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/wallabag-v1'); + + $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-v1'); + $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form(); + + $file = new UploadedFile(__DIR__.'/../fixtures/wallabag-v1.json', 'wallabag-v1.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-v1'); + $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]); + } +} diff --git a/src/Wallabag/ImportBundle/Tests/Import/ImportChainTest.php b/src/Wallabag/ImportBundle/Tests/Import/ImportChainTest.php new file mode 100644 index 00000000..702d2a9b --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Import/ImportChainTest.php @@ -0,0 +1,21 @@ +getMockBuilder('Wallabag\ImportBundle\Import\ImportInterface') + ->disableOriginalConstructor() + ->getMock(); + + $importChain = new ImportChain(); + $importChain->addImport($import, 'alias'); + + $this->assertCount(1, $importChain->getAll()); + $this->assertEquals($import, $importChain->getAll()['alias']); + } +} diff --git a/src/Wallabag/ImportBundle/Tests/Import/ImportCompilerPassTest.php b/src/Wallabag/ImportBundle/Tests/Import/ImportCompilerPassTest.php new file mode 100644 index 00000000..bd62ab3b --- /dev/null +++ b/src/Wallabag/ImportBundle/Tests/Import/ImportCompilerPassTest.php @@ -0,0 +1,47 @@ +process($container); + + $this->assertNull($res); + } + + public function testProcess() + { + $container = new ContainerBuilder(); + $container + ->register('wallabag_import.chain') + ->setPublic(false) + ; + + $container + ->register('foo') + ->addTag('wallabag_import.import', array('alias' => 'pocket')) + ; + + $this->process($container); + + $this->assertTrue($container->hasDefinition('wallabag_import.chain')); + + $definition = $container->getDefinition('wallabag_import.chain'); + $this->assertTrue($definition->hasMethodCall('addImport')); + + $calls = $definition->getMethodCalls(); + $this->assertEquals('pocket', $calls[0][1][1]); + } + + protected function process(ContainerBuilder $container) + { + $repeatedPass = new ImportCompilerPass(); + $repeatedPass->process($container); + } +} diff --git a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php index cf706fa9..6ee70db0 100644 --- a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php +++ b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php @@ -74,7 +74,8 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase $pocketImport = $this->getPocketImport(); $this->assertEquals('Pocket', $pocketImport->getName()); - $this->assertEquals('This importer will import all your Pocket data.', $pocketImport->getDescription()); + $this->assertNotEmpty($pocketImport->getUrl()); + $this->assertContains('This importer will import all your Pocket data.', $pocketImport->getDescription()); } public function testOAuthRequest() diff --git a/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php index fc66d402..8a8eb3fa 100644 --- a/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php +++ b/src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php @@ -39,7 +39,8 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase $wallabagV1Import = $this->getWallabagV1Import(); $this->assertEquals('Wallabag v1', $wallabagV1Import->getName()); - $this->assertEquals('This importer will import all your wallabag v1 articles.', $wallabagV1Import->getDescription()); + $this->assertNotEmpty($wallabagV1Import->getUrl()); + $this->assertContains('This importer will import all your wallabag v1 articles.', $wallabagV1Import->getDescription()); } public function testImport() diff --git a/src/Wallabag/ImportBundle/Tests/fixtures/test.html b/src/Wallabag/ImportBundle/Tests/fixtures/test.html new file mode 100644 index 00000000..e69de29b diff --git a/src/Wallabag/ImportBundle/Tests/fixtures/test.txt b/src/Wallabag/ImportBundle/Tests/fixtures/test.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/Wallabag/ImportBundle/WallabagImportBundle.php b/src/Wallabag/ImportBundle/WallabagImportBundle.php index d00f2fe9..a5ddc1b4 100644 --- a/src/Wallabag/ImportBundle/WallabagImportBundle.php +++ b/src/Wallabag/ImportBundle/WallabagImportBundle.php @@ -3,7 +3,15 @@ namespace Wallabag\ImportBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Wallabag\ImportBundle\Import\ImportCompilerPass; class WallabagImportBundle extends Bundle { + public function build(ContainerBuilder $container) + { + parent::build($container); + + $container->addCompilerPass(new ImportCompilerPass()); + } } -- cgit v1.2.3 From 6d7c7a6e3fbfaeefe51daf91d58f09c5b156f45a Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Thu, 31 Dec 2015 11:25:04 +0100 Subject: Remove real consumer key We should never commit them :) --- app/config/parameters.yml.dist | 2 +- app/config/tests/parameters.yml.dist.mysql | 2 +- app/config/tests/parameters.yml.dist.pgsql | 2 +- app/config/tests/parameters.yml.dist.sqlite | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index c0d57aa1..a769bc66 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -62,4 +62,4 @@ parameters: rss_limit: 50 # pocket import - pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 + pocket_consumer_key: xxxxxxxx diff --git a/app/config/tests/parameters.yml.dist.mysql b/app/config/tests/parameters.yml.dist.mysql index c0e19fe7..88b1d2b4 100644 --- a/app/config/tests/parameters.yml.dist.mysql +++ b/app/config/tests/parameters.yml.dist.mysql @@ -62,4 +62,4 @@ parameters: rss_limit: 50 # pocket import - pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 + pocket_consumer_key: xxxxxxxx diff --git a/app/config/tests/parameters.yml.dist.pgsql b/app/config/tests/parameters.yml.dist.pgsql index d4dd9da5..3c61142d 100644 --- a/app/config/tests/parameters.yml.dist.pgsql +++ b/app/config/tests/parameters.yml.dist.pgsql @@ -62,4 +62,4 @@ parameters: rss_limit: 50 # pocket import - pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 + pocket_consumer_key: xxxxxxxx diff --git a/app/config/tests/parameters.yml.dist.sqlite b/app/config/tests/parameters.yml.dist.sqlite index 5fbf4c70..2f7699b5 100644 --- a/app/config/tests/parameters.yml.dist.sqlite +++ b/app/config/tests/parameters.yml.dist.sqlite @@ -62,4 +62,4 @@ parameters: rss_limit: 50 # pocket import - pocket_consumer_key: 47025-85ed5e6cfd72abbb49d12db1 + pocket_consumer_key: xxxxxxxx -- cgit v1.2.3 From 5b2b5858fe363c1f9203b153166def099ecb5d67 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Sat, 2 Jan 2016 23:31:41 +0100 Subject: Update deps --- composer.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index 4cd8b034..858a125c 100644 --- a/composer.lock +++ b/composer.lock @@ -117,33 +117,33 @@ }, { "name": "doctrine/cache", - "version": "v1.5.4", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136" + "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/47cdc76ceb95cc591d9c79a36dc3794975b5d136", - "reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136", + "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6", + "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "~5.5|~7.0" }, "conflict": { "doctrine/common": ">2.2,<2.4" }, "require-dev": { - "phpunit/phpunit": ">=3.7", + "phpunit/phpunit": "~4.8|~5.0", "predis/predis": "~1.0", "satooshi/php-coveralls": "~0.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -183,7 +183,7 @@ "cache", "caching" ], - "time": "2015-12-19 05:03:47" + "time": "2015-12-31 16:37:02" }, { "name": "doctrine/collections", @@ -981,17 +981,17 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "1.7.6", + "version": "1.7.7", "target-dir": "FOS/RestBundle", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "f95b2f141748e9a5e2ddae833f60c38417aee8c3" + "reference": "c79b7e5df96e5581591ceb6a026bd4e5f9346de0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/f95b2f141748e9a5e2ddae833f60c38417aee8c3", - "reference": "f95b2f141748e9a5e2ddae833f60c38417aee8c3", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/c79b7e5df96e5581591ceb6a026bd4e5f9346de0", + "reference": "c79b7e5df96e5581591ceb6a026bd4e5f9346de0", "shasum": "" }, "require": { @@ -1063,7 +1063,7 @@ "keywords": [ "rest" ], - "time": "2015-12-20 13:45:30" + "time": "2015-12-29 16:02:50" }, { "name": "friendsofsymfony/user-bundle", @@ -1071,12 +1071,12 @@ "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git", - "reference": "e39b040e272c72f0a090c67d802e1d3b2d0b0313" + "reference": "e5e7a2b8984da8dfedaf44adc7e5f60a62ad280c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/e39b040e272c72f0a090c67d802e1d3b2d0b0313", - "reference": "e39b040e272c72f0a090c67d802e1d3b2d0b0313", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/e5e7a2b8984da8dfedaf44adc7e5f60a62ad280c", + "reference": "e5e7a2b8984da8dfedaf44adc7e5f60a62ad280c", "shasum": "" }, "require": { @@ -1132,7 +1132,7 @@ "keywords": [ "User management" ], - "time": "2015-12-05 09:38:57" + "time": "2015-12-28 18:02:43" }, { "name": "gedmo/doctrine-extensions", -- cgit v1.2.3 From c5c7f90a81d7a2082c7b6dad38c2a6dfdba8d016 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Sun, 3 Jan 2016 10:32:56 +0100 Subject: Fix tag related test for Pocket --- src/Wallabag/ImportBundle/Import/PocketImport.php | 5 +++-- src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index b1c5bb00..853ad135 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -184,13 +184,14 @@ class PocketImport implements ImportInterface $label = trim($tag['tag']); $tagEntity = $this->em ->getRepository('WallabagCoreBundle:Tag') - ->findOneByLabelAndUserId($label, $this->user->getId()); + ->findOneByLabel($label); if (is_object($tagEntity)) { $entry->addTag($tagEntity); } else { - $newTag = new Tag($this->user); + $newTag = new Tag(); $newTag->setLabel($label); + $entry->addTag($newTag); } $this->em->flush(); diff --git a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php index 6ee70db0..1fc2dfa6 100644 --- a/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php +++ b/src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php @@ -260,7 +260,9 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase ->getMock(); $tagRepo->expects($this->exactly(2)) - ->method('findOneByLabelAndUserId') + // the method `findOneByLabel` doesn't exist, EntityRepository will then call `_call` method + // to magically call the `findOneBy` with ['label' => 'foo'] + ->method('__call') ->will($this->onConsecutiveCalls(false, $tag)); $this->em -- cgit v1.2.3 From 8eedc8cfacc07e998f6f0bcdfe5b76496a215ea2 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Sun, 3 Jan 2016 10:59:55 +0100 Subject: Few phpDoc fix And some little mistakes --- .../ApiBundle/Controller/WallabagRestController.php | 20 +++++++++++++++----- src/Wallabag/CoreBundle/Command/InstallCommand.php | 1 - src/Wallabag/CoreBundle/Entity/Config.php | 9 +++++---- src/Wallabag/CoreBundle/Entity/Entry.php | 8 ++++---- src/Wallabag/ImportBundle/Import/PocketImport.php | 3 ++- .../ImportBundle/Import/WallabagV1Import.php | 2 +- 6 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 459c4172..354a6f8e 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php @@ -60,7 +60,7 @@ class WallabagRestController extends FOSRestController * } * ) * - * @return Entry + * @return Response */ public function getEntriesAction(Request $request) { @@ -101,7 +101,7 @@ class WallabagRestController extends FOSRestController * } * ) * - * @return Entry + * @return Response */ public function getEntryAction(Entry $entry) { @@ -124,7 +124,7 @@ class WallabagRestController extends FOSRestController * } * ) * - * @return Entry + * @return Response */ public function postEntriesAction(Request $request) { @@ -166,7 +166,7 @@ class WallabagRestController extends FOSRestController * } * ) * - * @return Entry + * @return Response */ public function patchEntriesAction(Entry $entry, Request $request) { @@ -211,7 +211,7 @@ class WallabagRestController extends FOSRestController * } * ) * - * @return Entry + * @return Response */ public function deleteEntriesAction(Entry $entry) { @@ -235,6 +235,8 @@ class WallabagRestController extends FOSRestController * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} * } * ) + * + * @return Response */ public function getEntriesTagsAction(Entry $entry) { @@ -257,6 +259,8 @@ class WallabagRestController extends FOSRestController * {"name"="tags", "dataType"="string", "required"=false, "format"="tag1,tag2,tag3", "description"="a comma-separated list of tags."}, * } * ) + * + * @return Response */ public function postEntriesTagsAction(Request $request, Entry $entry) { @@ -286,6 +290,8 @@ class WallabagRestController extends FOSRestController * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} * } * ) + * + * @return Response */ public function deleteEntriesTagsAction(Entry $entry, Tag $tag) { @@ -306,6 +312,8 @@ class WallabagRestController extends FOSRestController * Retrieve all tags. * * @ApiDoc() + * + * @return Response */ public function getTagsAction() { @@ -328,6 +336,8 @@ class WallabagRestController extends FOSRestController * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"} * } * ) + * + * @return Response */ public function deleteTagAction(Tag $tag) { diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index 85c4ee90..e791d4dd 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php @@ -11,7 +11,6 @@ use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Helper\Table; -use Wallabag\UserBundle\Entity\User; use Wallabag\CoreBundle\Entity\Config; class InstallCommand extends ContainerAwareCommand diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php index 2ca4182e..d3590f35 100644 --- a/src/Wallabag/CoreBundle/Entity/Config.php +++ b/src/Wallabag/CoreBundle/Entity/Config.php @@ -5,6 +5,7 @@ namespace Wallabag\CoreBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; +use Wallabag\UserBundle\Entity\User; /** * Config. @@ -86,7 +87,7 @@ class Config /* * @param User $user */ - public function __construct(\Wallabag\UserBundle\Entity\User $user) + public function __construct(User $user) { $this->user = $user; $this->taggingRules = new ArrayCollection(); @@ -181,7 +182,7 @@ class Config * * @return Config */ - public function setUser(\Wallabag\UserBundle\Entity\User $user = null) + public function setUser(User $user = null) { $this->user = $user; @@ -225,7 +226,7 @@ class Config /** * Set rssLimit. * - * @param string $rssLimit + * @param int $rssLimit * * @return Config */ @@ -239,7 +240,7 @@ class Config /** * Get rssLimit. * - * @return string + * @return int */ public function getRssLimit() { diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php index b413c489..f11a7786 100644 --- a/src/Wallabag/CoreBundle/Entity/Entry.php +++ b/src/Wallabag/CoreBundle/Entity/Entry.php @@ -245,7 +245,7 @@ class Entry /** * Set isArchived. * - * @param string $isArchived + * @param bool $isArchived * * @return Entry */ @@ -259,7 +259,7 @@ class Entry /** * Get isArchived. * - * @return string + * @return bool */ public function isArchived() { @@ -276,7 +276,7 @@ class Entry /** * Set isStarred. * - * @param string $isStarred + * @param bool $isStarred * * @return Entry */ @@ -290,7 +290,7 @@ class Entry /** * Get isStarred. * - * @return string + * @return bool */ public function isStarred() { diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 853ad135..267c4af5 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -18,6 +18,7 @@ class PocketImport implements ImportInterface private $em; private $contentProxy; private $logger; + private $client; private $consumerKey; private $skippedEntries = 0; private $importedEntries = 0; @@ -255,7 +256,7 @@ class PocketImport implements ImportInterface // flush every 20 entries if (($i % 20) === 0) { - $em->flush(); + $this->em->flush(); } ++$i; } diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php index aff5af40..0866ebe9 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php @@ -149,7 +149,7 @@ class WallabagV1Import implements ImportInterface // flush every 20 entries if (($i % 20) === 0) { - $em->flush(); + $this->em->flush(); } ++$i; } -- cgit v1.2.3 From d1af8ad4dbf7f3ce5170655c2fa8403406283039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Tue, 5 Jan 2016 22:38:09 +0100 Subject: Added french translations --- .../CoreBundle/Resources/translations/messages.fr.yml | 12 ++++++++++++ src/Wallabag/ImportBundle/Import/PocketImport.php | 7 +++++-- src/Wallabag/ImportBundle/Import/WallabagV1Import.php | 9 ++++++--- src/Wallabag/ImportBundle/Resources/config/services.yml | 2 ++ .../ImportBundle/Resources/views/Import/index.html.twig | 2 +- .../ImportBundle/Resources/views/Pocket/index.html.twig | 2 +- .../ImportBundle/Resources/views/WallabagV1/index.html.twig | 2 +- 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml index 7b10dea1..3140091c 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml @@ -13,6 +13,7 @@ archive: 'Lus' all: 'Tous les articles' tags: 'Tags' config: 'Configuration' +import: 'Importer' howto: 'Aide' logout: 'Déconnexion' Filtered: 'Articles filtrés' @@ -128,3 +129,14 @@ Download: 'Télécharger' Does this article appear wrong?: "Est-ce que cet article s'affiche mal ?" Problems?: 'Un problème ?' Edit title: "Modifier le titre" + +# Import +Welcome on wallabag importer. Please select your previous service that you want to migrate.: "Bienvenue dans l'outil de migration de wallabag. Choisissez ci-dessous le service depuis lequel vous souhaitez migrer." +"This importer will import all your Pocket data. Pocket doesn't allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag.": "Cet outil va importer toutes vos données de Pocket. Pocket ne nous autorise pas à récupérer le contenu depuis leur service, donc wallabag doit reparcourir chaque article pour récupérer son contenu." +"This importer will import all your wallabag v1 articles. On your config page, click on \"JSON export\" in the \"Export your wallabag data\" section. You will have a \"wallabag-export-1-xxxx-xx-xx.json\" file.": "Cet outil va importer toutes vos données de wallabag v1. Sur votre page de configuration de wallabag v1, cliquez sur \"Export JSON\" dans la section \"Exporter vos données de wallabag\". Vous allez récupérer un fichier \"wallabag-export-1-xxxx-xx-xx.json\"." +"You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.": "Vous pouvez importer vos données depuis votre compte Pocket. Vous n'avez qu'à cliquer sur le bouton ci-dessous et à autoriser wallabag à se connecter à getpocket.com." +Connect to Pocket and import data: Se connecter à Pocket et importer les données. +Please select your wallabag export and click on the below button to upload and import it.: Choisissez le fichier de votre export wallabag v1 et cliquez sur le bouton ci-dessous pour l'importer. +File: Fichier +Upload file: Importer le fichier +Import contents: "Importer les contenus" \ No newline at end of file diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 267c4af5..9b82720a 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -11,6 +11,7 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInt use Wallabag\CoreBundle\Entity\Entry; use Wallabag\CoreBundle\Entity\Tag; use Wallabag\CoreBundle\Helper\ContentProxy; +use Symfony\Component\Translation\TranslatorInterface; class PocketImport implements ImportInterface { @@ -23,14 +24,16 @@ class PocketImport implements ImportInterface private $skippedEntries = 0; private $importedEntries = 0; protected $accessToken; + private $translator; - public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, $consumerKey) + public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, $consumerKey, TranslatorInterface $translator) { $this->user = $tokenStorage->getToken()->getUser(); $this->em = $em; $this->contentProxy = $contentProxy; $this->consumerKey = $consumerKey; $this->logger = new NullLogger(); + $this->translator = $translator; } public function setLogger(LoggerInterface $logger) @@ -59,7 +62,7 @@ class PocketImport implements ImportInterface */ public function getDescription() { - return 'This importer will import all your Pocket data. Pocket doesn\'t allow us to retrieve content from their service, so the readable content of each article will be re-fetched by Wallabag.'; + return $this->translator->trans("This importer will import all your Pocket data. Pocket doesn't allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag."); } /** diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php index 0866ebe9..68f0574f 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php @@ -5,6 +5,7 @@ namespace Wallabag\ImportBundle\Import; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Doctrine\ORM\EntityManager; +use Symfony\Component\Translation\TranslatorInterface; use Wallabag\CoreBundle\Entity\Entry; use Wallabag\UserBundle\Entity\User; use Wallabag\CoreBundle\Tools\Utils; @@ -17,11 +18,13 @@ class WallabagV1Import implements ImportInterface private $skippedEntries = 0; private $importedEntries = 0; private $filepath; + private $translator; - public function __construct(EntityManager $em) + public function __construct(EntityManager $em, TranslatorInterface $translator) { $this->em = $em; $this->logger = new NullLogger(); + $this->translator = $translator; } public function setLogger(LoggerInterface $logger) @@ -47,7 +50,7 @@ class WallabagV1Import implements ImportInterface */ public function getName() { - return 'Wallabag v1'; + return 'wallabag v1'; } /** @@ -63,7 +66,7 @@ class WallabagV1Import implements ImportInterface */ public function getDescription() { - return 'This importer will import all your wallabag v1 articles. On your config page, click on "JSON export" in the "Export your wallabag data" section. You will have a "wallabag-export-1-xxxx-xx-xx.json" file.'; + return $this->translator->trans('This importer will import all your wallabag v1 articles. On your config page, click on "JSON export" in the "Export your wallabag data" section. You will have a "wallabag-export-1-xxxx-xx-xx.json" file.'); } /** diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index e4dde100..55348ce7 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -18,6 +18,7 @@ services: - "@doctrine.orm.entity_manager" - "@wallabag_core.content_proxy" - %pocket_consumer_key% + - "@translator" calls: - [ setClient, [ "@wallabag_import.pocket.client" ] ] - [ setLogger, [ "@logger" ]] @@ -28,6 +29,7 @@ services: class: Wallabag\ImportBundle\Import\WallabagV1Import arguments: - "@doctrine.orm.entity_manager" + - "@translator" calls: - [ setLogger, [ "@logger" ]] tags: diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index 27baa1e3..1f0addca 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -11,7 +11,7 @@
  • {{ import.name }}
    {{ import.description|raw }}
    -

    Import contents

    +

    {% trans %}Import contents{% endtrans %}

  • {% endfor %} diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig index 9803896c..58053780 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -9,7 +9,7 @@

    {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %}

    diff --git a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig index 23d3e146..afc57226 100644 --- a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig @@ -15,7 +15,7 @@
    {{ form_errors(form.file) }}
    - File + {% trans %}File{% endtrans %} {{ form_widget(form.file) }}
    -- cgit v1.2.3 From b88cf91fc8371194df78e690983c61ea94f266cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Wed, 6 Jan 2016 06:34:57 +0100 Subject: updated tests --- src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml | 2 +- src/Wallabag/ImportBundle/Import/PocketImport.php | 6 ++---- src/Wallabag/ImportBundle/Import/WallabagV1Import.php | 7 ++----- src/Wallabag/ImportBundle/Resources/config/services.yml | 2 -- src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig | 2 +- src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig | 2 +- .../ImportBundle/Resources/views/WallabagV1/index.html.twig | 2 +- src/Wallabag/ImportBundle/Tests/Import/PocketImportTest.php | 2 +- src/Wallabag/ImportBundle/Tests/Import/WallabagV1ImportTest.php | 2 +- 9 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml index 3140091c..06746584 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml @@ -132,7 +132,7 @@ Edit title: "Modifier le titre" # Import Welcome on wallabag importer. Please select your previous service that you want to migrate.: "Bienvenue dans l'outil de migration de wallabag. Choisissez ci-dessous le service depuis lequel vous souhaitez migrer." -"This importer will import all your Pocket data. Pocket doesn't allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag.": "Cet outil va importer toutes vos données de Pocket. Pocket ne nous autorise pas à récupérer le contenu depuis leur service, donc wallabag doit reparcourir chaque article pour récupérer son contenu." +"This importer will import all your Pocket data. Pocket doesn't allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag.": "Cet outil va importer toutes vos données de Pocket. Pocket ne nous autorise pas à récupérer le contenu depuis leur service, donc wallabag doit reparcourir chaque article pour récupérer son contenu." "This importer will import all your wallabag v1 articles. On your config page, click on \"JSON export\" in the \"Export your wallabag data\" section. You will have a \"wallabag-export-1-xxxx-xx-xx.json\" file.": "Cet outil va importer toutes vos données de wallabag v1. Sur votre page de configuration de wallabag v1, cliquez sur \"Export JSON\" dans la section \"Exporter vos données de wallabag\". Vous allez récupérer un fichier \"wallabag-export-1-xxxx-xx-xx.json\"." "You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.": "Vous pouvez importer vos données depuis votre compte Pocket. Vous n'avez qu'à cliquer sur le bouton ci-dessous et à autoriser wallabag à se connecter à getpocket.com." Connect to Pocket and import data: Se connecter à Pocket et importer les données. diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php index 9b82720a..cdcec1e2 100644 --- a/src/Wallabag/ImportBundle/Import/PocketImport.php +++ b/src/Wallabag/ImportBundle/Import/PocketImport.php @@ -11,7 +11,6 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInt use Wallabag\CoreBundle\Entity\Entry; use Wallabag\CoreBundle\Entity\Tag; use Wallabag\CoreBundle\Helper\ContentProxy; -use Symfony\Component\Translation\TranslatorInterface; class PocketImport implements ImportInterface { @@ -26,14 +25,13 @@ class PocketImport implements ImportInterface protected $accessToken; private $translator; - public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, $consumerKey, TranslatorInterface $translator) + public function __construct(TokenStorageInterface $tokenStorage, EntityManager $em, ContentProxy $contentProxy, $consumerKey) { $this->user = $tokenStorage->getToken()->getUser(); $this->em = $em; $this->contentProxy = $contentProxy; $this->consumerKey = $consumerKey; $this->logger = new NullLogger(); - $this->translator = $translator; } public function setLogger(LoggerInterface $logger) @@ -62,7 +60,7 @@ class PocketImport implements ImportInterface */ public function getDescription() { - return $this->translator->trans("This importer will import all your Pocket data. Pocket doesn't allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag."); + return 'This importer will import all your Pocket data. Pocket doesn\'t allow us to retrieve content from their service, so the readable content of each article will be re-fetched by wallabag.'; } /** diff --git a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php index 68f0574f..393089d6 100644 --- a/src/Wallabag/ImportBundle/Import/WallabagV1Import.php +++ b/src/Wallabag/ImportBundle/Import/WallabagV1Import.php @@ -5,7 +5,6 @@ namespace Wallabag\ImportBundle\Import; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Doctrine\ORM\EntityManager; -use Symfony\Component\Translation\TranslatorInterface; use Wallabag\CoreBundle\Entity\Entry; use Wallabag\UserBundle\Entity\User; use Wallabag\CoreBundle\Tools\Utils; @@ -18,13 +17,11 @@ class WallabagV1Import implements ImportInterface private $skippedEntries = 0; private $importedEntries = 0; private $filepath; - private $translator; - public function __construct(EntityManager $em, TranslatorInterface $translator) + public function __construct(EntityManager $em) { $this->em = $em; $this->logger = new NullLogger(); - $this->translator = $translator; } public function setLogger(LoggerInterface $logger) @@ -66,7 +63,7 @@ class WallabagV1Import implements ImportInterface */ public function getDescription() { - return $this->translator->trans('This importer will import all your wallabag v1 articles. On your config page, click on "JSON export" in the "Export your wallabag data" section. You will have a "wallabag-export-1-xxxx-xx-xx.json" file.'); + return 'This importer will import all your wallabag v1 articles. On your config page, click on "JSON export" in the "Export your wallabag data" section. You will have a "wallabag-export-1-xxxx-xx-xx.json" file.'; } /** diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index 55348ce7..e4dde100 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -18,7 +18,6 @@ services: - "@doctrine.orm.entity_manager" - "@wallabag_core.content_proxy" - %pocket_consumer_key% - - "@translator" calls: - [ setClient, [ "@wallabag_import.pocket.client" ] ] - [ setLogger, [ "@logger" ]] @@ -29,7 +28,6 @@ services: class: Wallabag\ImportBundle\Import\WallabagV1Import arguments: - "@doctrine.orm.entity_manager" - - "@translator" calls: - [ setLogger, [ "@logger" ]] tags: diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index 1f0addca..303e6cbf 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig @@ -10,7 +10,7 @@ {% for import in imports %}
  • {{ import.name }}
    -
    {{ import.description|raw }}
    +
    {{ import.description|trans }}

    {% trans %}Import contents{% endtrans %}

  • {% endfor %} diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig index 58053780..643ad775 100644 --- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig +++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig @@ -5,7 +5,7 @@
    -
    {{ import.description|raw }}
    +
    {{ import.description|trans }}

    {% trans %}You can import your data from your Pocket account. You just have to click on the below button and authorize the application to connect to getpocket.com.{% endtrans %}