From ae669126e718ede5dbf76929215d8514cd960976 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Tue, 12 Jul 2016 13:51:05 +0200 Subject: [PATCH] Import Firefox & Chrome bookmarks into wallabag --- .../Resources/translations/messages.da.yml | 4 + .../Resources/translations/messages.de.yml | 4 + .../Resources/translations/messages.en.yml | 4 + .../Resources/translations/messages.es.yml | 4 + .../Resources/translations/messages.fa.yml | 4 + .../Resources/translations/messages.fr.yml | 6 +- .../Resources/translations/messages.it.yml | 4 + .../Resources/translations/messages.oc.yml | 4 + .../Resources/translations/messages.pl.yml | 4 + .../Resources/translations/messages.ro.yml | 4 + .../Resources/translations/messages.tr.yml | 4 + .../ImportBundle/Command/ImportCommand.php | 19 +- .../Controller/BrowserController.php | 91 +++++++ .../ImportBundle/Import/BrowserImport.php | 227 ++++++++++++++++++ .../Resources/config/services.yml | 10 + .../Resources/views/Browser/index.html.twig | 43 ++++ .../Resources/views/Import/index.html.twig | 2 +- .../Controller/BrowserControllerTest.php | 94 ++++++++ .../Wallabag/ImportBundle/fixtures/Bookmarks | 61 +++++ 19 files changed, 586 insertions(+), 7 deletions(-) create mode 100644 src/Wallabag/ImportBundle/Controller/BrowserController.php create mode 100644 src/Wallabag/ImportBundle/Import/BrowserImport.php create mode 100644 src/Wallabag/ImportBundle/Resources/views/Browser/index.html.twig create mode 100644 tests/Wallabag/ImportBundle/Controller/BrowserControllerTest.php create mode 100644 tests/Wallabag/ImportBundle/fixtures/Bookmarks diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml index c6fcb355..f9f4a958 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml @@ -349,6 +349,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: # page_title: 'Developer' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml index c0e82b59..c1196be5 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml @@ -349,6 +349,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: page_title: 'Entwickler' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml index 6f262209..99bd4079 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml @@ -349,6 +349,10 @@ import: how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + browser: + page_title: 'Import > Browser' + description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: page_title: 'Developer' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml index 7b981069..5ffeab07 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml @@ -349,6 +349,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: page_title: 'Promotor' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml index 99fcc378..fa2c3ca9 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml @@ -349,6 +349,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: # page_title: 'Developer' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml index dd82e7f5..b24cfa26 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml @@ -349,6 +349,10 @@ import: how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l'importer." worker: enabled: "Les imports sont asynchrones. Une fois l'import commencé un worker externe traitera les messages un par un. Le service activé est :" + browser: + page_title: 'Import > Navigateur' + description: "Cet outil va vous permettre d'importer tous vos marques-pages de Firefox ou de Google Chrome/Chromium.

Pour Firefox, ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json.

Pour Google Chrome, la situation du fichier dépend de votre système d'exploitation : Une fois que vous y êtes, copiez le fichier Bookmarks à un endroit où vous le retrouverez.
Notez que si vous utilisez Chromium à la place de Chrome, vous devez corriger les chemins en conséquence.

" + how_to: "Choisissez le fichier de sauvegarde de vos marques-page et cliquez sur le bouton pour l'importer. Soyez avertis que le processus peut prendre un temps assez long car tous les articles doivent être récupérés en ligne." developer: page_title: 'Développeur' @@ -432,7 +436,7 @@ flashes: notice: failed: "L'import a échoué, veuillez ré-essayer" failed_on_file: "Erreur lors du traitement de l'import. Vérifier votre fichier." - summary: "Rapport d'import: %imported% importés, %skipped% déjà présent." + summary: "Rapport d'import: %imported% importés, %skipped% déjà présents." summary_with_queue: "Rapport d'import: %queued% en cours de traitement." error: redis_enabled_not_installed: Redis est activé pour les imports asynchrones mais impossible de s'y connecter. Vérifier la configuration de Redis. diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml index d3ce30c9..f6aa245e 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml @@ -348,6 +348,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.Note that you may have Chromium instead of Chrome and have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched" developer: page_title: 'Sviluppatori' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml index d040daea..596c764f 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml @@ -349,6 +349,10 @@ import: how_to: "Mercés de seleccionar vòstre Readability fichièr e de clicar sul boton dejós per lo telecargar e l'importar." worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: page_title: 'Desvolopador' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml index a51ed1f2..bf0da022 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml @@ -349,6 +349,10 @@ import: how_to: 'Wybierz swój plik eksportu z Readability i kliknij poniższy przycisk, aby go załadować.' worker: enabled: "Import jest wykonywany asynchronicznie. Od momentu rozpoczęcia importu, zewnętrzna usługa może zajmować się na raz tylko jednym zadaniem. Bieżącą usługą jest:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: page_title: 'Deweloper' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml index de21f0b3..928589cb 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml @@ -349,6 +349,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: # page_title: 'Developer' diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml index d4b7a7a2..723b1edb 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml @@ -349,6 +349,10 @@ import: # how_to: 'Please select your Readability export and click on the below button to upload and import it.' worker: # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" + # browser: + # page_title: 'Import > Browser' + # description: "This importer will import all your Firefox or Chrome bookmarks.

For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file.

For Chrome, the location of the file depends on your operating system : Once you got there, copy the Bookmarks file someplace you'll find.
Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.

" + # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched." developer: # page_title: 'Developer' diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php index 20ecc6e1..537dffc2 100644 --- a/src/Wallabag/ImportBundle/Command/ImportCommand.php +++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php @@ -17,7 +17,7 @@ class ImportCommand extends ContainerAwareCommand ->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') - ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: v1 or v2', 'v1') + ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: wallabag v1, v2 or browser', 'v1') ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false) ; } @@ -40,10 +40,19 @@ class ImportCommand extends ContainerAwareCommand throw new Exception(sprintf('User with id "%s" not found', $input->getArgument('userId'))); } - $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v1.import'); - - if ('v2' === $input->getOption('importer')) { - $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v2.import'); + switch ($input->getOption('importer')) { + case 'v2': + $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v2.import'); + break; + case 'v1': + $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v1.import'); + break; + case 'browser': + $wallabag = $this->getContainer()->get('wallabag_import.browser.import'); + break; + default: + $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v1.import'); + break; } $wallabag->setMarkAsRead($input->getOption('markAsRead')); diff --git a/src/Wallabag/ImportBundle/Controller/BrowserController.php b/src/Wallabag/ImportBundle/Controller/BrowserController.php new file mode 100644 index 00000000..3b54a72e --- /dev/null +++ b/src/Wallabag/ImportBundle/Controller/BrowserController.php @@ -0,0 +1,91 @@ +get('wallabag_import.browser.import'); + } + + /** + * Return the template used for the form. + * + * @return string + */ + protected function getImportTemplate() + { + return 'WallabagImportBundle:Browser:index.html.twig'; + } + + /** + * @Route("/browser", name="import_browser") + * + * @param Request $request + * + * @return Response + */ + public function indexAction(Request $request) + { + $form = $this->createForm(UploadImportType::class); + $form->handleRequest($request); + + $wallabag = $this->getImportService(); + + if ($form->isValid()) { + $file = $form->get('file')->getData(); + $markAsRead = $form->get('mark_as_read')->getData(); + $name = $this->getUser()->getId().'.json'; + + if (in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) { + $res = $wallabag + ->setUser($this->getUser()) + ->setFilepath($this->getParameter('wallabag_import.resource_dir').'/'.$name) + ->setMarkAsRead($markAsRead) + ->import(); + + $message = 'flashes.import.notice.failed'; + + if (true === $res) { + $summary = $wallabag->getSummary(); + // TODO : Pluralize these messages + $message = $this->get('translator')->trans('flashes.import.notice.summary', [ + '%imported%' => $summary['imported'], + '%skipped%' => $summary['skipped'], + ]); + + 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', + 'flashes.import.notice.failed_on_file' + ); + } + } + + return $this->render($this->getImportTemplate(), [ + 'form' => $form->createView(), + 'import' => $wallabag, + ]); + } +} diff --git a/src/Wallabag/ImportBundle/Import/BrowserImport.php b/src/Wallabag/ImportBundle/Import/BrowserImport.php new file mode 100644 index 00000000..263a11d5 --- /dev/null +++ b/src/Wallabag/ImportBundle/Import/BrowserImport.php @@ -0,0 +1,227 @@ +em = $em; + $this->logger = new NullLogger(); + $this->contentProxy = $contentProxy; + } + + 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 + * + * @return $this + */ + public function setUser(User $user) + { + $this->user = $user; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'Firefox & Google Chrome'; + } + + /** + * {@inheritdoc} + */ + public function getUrl() + { + return 'import_browser'; + } + + /** + * {@inheritdoc} + */ + public function getDescription() + { + return 'import.browser.description'; + } + + /** + * {@inheritdoc} + */ + public function import() + { + if (!$this->user) { + $this->logger->error('WallabagImport: user is not defined'); + + return false; + } + + if (!file_exists($this->filepath) || !is_readable($this->filepath)) { + $this->logger->error('WallabagImport: unable to read file', ['filepath' => $this->filepath]); + + return false; + } + + $data = json_decode(file_get_contents($this->filepath), true); + + if (empty($data)) { + return false; + } + + $this->nbEntries = 1; + $this->parseEntries($data); + $this->em->flush(); + + return true; + } + + private function parseEntries($data) + { + foreach ($data as $importedEntry) { + $this->parseEntry($importedEntry); + } + $this->totalEntries += count($data); + } + + private function parseEntry($importedEntry) + { + if (!is_array($importedEntry)) { + return; + } + + /* Firefox uses guid while Chrome uses id */ + + if ((!key_exists('guid', $importedEntry) || (!key_exists('id', $importedEntry))) && is_array(reset($importedEntry))) { + $this->parseEntries($importedEntry); + + return; + } + if (key_exists('children', $importedEntry)) { + $this->parseEntries($importedEntry['children']); + + return; + } + if (key_exists('uri', $importedEntry) || key_exists('url', $importedEntry)) { + + /* Firefox uses uri while Chrome uses url */ + + $firefox = key_exists('uri', $importedEntry); + + $existingEntry = $this->em + ->getRepository('WallabagCoreBundle:Entry') + ->findByUrlAndUserId(($firefox) ? $importedEntry['uri'] : $importedEntry['url'], $this->user->getId()); + + if (false !== $existingEntry) { + ++$this->skippedEntries; + + return; + } + + if (false === parse_url(($firefox) ? $importedEntry['uri'] : $importedEntry['url']) || false === filter_var(($firefox) ? $importedEntry['uri'] : $importedEntry['url'], FILTER_VALIDATE_URL)) { + $this->logger->warning('Imported URL '.($firefox) ? $importedEntry['uri'] : $importedEntry['url'].' is not valid'); + ++$this->skippedEntries; + + return; + } + + try { + $entry = $this->contentProxy->updateEntry( + new Entry($this->user), + ($firefox) ? $importedEntry['uri'] : $importedEntry['url'] + ); + } catch (\Exception $e) { + $this->logger->warning('Error while saving '.($firefox) ? $importedEntry['uri'] : $importedEntry['url']); + ++$this->skippedEntries; + + return; + } + + $entry->setArchived($this->markAsRead); + + $this->em->persist($entry); + ++$this->importedEntries; + + // flush every 20 entries + if (($this->nbEntries % 20) === 0) { + $this->em->flush(); + $this->em->clear($entry); + } + ++$this->nbEntries; + + /* + + Maybe not useful. Delete at will. + + */ + + $this->logger->info($this->nbEntries.' / '.$this->totalEntries); + } + } + + /** + * Set whether articles must be all marked as read. + * + * @param bool $markAsRead + * + * @return $this + */ + public function setMarkAsRead($markAsRead) + { + $this->markAsRead = $markAsRead; + + return $this; + } + + /** + * Set file path to the json file. + * + * @param string $filepath + * + * @return $this + */ + public function setFilepath($filepath) + { + $this->filepath = $filepath; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getSummary() + { + return [ + 'skipped' => $this->skippedEntries, + 'imported' => $this->importedEntries, + ]; + } +} diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml index f03404ae..d8be5c28 100644 --- a/src/Wallabag/ImportBundle/Resources/config/services.yml +++ b/src/Wallabag/ImportBundle/Resources/config/services.yml @@ -56,3 +56,13 @@ services: - [ setLogger, [ "@logger" ]] tags: - { name: wallabag_import.import, alias: readability } + + wallabag_import.browser.import: + class: Wallabag\ImportBundle\Import\BrowserImport + arguments: + - "@doctrine.orm.entity_manager" + - "@wallabag_core.content_proxy" + calls: + - [ setLogger, [ "@logger" ]] + tags: + - { name: wallabag_import.import, alias: browser } diff --git a/src/Wallabag/ImportBundle/Resources/views/Browser/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Browser/index.html.twig new file mode 100644 index 00000000..bfc74e9d --- /dev/null +++ b/src/Wallabag/ImportBundle/Resources/views/Browser/index.html.twig @@ -0,0 +1,43 @@ +{% extends "WallabagCoreBundle::layout.html.twig" %} + +{% block title %}{{ 'import.browser.page_title'|trans }}{% endblock %} + +{% block content %} +
+
+
+
+
{{ import.description|trans|raw }}
+

{{ 'import.browser.how_to'|trans }}

+ +
+ {{ form_start(form, {'method': 'POST'}) }} + {{ form_errors(form) }} +
+
+ {{ form_errors(form.file) }} +
+ {{ form.file.vars.label|trans }} + {{ form_widget(form.file) }} +
+
+ +
+
+
+
{{ 'import.form.mark_as_read_title'|trans }}
+ {{ form_widget(form.mark_as_read) }} + {{ form_label(form.mark_as_read) }} +
+
+ + {{ form_widget(form.save, { 'attr': {'class': 'btn waves-effect waves-light'} }) }} + + {{ form_rest(form) }} + +
+
+
+
+
+{% endblock %} diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig index aebbfa20..6ea5e0f4 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 @@ {% for import in imports %}
  • {{ import.name }}
    -
    {{ import.description|trans }}
    +
    {{ import.description|trans|raw }}

    {{ 'import.action.import_contents'|trans }}

  • {% endfor %} diff --git a/tests/Wallabag/ImportBundle/Controller/BrowserControllerTest.php b/tests/Wallabag/ImportBundle/Controller/BrowserControllerTest.php new file mode 100644 index 00000000..8016227c --- /dev/null +++ b/tests/Wallabag/ImportBundle/Controller/BrowserControllerTest.php @@ -0,0 +1,94 @@ +logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/browser'); + + $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/browser'); + $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form(); + + $file = new UploadedFile(__DIR__.'/../fixtures/Bookmarks', 'Bookmarks'); + + $data = [ + 'upload_import_file[file]' => $file, + ]; + + $client->submit($form, $data); + + $this->assertEquals(302, $client->getResponse()->getStatusCode()); + + $crawler = $client->followRedirect(); + + $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); + $this->assertContains('flashes.import.notice.summary', $body[0]); + + $content = $client->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('WallabagCoreBundle:Entry') + ->findByUrlAndUserId( + 'http://lexpansion.lexpress.fr/high-tech/orange-offre-un-meilleur-reseau-mobile-que-bouygues-et-sfr-free-derriere_1811554.html', + $this->getLoggedInUserId() + ); + + $this->assertNotEmpty($content->getMimetype()); + $this->assertNotEmpty($content->getPreviewPicture()); + $this->assertNotEmpty($content->getLanguage()); + $this->assertEquals(0, count($content->getTags())); + + $content = $client->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('WallabagCoreBundle:Entry') + ->findByUrlAndUserId( + 'http://stackoverflow.com/questions/15017163/parser-for-exported-bookmarks-html-file-of-google-chrome-and-mozilla-in-java', + $this->getLoggedInUserId() + ); + + $this->assertNotEmpty($content->getMimetype()); + $this->assertNotEmpty($content->getPreviewPicture()); + $this->assertEmpty($content->getLanguage()); + } + + public function testImportWallabagWithEmptyFile() + { + $this->logInAs('admin'); + $client = $this->getClient(); + + $crawler = $client->request('GET', '/import/browser'); + $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form(); + + $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt'); + + $data = [ + 'upload_import_file[file]' => $file, + ]; + + $client->submit($form, $data); + + $this->assertEquals(302, $client->getResponse()->getStatusCode()); + + $crawler = $client->followRedirect(); + + $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); + $this->assertContains('flashes.import.notice.failed', $body[0]); + } +} diff --git a/tests/Wallabag/ImportBundle/fixtures/Bookmarks b/tests/Wallabag/ImportBundle/fixtures/Bookmarks new file mode 100644 index 00000000..8b78b8a4 --- /dev/null +++ b/tests/Wallabag/ImportBundle/fixtures/Bookmarks @@ -0,0 +1,61 @@ +{ + "checksum": "ef1e30cddf64cb94c63d7835640165be", + "roots": { + "bookmark_bar": { + "children": [ { + "date_added": "13112787540531997", + "id": "7", + "name": "Terrorisme: les sombres prédictions du directeur de la DGSI", + "type": "url", + "url": "http://www.lefigaro.fr/actualite-france/2016/07/12/01016-20160712ARTFIG00016-terrorisme-les-sombres-perspectives-de-patrick-calvar-directeur-de-la-dgsi.php" + } ], + "date_added": "13112787380480144", + "date_modified": "13112787542724942", + "id": "1", + "name": "Bookmarks bar", + "type": "folder" + }, + "other": { + "children": [ { + "date_added": "13112787503900822", + "id": "6", + "name": "Parser for Exported Bookmarks HTML file of Google Chrome and Mozilla in Java - Stack Overflow", + "type": "url", + "url": "http://stackoverflow.com/questions/15017163/parser-for-exported-bookmarks-html-file-of-google-chrome-and-mozilla-in-java" + }, { + "children": [ { + "date_added": "13112787564443378", + "id": "9", + "name": "Orange offre un meilleur réseau mobile que Bouygues et SFR, Free derrière - L'Express L'Expansion", + "type": "url", + "url": "http://lexpansion.lexpress.fr/high-tech/orange-offre-un-meilleur-reseau-mobile-que-bouygues-et-sfr-free-derriere_1811554.html" + } ], + "date_added": "13112787556763735", + "date_modified": "13112794390493325", + "id": "8", + "name": "test", + "type": "folder" + }, { + "date_added": "13112794390493325", + "id": "12", + "name": "JSON Formatter & Validator", + "type": "url", + "url": "https://jsonformatter.curiousconcept.com/" + } ], + "date_added": "13112787380480151", + "date_modified": "13112794393509988", + "id": "2", + "name": "Other bookmarks", + "type": "folder" + }, + "synced": { + "children": [ ], + "date_added": "13112787380480155", + "date_modified": "0", + "id": "3", + "name": "Mobile bookmarks", + "type": "folder" + } + }, + "version": 1 +} -- 2.41.0