Merge pull request #1820 from wallabag/import-refacto

Refacto wallabag import
This commit is contained in:
Nicolas Lœuillet 2016-03-28 18:52:22 +02:00
commit e2dda63152
8 changed files with 361 additions and 316 deletions

View file

@ -74,10 +74,9 @@ class InstallCommand extends ContainerAwareCommand
$fulfilled = true;
$label = '<comment>PDO Drivers</comment>';
if (extension_loaded('pdo_sqlite') || extension_loaded('pdo_mysql') || extension_loaded('pdo_pgsql')) {
$status = '<info>OK!</info>';
$help = '';
} else {
$status = '<info>OK!</info>';
$help = '';
if (!(extension_loaded('pdo_sqlite') || extension_loaded('pdo_mysql') || extension_loaded('pdo_pgsql'))) {
$fulfilled = false;
$status = '<error>ERROR!</error>';
$help = 'Needs one of sqlite, mysql or pgsql PDO drivers';
@ -88,11 +87,10 @@ class InstallCommand extends ContainerAwareCommand
foreach ($this->functionExists as $functionRequired) {
$label = '<comment>'.$functionRequired.'</comment>';
$status = '<info>OK!</info>';
$help = '';
if (function_exists($functionRequired)) {
$status = '<info>OK!</info>';
$help = '';
} else {
if (!function_exists($functionRequired)) {
$fulfilled = false;
$status = '<error>ERROR!</error>';
$help = 'You need the '.$functionRequired.' function activated';

View file

@ -367,6 +367,8 @@ class EntriesExport
/**
* Return a Serializer object for producing processes that need it (JSON & XML).
*
* @param string $format
*
* @return Serializer
*/
private function prepareSerializingContent($format)

View file

@ -0,0 +1,85 @@
<?php
namespace Wallabag\ImportBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Wallabag\ImportBundle\Form\Type\UploadImportType;
/**
* Define Wallabag import for v1 and v2, since there are very similar.
*/
abstract class WallabagController extends Controller
{
/**
* Return the service to handle the import.
*
* @return \Wallabag\ImportBundle\Import\ImportInterface
*/
abstract protected function getImportService();
/**
* Return the template used for the form.
*
* @return string
*/
abstract protected function getImportTemplate();
/**
* Handle import request.
*
* @param Request $request
*
* @return Response|RedirectResponse
*/
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();
$message = $this->get('translator')->trans('flashes.import.notice.summary', array(
'%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,
]);
}
}

View file

@ -2,64 +2,32 @@
namespace Wallabag\ImportBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Wallabag\ImportBundle\Form\Type\UploadImportType;
class WallabagV1Controller extends Controller
class WallabagV1Controller extends WallabagController
{
/**
* {@inheritdoc}
*/
protected function getImportService()
{
return $this->get('wallabag_import.wallabag_v1.import');
}
/**
* {@inheritdoc}
*/
protected function getImportTemplate()
{
return 'WallabagImportBundle:WallabagV1:index.html.twig';
}
/**
* @Route("/wallabag-v1", name="import_wallabag_v1")
*/
public function indexAction(Request $request)
{
$form = $this->createForm(UploadImportType::class);
$form->handleRequest($request);
$wallabag = $this->get('wallabag_import.wallabag_v1.import');
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();
$message = $this->get('translator')->trans('flashes.import.notice.summary', array(
'%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('WallabagImportBundle:WallabagV1:index.html.twig', [
'form' => $form->createView(),
'import' => $wallabag,
]);
return parent::indexAction($request);
}
}

View file

@ -2,64 +2,32 @@
namespace Wallabag\ImportBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Wallabag\ImportBundle\Form\Type\UploadImportType;
class WallabagV2Controller extends Controller
class WallabagV2Controller extends WallabagController
{
/**
* {@inheritdoc}
*/
protected function getImportService()
{
return $this->get('wallabag_import.wallabag_v2.import');
}
/**
* {@inheritdoc}
*/
protected function getImportTemplate()
{
return 'WallabagImportBundle:WallabagV2:index.html.twig';
}
/**
* @Route("/wallabag-v2", name="import_wallabag_v2")
*/
public function indexAction(Request $request)
{
$form = $this->createForm(UploadImportType::class);
$form->handleRequest($request);
$wallabag = $this->get('wallabag_import.wallabag_v2.import');
if ($form->isValid()) {
$file = $form->get('file')->getData();
$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();
$message = $this->get('translator')->trans('flashes.import.notice.summary', array(
'%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('WallabagImportBundle:WallabagV2:index.html.twig', [
'form' => $form->createView(),
'import' => $wallabag,
]);
return parent::indexAction($request);
}
}

View file

@ -0,0 +1,204 @@
<?php
namespace Wallabag\ImportBundle\Import;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Doctrine\ORM\EntityManager;
use Wallabag\CoreBundle\Entity\Entry;
use Wallabag\UserBundle\Entity\User;
use Wallabag\CoreBundle\Helper\ContentProxy;
abstract class WallabagImport implements ImportInterface
{
protected $user;
protected $em;
protected $logger;
protected $contentProxy;
protected $skippedEntries = 0;
protected $importedEntries = 0;
protected $filepath;
protected $markAsRead;
// untitled in all languages from v1
protected $untitled = [
'Untitled',
'Sans titre',
'podle nadpisu',
'Sin título',
'با عنوان',
'per titolo',
'Sem título',
'Без названия',
'po naslovu',
'Без назви',
'No title found',
'',
];
public function __construct(EntityManager $em, ContentProxy $contentProxy)
{
$this->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
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* {@inheritdoc}
*/
abstract public function getName();
/**
* {@inheritdoc}
*/
abstract public function getUrl();
/**
* {@inheritdoc}
*/
abstract public function getDescription();
/**
* {@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->parseEntries($data);
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;
}
/**
* Set whether articles must be all marked as read.
*
* @param bool $markAsRead
*/
public function setMarkAsRead($markAsRead)
{
$this->markAsRead = $markAsRead;
return $this;
}
/**
* Parse and insert all given entries.
*
* @param $entries
*/
protected function parseEntries($entries)
{
$i = 1;
foreach ($entries as $importedEntry) {
$existingEntry = $this->em
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId($importedEntry['url'], $this->user->getId());
if (false !== $existingEntry) {
++$this->skippedEntries;
continue;
}
$data = $this->prepareEntry($importedEntry, $this->markAsRead);
$entry = $this->contentProxy->updateEntry(
new Entry($this->user),
$importedEntry['url'],
$data
);
if (array_key_exists('tags', $data)) {
$this->contentProxy->assignTagsToEntry(
$entry,
$data['tags']
);
}
if (isset($importedEntry['preview_picture'])) {
$entry->setPreviewPicture($importedEntry['preview_picture']);
}
$entry->setArchived($data['is_archived']);
$entry->setStarred($data['is_starred']);
$this->em->persist($entry);
++$this->importedEntries;
// flush every 20 entries
if (($i % 20) === 0) {
$this->em->flush();
}
++$i;
}
$this->em->flush();
}
/**
* This should return a cleaned array for a given entry to be given to `updateEntry`.
*
* @param array $entry Data from the imported file
* @param bool $markAsRead Should we mark as read content?
*
* @return array
*/
abstract protected function prepareEntry($entry = [], $markAsRead = false);
}

View file

@ -2,49 +2,8 @@
namespace Wallabag\ImportBundle\Import;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Doctrine\ORM\EntityManager;
use Wallabag\CoreBundle\Entity\Entry;
use Wallabag\UserBundle\Entity\User;
use Wallabag\CoreBundle\Helper\ContentProxy;
class WallabagV1Import implements ImportInterface
class WallabagV1Import extends WallabagImport
{
protected $user;
protected $em;
protected $logger;
protected $contentProxy;
protected $skippedEntries = 0;
protected $importedEntries = 0;
protected $filepath;
protected $markAsRead;
public function __construct(EntityManager $em, ContentProxy $contentProxy)
{
$this->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
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* {@inheritdoc}
*/
@ -72,125 +31,29 @@ class WallabagV1Import implements ImportInterface
/**
* {@inheritdoc}
*/
public function import()
protected function prepareEntry($entry = [], $markAsRead = false)
{
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', array('filepath' => $this->filepath));
return false;
}
$data = json_decode(file_get_contents($this->filepath), true);
if (empty($data)) {
return false;
}
$this->parseEntries($data);
return true;
}
/**
* {@inheritdoc}
*/
public function getSummary()
{
return [
'skipped' => $this->skippedEntries,
'imported' => $this->importedEntries,
$data = [
'title' => $entry['title'],
'html' => $entry['content'],
'url' => $entry['url'],
'content_type' => '',
'language' => '',
'is_archived' => $entry['is_read'] || $markAsRead,
'is_starred' => $entry['is_fav'],
'tags' => '',
];
}
/**
* Set file path to the json file.
*
* @param string $filepath
*/
public function setFilepath($filepath)
{
$this->filepath = $filepath;
return $this;
}
/**
* Set whether articles must be all marked as read.
*
* @param bool $markAsRead
*/
public function setMarkAsRead($markAsRead)
{
$this->markAsRead = $markAsRead;
return $this;
}
/**
* @param $entries
*/
protected function parseEntries($entries)
{
$i = 1;
//Untitled in all languages from v1. This should never have been translated
$untitled = array('Untitled', 'Sans titre', 'podle nadpisu', 'Sin título', 'با عنوان', 'per titolo', 'Sem título', 'Без названия', 'po naslovu', 'Без назви', 'No title found', '');
foreach ($entries as $importedEntry) {
$existingEntry = $this->em
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId($importedEntry['url'], $this->user->getId());
if (false !== $existingEntry) {
++$this->skippedEntries;
continue;
}
$data = [
'title' => $importedEntry['title'],
'html' => $importedEntry['content'],
'url' => $importedEntry['url'],
'content_type' => '',
'language' => '',
];
// force content to be refreshed in case on bad fetch in the v1 installation
if (in_array($importedEntry['title'], $untitled)) {
$data = [];
}
$entry = $this->contentProxy->updateEntry(
new Entry($this->user),
$importedEntry['url'],
$data
);
if (array_key_exists('tags', $importedEntry) && $importedEntry['tags'] != '') {
$this->contentProxy->assignTagsToEntry(
$entry,
$importedEntry['tags']
);
}
$entry->setArchived($importedEntry['is_read'] || $this->markAsRead);
$entry->setStarred($importedEntry['is_fav']);
$this->em->persist($entry);
++$this->importedEntries;
// flush every 20 entries
if (($i % 20) === 0) {
$this->em->flush();
}
++$i;
// force content to be refreshed in case on bad fetch in the v1 installation
if (in_array($entry['title'], $this->untitled)) {
$data['title'] = '';
$data['html'] = '';
}
$this->em->flush();
if (array_key_exists('tags', $entry) && $entry['tags'] != '') {
$data['tags'] = $entry['tags'];
}
return $data;
}
}

View file

@ -2,9 +2,7 @@
namespace Wallabag\ImportBundle\Import;
use Wallabag\CoreBundle\Entity\Entry;
class WallabagV2Import extends WallabagV1Import implements ImportInterface
class WallabagV2Import extends WallabagImport
{
/**
* {@inheritdoc}
@ -31,55 +29,14 @@ class WallabagV2Import extends WallabagV1Import implements ImportInterface
}
/**
* @param $entries
* {@inheritdoc}
*/
protected function parseEntries($entries)
protected function prepareEntry($entry = [], $markAsRead = false)
{
$i = 1;
foreach ($entries as $importedEntry) {
$existingEntry = $this->em
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId($importedEntry['url'], $this->user->getId());
if (false !== $existingEntry) {
++$this->skippedEntries;
continue;
}
$importedEntry['html'] = $importedEntry['content'];
$importedEntry['content_type'] = $importedEntry['mimetype'];
$entry = $this->contentProxy->updateEntry(
new Entry($this->user),
$importedEntry['url'],
$importedEntry
);
if (array_key_exists('tags', $importedEntry) && !empty($importedEntry['tags'])) {
$this->contentProxy->assignTagsToEntry(
$entry,
$importedEntry['tags']
);
}
if (isset($importedEntry['preview_picture'])) {
$entry->setPreviewPicture($importedEntry['preview_picture']);
}
$entry->setArchived($importedEntry['is_archived'] || $this->markAsRead);
$entry->setStarred($importedEntry['is_starred']);
$this->em->persist($entry);
++$this->importedEntries;
// flush every 20 entries
if (($i % 20) === 0) {
$this->em->flush();
}
++$i;
}
$this->em->flush();
return [
'html' => $entry['content'],
'content_type' => $entry['mimetype'],
'is_archived' => ($entry['is_archived'] || $markAsRead),
] + $entry;
}
}