mirror of
https://github.com/wallabag/wallabag.git
synced 2025-06-27 16:36:00 +00:00
Merge branch '2.6' into master
This commit is contained in:
commit
8fd5a5273d
23 changed files with 749 additions and 14 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -5,6 +5,22 @@
|
||||||
* **[BC BREAK]** Convert 403 errors to 404 errors by @yguedidi in https://github.com/wallabag/wallabag/pull/8075
|
* **[BC BREAK]** Convert 403 errors to 404 errors by @yguedidi in https://github.com/wallabag/wallabag/pull/8075
|
||||||
* `wallassets/` folder renamed to `build/`
|
* `wallassets/` folder renamed to `build/`
|
||||||
|
|
||||||
|
## [2.6.13](https://github.com/wallabag/wallabag/tree/2.6.13)
|
||||||
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.12...2.6.13)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* Add support of Pocket CSV import by @kdecherf and @nicosomb in [https://github.com/wallabag/wallabag/pull/8240](https://github.com/wallabag/wallabag/pull/8240)
|
||||||
|
* Backport Pocket and Shaarli HTML imports from master by @nicosomb in [https://github.com/wallabag/wallabag/pull/8193](https://github.com/wallabag/wallabag/pull/8193)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Avoid non-validated OTP to be enabled #8139 by @j0k3r in [https://github.com/wallabag/wallabag/pull/8139](https://github.com/wallabag/wallabag/pull/8139)
|
||||||
|
|
||||||
|
### Technical stuff
|
||||||
|
|
||||||
|
* Update j0k3r/php-readability:1.2.13 to fix regression (about latin1 instead of UTF-8 used for entries) by @nicosomb [https://github.com/wallabag/wallabag/pull/8194](https://github.com/wallabag/wallabag/pull/8194)
|
||||||
|
|
||||||
## [2.6.12](https://github.com/wallabag/wallabag/tree/2.6.12)
|
## [2.6.12](https://github.com/wallabag/wallabag/tree/2.6.12)
|
||||||
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.11...2.6.12)
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.11...2.6.12)
|
||||||
|
|
||||||
|
@ -13,7 +29,6 @@
|
||||||
* Fix changelog by @yguedidi in [https://github.com/wallabag/wallabag/pull/8135](https://github.com/wallabag/wallabag/pull/8135)
|
* Fix changelog by @yguedidi in [https://github.com/wallabag/wallabag/pull/8135](https://github.com/wallabag/wallabag/pull/8135)
|
||||||
* Update dependencies by @yguedidi in [https://github.com/wallabag/wallabag/pull/8136](https://github.com/wallabag/wallabag/pull/8136)
|
* Update dependencies by @yguedidi in [https://github.com/wallabag/wallabag/pull/8136](https://github.com/wallabag/wallabag/pull/8136)
|
||||||
|
|
||||||
|
|
||||||
## [2.6.11](https://github.com/wallabag/wallabag/tree/2.6.11)
|
## [2.6.11](https://github.com/wallabag/wallabag/tree/2.6.11)
|
||||||
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.10...2.6.11)
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.10...2.6.11)
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,11 @@ old_sound_rabbit_mq:
|
||||||
exchange_options:
|
exchange_options:
|
||||||
name: 'wallabag.import.pocket_html'
|
name: 'wallabag.import.pocket_html'
|
||||||
type: topic
|
type: topic
|
||||||
|
import_pocket_csv:
|
||||||
|
connection: default
|
||||||
|
exchange_options:
|
||||||
|
name: 'wallabag.import.pocket_csv'
|
||||||
|
type: topic
|
||||||
consumers:
|
consumers:
|
||||||
import_pocket:
|
import_pocket:
|
||||||
connection: default
|
connection: default
|
||||||
|
@ -423,6 +428,15 @@ old_sound_rabbit_mq:
|
||||||
name: 'wallabag.import.pocket_html'
|
name: 'wallabag.import.pocket_html'
|
||||||
callback: wallabag.consumer.amqp.pocket_html
|
callback: wallabag.consumer.amqp.pocket_html
|
||||||
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
|
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
|
||||||
|
import_pocket_csv:
|
||||||
|
connection: default
|
||||||
|
exchange_options:
|
||||||
|
name: 'wallabag.import.pocket_csv'
|
||||||
|
type: topic
|
||||||
|
queue_options:
|
||||||
|
name: 'wallabag.import.pocket_csv'
|
||||||
|
callback: wallabag.consumer.amqp.pocket_csv
|
||||||
|
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
|
||||||
|
|
||||||
fos_js_routing:
|
fos_js_routing:
|
||||||
routes_to_expose:
|
routes_to_expose:
|
||||||
|
|
|
@ -108,6 +108,11 @@ services:
|
||||||
$rabbitMqProducer: '@old_sound_rabbit_mq.import_pocket_html_producer'
|
$rabbitMqProducer: '@old_sound_rabbit_mq.import_pocket_html_producer'
|
||||||
$redisProducer: '@wallabag.producer.redis.pocket_html'
|
$redisProducer: '@wallabag.producer.redis.pocket_html'
|
||||||
|
|
||||||
|
Wallabag\Controller\Import\PocketCsvController:
|
||||||
|
arguments:
|
||||||
|
$rabbitMqProducer: '@old_sound_rabbit_mq.import_pocket_csv_producer'
|
||||||
|
$redisProducer: '@wallabag.producer.redis.pocket_csv'
|
||||||
|
|
||||||
Wallabag\Doctrine\MigrationFactoryDecorator:
|
Wallabag\Doctrine\MigrationFactoryDecorator:
|
||||||
decorates: doctrine.migrations.migrations_factory
|
decorates: doctrine.migrations.migrations_factory
|
||||||
|
|
||||||
|
@ -328,6 +333,10 @@ services:
|
||||||
tags:
|
tags:
|
||||||
- { name: wallabag.import, alias: pocket_html }
|
- { name: wallabag.import, alias: pocket_html }
|
||||||
|
|
||||||
|
Wallabag\Import\PocketCsvImport:
|
||||||
|
tags:
|
||||||
|
- { name: wallabag.import, alias: pocket_csv }
|
||||||
|
|
||||||
# to factorize the proximity and bypass translation for prev & next
|
# to factorize the proximity and bypass translation for prev & next
|
||||||
pagerfanta.view.default_wallabag:
|
pagerfanta.view.default_wallabag:
|
||||||
class: Pagerfanta\View\OptionableView
|
class: Pagerfanta\View\OptionableView
|
||||||
|
|
|
@ -20,6 +20,7 @@ services:
|
||||||
$elcuratorConsumer: '@old_sound_rabbit_mq.import_elcurator_consumer'
|
$elcuratorConsumer: '@old_sound_rabbit_mq.import_elcurator_consumer'
|
||||||
$shaarliConsumer: '@old_sound_rabbit_mq.import_shaarli_consumer'
|
$shaarliConsumer: '@old_sound_rabbit_mq.import_shaarli_consumer'
|
||||||
$pocketHtmlConsumer: '@old_sound_rabbit_mq.import_pocket_html_consumer'
|
$pocketHtmlConsumer: '@old_sound_rabbit_mq.import_pocket_html_consumer'
|
||||||
|
$pocketCsvConsumer: '@old_sound_rabbit_mq.import_pocket_csv_consumer'
|
||||||
$omnivoreConsumer: '@old_sound_rabbit_mq.import_omnivore_consumer'
|
$omnivoreConsumer: '@old_sound_rabbit_mq.import_omnivore_consumer'
|
||||||
|
|
||||||
wallabag.consumer.amqp.pocket:
|
wallabag.consumer.amqp.pocket:
|
||||||
|
@ -86,3 +87,8 @@ services:
|
||||||
class: Wallabag\Consumer\AMQPEntryConsumer
|
class: Wallabag\Consumer\AMQPEntryConsumer
|
||||||
arguments:
|
arguments:
|
||||||
$import: '@Wallabag\Import\PocketHtmlImport'
|
$import: '@Wallabag\Import\PocketHtmlImport'
|
||||||
|
|
||||||
|
wallabag.consumer.amqp.pocket_csv:
|
||||||
|
class: Wallabag\Consumer\AMQPEntryConsumer
|
||||||
|
arguments:
|
||||||
|
$import: '@Wallabag\Import\PocketCsvImport'
|
||||||
|
|
|
@ -212,3 +212,19 @@ services:
|
||||||
class: Wallabag\Consumer\RedisEntryConsumer
|
class: Wallabag\Consumer\RedisEntryConsumer
|
||||||
arguments:
|
arguments:
|
||||||
$import: '@Wallabag\Import\PocketHtmlImport'
|
$import: '@Wallabag\Import\PocketHtmlImport'
|
||||||
|
|
||||||
|
# pocket csv
|
||||||
|
wallabag.queue.redis.pocket_csv:
|
||||||
|
class: Simpleue\Queue\RedisQueue
|
||||||
|
arguments:
|
||||||
|
$queueName: "wallabag.import.pocket_csv"
|
||||||
|
|
||||||
|
wallabag.producer.redis.pocket_csv:
|
||||||
|
class: Wallabag\Redis\Producer
|
||||||
|
arguments:
|
||||||
|
- "@wallabag.queue.redis.pocket_csv"
|
||||||
|
|
||||||
|
wallabag.consumer.redis.pocket_csv:
|
||||||
|
class: Wallabag\Consumer\RedisEntryConsumer
|
||||||
|
arguments:
|
||||||
|
$import: '@Wallabag\Import\PocketCsvImport'
|
||||||
|
|
|
@ -23,6 +23,7 @@ $config
|
||||||
'friendsoftwig/twigcs',
|
'friendsoftwig/twigcs',
|
||||||
'incenteev/composer-parameter-handler',
|
'incenteev/composer-parameter-handler',
|
||||||
'j0k3r/graby-site-config',
|
'j0k3r/graby-site-config',
|
||||||
|
'j0k3r/php-readability',
|
||||||
'laminas/laminas-code',
|
'laminas/laminas-code',
|
||||||
'lcobucci/jwt',
|
'lcobucci/jwt',
|
||||||
'mgargano/simplehtmldom',
|
'mgargano/simplehtmldom',
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
"incenteev/composer-parameter-handler": "^2.2",
|
"incenteev/composer-parameter-handler": "^2.2",
|
||||||
"j0k3r/graby": "^2.4.6",
|
"j0k3r/graby": "^2.4.6",
|
||||||
"j0k3r/graby-site-config": "^1.0.197",
|
"j0k3r/graby-site-config": "^1.0.197",
|
||||||
|
"j0k3r/php-readability": "^1.2.13",
|
||||||
"javibravo/simpleue": "^2.1",
|
"javibravo/simpleue": "^2.1",
|
||||||
"jms/serializer": "^3.32.3",
|
"jms/serializer": "^3.32.3",
|
||||||
"jms/serializer-bundle": "^5.5.1",
|
"jms/serializer-bundle": "^5.5.1",
|
||||||
|
|
18
composer.lock
generated
18
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "00b8f95df6ec0572c06ad6f34847405c",
|
"content-hash": "8a12584ee6ea6887963779b321b4860e",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "babdev/pagerfanta-bundle",
|
"name": "babdev/pagerfanta-bundle",
|
||||||
|
@ -4261,16 +4261,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "j0k3r/php-readability",
|
"name": "j0k3r/php-readability",
|
||||||
"version": "1.2.12",
|
"version": "1.2.13",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/j0k3r/php-readability.git",
|
"url": "https://github.com/j0k3r/php-readability.git",
|
||||||
"reference": "109a22662de0d703f01387e5714ad4f9a03b95c0"
|
"reference": "b9dde0f4cd46e9fc082bb37f75dc94ecd2f8faad"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/j0k3r/php-readability/zipball/109a22662de0d703f01387e5714ad4f9a03b95c0",
|
"url": "https://api.github.com/repos/j0k3r/php-readability/zipball/b9dde0f4cd46e9fc082bb37f75dc94ecd2f8faad",
|
||||||
"reference": "109a22662de0d703f01387e5714ad4f9a03b95c0",
|
"reference": "b9dde0f4cd46e9fc082bb37f75dc94ecd2f8faad",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4332,7 +4332,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/j0k3r/php-readability/issues",
|
"issues": "https://github.com/j0k3r/php-readability/issues",
|
||||||
"source": "https://github.com/j0k3r/php-readability/tree/1.2.12"
|
"source": "https://github.com/j0k3r/php-readability/tree/1.2.13"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -4340,7 +4340,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-03-04T09:20:40+00:00"
|
"time": "2025-06-03T08:02:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "javibravo/simpleue",
|
"name": "javibravo/simpleue",
|
||||||
|
@ -19449,6 +19449,6 @@
|
||||||
"ext-tokenizer": "*",
|
"ext-tokenizer": "*",
|
||||||
"ext-xml": "*"
|
"ext-xml": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ use Wallabag\Import\FirefoxImport;
|
||||||
use Wallabag\Import\InstapaperImport;
|
use Wallabag\Import\InstapaperImport;
|
||||||
use Wallabag\Import\OmnivoreImport;
|
use Wallabag\Import\OmnivoreImport;
|
||||||
use Wallabag\Import\PinboardImport;
|
use Wallabag\Import\PinboardImport;
|
||||||
|
use Wallabag\Import\PocketCsvImport;
|
||||||
use Wallabag\Import\PocketHtmlImport;
|
use Wallabag\Import\PocketHtmlImport;
|
||||||
use Wallabag\Import\ReadabilityImport;
|
use Wallabag\Import\ReadabilityImport;
|
||||||
use Wallabag\Import\ShaarliImport;
|
use Wallabag\Import\ShaarliImport;
|
||||||
|
@ -48,6 +49,7 @@ class ImportCommand extends Command
|
||||||
private readonly ElcuratorImport $elcuratorImport,
|
private readonly ElcuratorImport $elcuratorImport,
|
||||||
private readonly ShaarliImport $shaarliImport,
|
private readonly ShaarliImport $shaarliImport,
|
||||||
private readonly PocketHtmlImport $pocketHtmlImport,
|
private readonly PocketHtmlImport $pocketHtmlImport,
|
||||||
|
private readonly PocketCsvImport $pocketCsvImport,
|
||||||
private readonly OmnivoreImport $omnivoreImport,
|
private readonly OmnivoreImport $omnivoreImport,
|
||||||
) {
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
@ -58,7 +60,7 @@ class ImportCommand extends Command
|
||||||
$this
|
$this
|
||||||
->addArgument('username', InputArgument::REQUIRED, 'User to populate')
|
->addArgument('username', InputArgument::REQUIRED, 'User to populate')
|
||||||
->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file')
|
->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file')
|
||||||
->addOption('importer', null, InputOption::VALUE_OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, delicious, readability, firefox, chrome, elcurator, shaarli or pocket', 'v1')
|
->addOption('importer', null, InputOption::VALUE_OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, delicious, readability, firefox, chrome, elcurator, shaarli, pocket or pocket_csv', 'v1')
|
||||||
->addOption('markAsRead', null, InputOption::VALUE_OPTIONAL, 'Mark all entries as read', false)
|
->addOption('markAsRead', null, InputOption::VALUE_OPTIONAL, 'Mark all entries as read', false)
|
||||||
->addOption('useUserId', null, InputOption::VALUE_NONE, 'Use user id instead of username to find account')
|
->addOption('useUserId', null, InputOption::VALUE_NONE, 'Use user id instead of username to find account')
|
||||||
->addOption('disableContentUpdate', null, InputOption::VALUE_NONE, 'Disable fetching updated content from URL')
|
->addOption('disableContentUpdate', null, InputOption::VALUE_NONE, 'Disable fetching updated content from URL')
|
||||||
|
@ -109,6 +111,7 @@ class ImportCommand extends Command
|
||||||
'elcurator' => $this->elcuratorImport,
|
'elcurator' => $this->elcuratorImport,
|
||||||
'shaarli' => $this->shaarliImport,
|
'shaarli' => $this->shaarliImport,
|
||||||
'pocket' => $this->pocketHtmlImport,
|
'pocket' => $this->pocketHtmlImport,
|
||||||
|
'pocket_csv' => $this->pocketCsvImport,
|
||||||
'omnivore' => $this->omnivoreImport,
|
'omnivore' => $this->omnivoreImport,
|
||||||
default => $this->wallabagV1Import,
|
default => $this->wallabagV1Import,
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ class RabbitMQConsumerTotalProxy
|
||||||
private readonly Consumer $elcuratorConsumer,
|
private readonly Consumer $elcuratorConsumer,
|
||||||
private readonly Consumer $shaarliConsumer,
|
private readonly Consumer $shaarliConsumer,
|
||||||
private readonly Consumer $pocketHtmlConsumer,
|
private readonly Consumer $pocketHtmlConsumer,
|
||||||
|
private readonly Consumer $pocketCsvConsumer,
|
||||||
private readonly Consumer $omnivoreConsumer,
|
private readonly Consumer $omnivoreConsumer,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
@ -75,6 +76,9 @@ class RabbitMQConsumerTotalProxy
|
||||||
case 'pocket_html':
|
case 'pocket_html':
|
||||||
$consumer = $this->pocketHtmlConsumer;
|
$consumer = $this->pocketHtmlConsumer;
|
||||||
break;
|
break;
|
||||||
|
case 'pocket_csv':
|
||||||
|
$consumer = $this->pocketCsvConsumer;
|
||||||
|
break;
|
||||||
case 'omnivore':
|
case 'omnivore':
|
||||||
$consumer = $this->omnivoreConsumer;
|
$consumer = $this->omnivoreConsumer;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -58,6 +58,7 @@ class ImportController extends AbstractController
|
||||||
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('elcurator')
|
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('elcurator')
|
||||||
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('shaarli')
|
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('shaarli')
|
||||||
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('pocket_html')
|
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('pocket_html')
|
||||||
|
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('pocket_csv')
|
||||||
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('omnivore')
|
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('omnivore')
|
||||||
;
|
;
|
||||||
} catch (\Exception) {
|
} catch (\Exception) {
|
||||||
|
@ -77,6 +78,7 @@ class ImportController extends AbstractController
|
||||||
+ $this->redisClient->llen('wallabag.import.elcurator')
|
+ $this->redisClient->llen('wallabag.import.elcurator')
|
||||||
+ $this->redisClient->llen('wallabag.import.shaarli')
|
+ $this->redisClient->llen('wallabag.import.shaarli')
|
||||||
+ $this->redisClient->llen('wallabag.import.pocket_html')
|
+ $this->redisClient->llen('wallabag.import.pocket_html')
|
||||||
|
+ $this->redisClient->llen('wallabag.import.pocket_csv')
|
||||||
+ $this->redisClient->llen('wallabag.import.omnivore')
|
+ $this->redisClient->llen('wallabag.import.omnivore')
|
||||||
;
|
;
|
||||||
} catch (\Exception) {
|
} catch (\Exception) {
|
||||||
|
|
46
src/Controller/Import/PocketCsvController.php
Normal file
46
src/Controller/Import/PocketCsvController.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Wallabag\Controller\Import;
|
||||||
|
|
||||||
|
use Craue\ConfigBundle\Util\Config;
|
||||||
|
use OldSound\RabbitMqBundle\RabbitMq\Producer as RabbitMqProducer;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Wallabag\Import\PocketCsvImport;
|
||||||
|
use Wallabag\Redis\Producer as RedisProducer;
|
||||||
|
|
||||||
|
class PocketCsvController extends HtmlController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly PocketCsvImport $pocketCsvImport,
|
||||||
|
private readonly Config $craueConfig,
|
||||||
|
private readonly RabbitMqProducer $rabbitMqProducer,
|
||||||
|
private readonly RedisProducer $redisProducer,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/import/pocket_csv', name: 'import_pocket_csv', methods: ['GET', 'POST'])]
|
||||||
|
#[IsGranted('IMPORT_ENTRIES')]
|
||||||
|
public function indexAction(Request $request, TranslatorInterface $translator)
|
||||||
|
{
|
||||||
|
return parent::indexAction($request, $translator);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getImportService()
|
||||||
|
{
|
||||||
|
if ($this->craueConfig->get('import_with_rabbitmq')) {
|
||||||
|
$this->pocketCsvImport->setProducer($this->rabbitMqProducer);
|
||||||
|
} elseif ($this->craueConfig->get('import_with_redis')) {
|
||||||
|
$this->pocketCsvImport->setProducer($this->redisProducer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->pocketCsvImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getImportTemplate()
|
||||||
|
{
|
||||||
|
return 'Import/PocketCsv/index.html.twig';
|
||||||
|
}
|
||||||
|
}
|
133
src/Import/PocketCsvImport.php
Normal file
133
src/Import/PocketCsvImport.php
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Wallabag\Import;
|
||||||
|
|
||||||
|
use Wallabag\Entity\Entry;
|
||||||
|
|
||||||
|
class PocketCsvImport extends AbstractImport
|
||||||
|
{
|
||||||
|
protected $filepath;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Pocket CSV';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrl()
|
||||||
|
{
|
||||||
|
return 'import_pocket_csv';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return 'import.pocket_csv.description';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFilepath($filepath): static
|
||||||
|
{
|
||||||
|
$this->filepath = $filepath;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateEntry(array $importedEntry)
|
||||||
|
{
|
||||||
|
if (empty($importedEntry['url'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function import()
|
||||||
|
{
|
||||||
|
if (!$this->user) {
|
||||||
|
$this->logger->error('Pocket CSV Import: user is not defined');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
|
||||||
|
$this->logger->error('Pocket CSV Import: unable to read file', ['filepath' => $this->filepath]);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = [];
|
||||||
|
$handle = fopen($this->filepath, 'r');
|
||||||
|
while (false !== ($data = fgetcsv($handle, 10240))) {
|
||||||
|
if ('title' === $data[0]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries[] = [
|
||||||
|
'url' => $data[1],
|
||||||
|
'title' => $data[0],
|
||||||
|
'is_archived' => 'archive' === $data[4],
|
||||||
|
'created_at' => $data[2],
|
||||||
|
'tags' => $data[3],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
if (empty($entries)) {
|
||||||
|
$this->logger->error('PocketCsvImport: no entries in imported file');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->producer) {
|
||||||
|
$this->parseEntriesForProducer($entries);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parseEntries($entries);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseEntry(array $importedEntry)
|
||||||
|
{
|
||||||
|
$existingEntry = $this->em
|
||||||
|
->getRepository(Entry::class)
|
||||||
|
->findByUrlAndUserId($importedEntry['url'], $this->user->getId());
|
||||||
|
|
||||||
|
if (false !== $existingEntry) {
|
||||||
|
++$this->skippedEntries;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry = new Entry($this->user);
|
||||||
|
$entry->setUrl($importedEntry['url']);
|
||||||
|
$entry->setTitle($importedEntry['title']);
|
||||||
|
|
||||||
|
// update entry with content (in case fetching failed, the given entry will be return)
|
||||||
|
$this->fetchContent($entry, $importedEntry['url'], $importedEntry);
|
||||||
|
|
||||||
|
if (!empty($importedEntry['tags'])) {
|
||||||
|
$tags = str_replace('|', ',', $importedEntry['tags']);
|
||||||
|
$this->tagsAssigner->assignTagsToEntry(
|
||||||
|
$entry,
|
||||||
|
$tags,
|
||||||
|
$this->em->getUnitOfWork()->getScheduledEntityInsertions()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry->updateArchived($importedEntry['is_archived']);
|
||||||
|
$entry->setCreatedAt(\DateTime::createFromFormat('U', $importedEntry['created_at']));
|
||||||
|
|
||||||
|
$this->em->persist($entry);
|
||||||
|
++$this->importedEntries;
|
||||||
|
|
||||||
|
return $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setEntryAsRead(array $importedEntry)
|
||||||
|
{
|
||||||
|
$importedEntry['is_archived'] = 'archive';
|
||||||
|
|
||||||
|
return $importedEntry;
|
||||||
|
}
|
||||||
|
}
|
47
templates/Import/PocketCsv/index.html.twig
Normal file
47
templates/Import/PocketCsv/index.html.twig
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{% extends "layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'import.pocket_csv.page_title'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="card-panel settings">
|
||||||
|
{% include 'Import/_information.html.twig' %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<blockquote>{{ import.description|trans|raw }}</blockquote>
|
||||||
|
<p>{{ 'import.pocket_csv.how_to'|trans }}</p>
|
||||||
|
|
||||||
|
<div class="col s12">
|
||||||
|
{{ form_start(form, {'method': 'POST'}) }}
|
||||||
|
{{ form_errors(form) }}
|
||||||
|
<div class="row">
|
||||||
|
<div class="file-field input-field col s12">
|
||||||
|
{{ form_errors(form.file) }}
|
||||||
|
<div class="btn">
|
||||||
|
<span>{{ form.file.vars.label|trans }}</span>
|
||||||
|
{{ form_widget(form.file) }}
|
||||||
|
</div>
|
||||||
|
<div class="file-path-wrapper">
|
||||||
|
<input class="file-path validate" type="text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h6 class="col s12">{{ 'import.form.mark_as_read_title'|trans }}</h6>
|
||||||
|
<div class="col s6 with-checkbox">
|
||||||
|
<label for="{{ form.mark_as_read.vars.id }}">
|
||||||
|
{{ form_widget(form.mark_as_read) }}
|
||||||
|
<span>{{ form.mark_as_read.vars.label|trans }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
|
||||||
|
|
||||||
|
{{ form_rest(form) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -23,6 +23,6 @@ class ImportControllerTest extends WallabagTestCase
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/import/');
|
$crawler = $client->request('GET', '/import/');
|
||||||
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||||
$this->assertSame(13, $crawler->filter('.card-title')->count());
|
$this->assertSame(14, $crawler->filter('.card-title')->count());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
168
tests/Controller/Import/PocketCsvControllerTest.php
Normal file
168
tests/Controller/Import/PocketCsvControllerTest.php
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Wallabag\Controller\Import;
|
||||||
|
|
||||||
|
use Craue\ConfigBundle\Util\Config;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Predis\Client;
|
||||||
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
use Tests\Wallabag\WallabagTestCase;
|
||||||
|
use Wallabag\Entity\Entry;
|
||||||
|
|
||||||
|
class PocketCsvControllerTest extends WallabagTestCase
|
||||||
|
{
|
||||||
|
public function testImportPocketCsv()
|
||||||
|
{
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/import/pocket_csv');
|
||||||
|
|
||||||
|
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||||
|
$this->assertSame(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
|
||||||
|
$this->assertSame(1, $crawler->filter('input[type=file]')->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportPocketCsvWithRabbitEnabled()
|
||||||
|
{
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
|
$client->getContainer()->get(Config::class)->set('import_with_rabbitmq', 1);
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/import/pocket_csv');
|
||||||
|
|
||||||
|
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||||
|
$this->assertSame(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
|
||||||
|
$this->assertSame(1, $crawler->filter('input[type=file]')->count());
|
||||||
|
|
||||||
|
$client->getContainer()->get(Config::class)->set('import_with_rabbitmq', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportPocketCsvBadFile()
|
||||||
|
{
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/import/pocket_csv');
|
||||||
|
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'upload_import_file[file]' => '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$client->submit($form, $data);
|
||||||
|
|
||||||
|
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportPocketCsvWithRedisEnabled()
|
||||||
|
{
|
||||||
|
$this->checkRedis();
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getTestClient();
|
||||||
|
$client->getContainer()->get(Config::class)->set('import_with_redis', 1);
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/import/pocket_csv');
|
||||||
|
|
||||||
|
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||||
|
$this->assertSame(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
|
||||||
|
$this->assertSame(1, $crawler->filter('input[type=file]')->count());
|
||||||
|
|
||||||
|
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
|
||||||
|
|
||||||
|
$file = new UploadedFile(__DIR__ . '/../../fixtures/Import/pocket.csv', 'Bookmarks');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'upload_import_file[file]' => $file,
|
||||||
|
];
|
||||||
|
|
||||||
|
$client->submit($form, $data);
|
||||||
|
|
||||||
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$crawler = $client->followRedirect();
|
||||||
|
|
||||||
|
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
|
||||||
|
$this->assertStringContainsString('flashes.import.notice.summary', $body[0]);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($client->getContainer()->get(Client::class)->lpop('wallabag.import.pocket_csv'));
|
||||||
|
|
||||||
|
$client->getContainer()->get(Config::class)->set('import_with_redis', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportWallabagWithPocketCsvFile()
|
||||||
|
{
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/import/pocket_csv');
|
||||||
|
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
|
||||||
|
|
||||||
|
$file = new UploadedFile(__DIR__ . '/../../fixtures/Import/pocket.csv', 'Bookmarks');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'upload_import_file[file]' => $file,
|
||||||
|
];
|
||||||
|
|
||||||
|
$client->submit($form, $data);
|
||||||
|
|
||||||
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$crawler = $client->followRedirect();
|
||||||
|
|
||||||
|
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
|
||||||
|
$this->assertStringContainsString('flashes.import.notice.summary', $body[0]);
|
||||||
|
|
||||||
|
$entries = $client->getContainer()
|
||||||
|
->get(EntityManagerInterface::class)
|
||||||
|
->getRepository(Entry::class)
|
||||||
|
->findBy(['user' => $this->getLoggedInUserId()]);
|
||||||
|
|
||||||
|
$expectedEntries = [
|
||||||
|
'http://youmightnotneedjquery.com/,1600322788',
|
||||||
|
'https://jp-lambert.me/est-ce-que-jai-besoin-d-un-scrum-master-604f5a471c73',
|
||||||
|
'https://www.monde-diplomatique.fr/2020/09/HALIMI/62165',
|
||||||
|
'https://www.reddit.com/r/DataHoarder/comments/ioupbk/archivebox_question_how_do_i_import_links_from_a/',
|
||||||
|
'https://www.numerama.com/politique/646826-tu-vas-pleurer-les-premieres-fois-que-se-passe-t-il-au-sein-du-studio-dubisoft-derriere-trackmania.html#utm_medium=distibuted&utm_source=rss&utm_campaign=646826',
|
||||||
|
'https://www.nouvelobs.com/rue89/20200911.OBS33165/comment-konbini-s-est-fait-pieger-par-un-pere-masculiniste.html',
|
||||||
|
'https://reporterre.net/Des-abeilles-pour-resoudre-les-conflits-entre-les-humains-et-les-elephants',
|
||||||
|
];
|
||||||
|
|
||||||
|
$matchedEntries = array_map(function ($expectedUrl) use ($entries) {
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if ($entry->getUrl() === $expectedUrl) {
|
||||||
|
return $entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, $expectedEntries);
|
||||||
|
|
||||||
|
$this->assertCount(\count($expectedEntries), $matchedEntries, 'Should have 7 entries imported from pocket.csv');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportWallabagWithEmptyFile()
|
||||||
|
{
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/import/pocket_csv');
|
||||||
|
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
|
||||||
|
|
||||||
|
$file = new UploadedFile(__DIR__ . '/../../fixtures/Import/test.csv', 'test.csv');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'upload_import_file[file]' => $file,
|
||||||
|
];
|
||||||
|
|
||||||
|
$client->submit($form, $data);
|
||||||
|
|
||||||
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$crawler = $client->followRedirect();
|
||||||
|
|
||||||
|
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
|
||||||
|
$this->assertStringContainsString('flashes.import.notice.failed', $body[0]);
|
||||||
|
}
|
||||||
|
}
|
252
tests/Import/PocketCsvImportTest.php
Normal file
252
tests/Import/PocketCsvImportTest.php
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Wallabag\Import;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use M6Web\Component\RedisMock\RedisMockFactory;
|
||||||
|
use Monolog\Handler\TestHandler;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Predis\Client;
|
||||||
|
use Simpleue\Queue\RedisQueue;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||||
|
use Wallabag\Entity\Entry;
|
||||||
|
use Wallabag\Entity\User;
|
||||||
|
use Wallabag\Helper\ContentProxy;
|
||||||
|
use Wallabag\Helper\TagsAssigner;
|
||||||
|
use Wallabag\Import\PocketCsvImport;
|
||||||
|
use Wallabag\Redis\Producer;
|
||||||
|
use Wallabag\Repository\EntryRepository;
|
||||||
|
|
||||||
|
class PocketCsvImportTest extends TestCase
|
||||||
|
{
|
||||||
|
protected $user;
|
||||||
|
protected $em;
|
||||||
|
protected $logHandler;
|
||||||
|
protected $contentProxy;
|
||||||
|
protected $tagsAssigner;
|
||||||
|
|
||||||
|
public function testInit()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport();
|
||||||
|
|
||||||
|
$this->assertSame('Pocket CSV', $pocketCsvImport->getName());
|
||||||
|
$this->assertNotEmpty($pocketCsvImport->getUrl());
|
||||||
|
$this->assertSame('import.pocket_csv.description', $pocketCsvImport->getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImport()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport(false, 7);
|
||||||
|
$pocketCsvImport->setFilepath(__DIR__ . '/../fixtures/Import/pocket.csv');
|
||||||
|
|
||||||
|
$entryRepo = $this->getMockBuilder(EntryRepository::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$entryRepo->expects($this->exactly(7))
|
||||||
|
->method('findByUrlAndUserId')
|
||||||
|
->willReturn(false);
|
||||||
|
|
||||||
|
$this->em
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getRepository')
|
||||||
|
->willReturn($entryRepo);
|
||||||
|
|
||||||
|
$entry = $this->getMockBuilder(Entry::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->contentProxy
|
||||||
|
->expects($this->exactly(7))
|
||||||
|
->method('updateEntry')
|
||||||
|
->willReturn($entry);
|
||||||
|
|
||||||
|
$res = $pocketCsvImport->import();
|
||||||
|
|
||||||
|
$this->assertTrue($res);
|
||||||
|
$this->assertSame(['skipped' => 0, 'imported' => 7, 'queued' => 0], $pocketCsvImport->getSummary());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportAndMarkAllAsRead()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport(false, 1);
|
||||||
|
$pocketCsvImport->setFilepath(__DIR__ . '/../fixtures/Import/pocket.csv');
|
||||||
|
|
||||||
|
$entryRepo = $this->getMockBuilder(EntryRepository::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$entryRepo->expects($this->exactly(7))
|
||||||
|
->method('findByUrlAndUserId')
|
||||||
|
->will($this->onConsecutiveCalls(false, true));
|
||||||
|
|
||||||
|
$this->em
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getRepository')
|
||||||
|
->willReturn($entryRepo);
|
||||||
|
|
||||||
|
$this->contentProxy
|
||||||
|
->expects($this->exactly(1))
|
||||||
|
->method('updateEntry')
|
||||||
|
->willReturn(new Entry($this->user));
|
||||||
|
|
||||||
|
// check that every entry persisted are archived
|
||||||
|
$this->em
|
||||||
|
->expects($this->any())
|
||||||
|
->method('persist')
|
||||||
|
->with($this->callback(fn ($persistedEntry) => (bool) $persistedEntry->isArchived()));
|
||||||
|
|
||||||
|
$res = $pocketCsvImport
|
||||||
|
->setMarkAsRead(true)
|
||||||
|
->import();
|
||||||
|
|
||||||
|
$this->assertTrue($res);
|
||||||
|
|
||||||
|
$this->assertSame(['skipped' => 6, 'imported' => 1, 'queued' => 0], $pocketCsvImport->getSummary());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportWithRabbit()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport();
|
||||||
|
$pocketCsvImport->setFilepath(__DIR__ . '/../fixtures/Import/pocket.csv');
|
||||||
|
|
||||||
|
$entryRepo = $this->getMockBuilder(EntryRepository::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$entryRepo->expects($this->never())
|
||||||
|
->method('findByUrlAndUserId');
|
||||||
|
|
||||||
|
$this->em
|
||||||
|
->expects($this->never())
|
||||||
|
->method('getRepository');
|
||||||
|
|
||||||
|
$entry = $this->getMockBuilder(Entry::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->contentProxy
|
||||||
|
->expects($this->never())
|
||||||
|
->method('updateEntry');
|
||||||
|
|
||||||
|
$producer = $this->getMockBuilder(\OldSound\RabbitMqBundle\RabbitMq\Producer::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$producer
|
||||||
|
->expects($this->exactly(7))
|
||||||
|
->method('publish');
|
||||||
|
|
||||||
|
$pocketCsvImport->setProducer($producer);
|
||||||
|
|
||||||
|
$res = $pocketCsvImport->setMarkAsRead(true)->import();
|
||||||
|
|
||||||
|
$this->assertTrue($res);
|
||||||
|
$this->assertSame(['skipped' => 0, 'imported' => 0, 'queued' => 7], $pocketCsvImport->getSummary());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportWithRedis()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport();
|
||||||
|
$pocketCsvImport->setFilepath(__DIR__ . '/../fixtures/Import/pocket.csv');
|
||||||
|
|
||||||
|
$entryRepo = $this->getMockBuilder(EntryRepository::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$entryRepo->expects($this->never())
|
||||||
|
->method('findByUrlAndUserId');
|
||||||
|
|
||||||
|
$this->em
|
||||||
|
->expects($this->never())
|
||||||
|
->method('getRepository');
|
||||||
|
|
||||||
|
$entry = $this->getMockBuilder(Entry::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->contentProxy
|
||||||
|
->expects($this->never())
|
||||||
|
->method('updateEntry');
|
||||||
|
|
||||||
|
$factory = new RedisMockFactory();
|
||||||
|
$redisMock = $factory->getAdapter(Client::class, true);
|
||||||
|
|
||||||
|
$queue = new RedisQueue($redisMock, 'pocket_csv');
|
||||||
|
$producer = new Producer($queue);
|
||||||
|
|
||||||
|
$pocketCsvImport->setProducer($producer);
|
||||||
|
|
||||||
|
$res = $pocketCsvImport->setMarkAsRead(true)->import();
|
||||||
|
|
||||||
|
$this->assertTrue($res);
|
||||||
|
$this->assertSame(['skipped' => 0, 'imported' => 0, 'queued' => 7], $pocketCsvImport->getSummary());
|
||||||
|
|
||||||
|
$this->assertNotEmpty($redisMock->lpop('pocket_csv'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportBadFile()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport();
|
||||||
|
$pocketCsvImport->setFilepath(__DIR__ . '/../fixtures/Import/wallabag-v1.jsonx');
|
||||||
|
|
||||||
|
$res = $pocketCsvImport->import();
|
||||||
|
|
||||||
|
$this->assertFalse($res);
|
||||||
|
|
||||||
|
$records = $this->logHandler->getRecords();
|
||||||
|
$this->assertStringContainsString('Pocket CSV Import: unable to read file', $records[0]['message']);
|
||||||
|
$this->assertSame('ERROR', $records[0]['level_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImportUserNotDefined()
|
||||||
|
{
|
||||||
|
$pocketCsvImport = $this->getPocketCsvImport(true);
|
||||||
|
$pocketCsvImport->setFilepath(__DIR__ . '/../fixtures/Import/pocket.csv');
|
||||||
|
|
||||||
|
$res = $pocketCsvImport->import();
|
||||||
|
|
||||||
|
$this->assertFalse($res);
|
||||||
|
|
||||||
|
$records = $this->logHandler->getRecords();
|
||||||
|
$this->assertStringContainsString('Pocket CSV Import: user is not defined', $records[0]['message']);
|
||||||
|
$this->assertSame('ERROR', $records[0]['level_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPocketCsvImport($unsetUser = false, $dispatched = 0)
|
||||||
|
{
|
||||||
|
$this->user = new User();
|
||||||
|
|
||||||
|
$this->em = $this->getMockBuilder(EntityManager::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->contentProxy = $this->getMockBuilder(ContentProxy::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->tagsAssigner = $this->getMockBuilder(TagsAssigner::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$dispatcher = $this->getMockBuilder(EventDispatcher::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$dispatcher
|
||||||
|
->expects($this->exactly($dispatched))
|
||||||
|
->method('dispatch');
|
||||||
|
|
||||||
|
$this->logHandler = new TestHandler();
|
||||||
|
$logger = new Logger('test', [$this->logHandler]);
|
||||||
|
|
||||||
|
$wallabag = new PocketCsvImport($this->em, $this->contentProxy, $this->tagsAssigner, $dispatcher, $logger);
|
||||||
|
|
||||||
|
if (false === $unsetUser) {
|
||||||
|
$wallabag->setUser($this->user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $wallabag;
|
||||||
|
}
|
||||||
|
}
|
10
tests/fixtures/Import/pocket.csv
vendored
Normal file
10
tests/fixtures/Import/pocket.csv
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
title,url,time_added,tags,status
|
||||||
|
You Might Not Need jQuery,http://youmightnotneedjquery.com/,1600322788,,unread
|
||||||
|
Est-ce que j’ai besoin d’un Scrum Master ? | by Jean-Pierre Lambert | Jean-,https://jp-lambert.me/est-ce-que-jai-besoin-d-un-scrum-master-604f5a471c73,1600172739,,unread
|
||||||
|
"Avec les accusés d’El Halia, par Gisèle Halimi (Le Monde diplomatique, sept",https://www.monde-diplomatique.fr/2020/09/HALIMI/62165,1599806347,,unread
|
||||||
|
ArchiveBox question: How do I import links from a RSS feed?,https://www.reddit.com/r/DataHoarder/comments/ioupbk/archivebox_question_how_do_i_import_links_from_a/,1600961496,,archive
|
||||||
|
« Tu vas pleurer les premières fois » : que se passe-t-il au sein du studio,https://www.numerama.com/politique/646826-tu-vas-pleurer-les-premieres-fois-que-se-passe-t-il-au-sein-du-studio-dubisoft-derriere-trackmania.html#utm_medium=distibuted&utm_source=rss&utm_campaign=646826,1599809025,,unread
|
||||||
|
Comment Konbini s’est fait piéger par un « père masculiniste »,https://www.nouvelobs.com/rue89/20200911.OBS33165/comment-konbini-s-est-fait-pieger-par-un-pere-masculiniste.html,1599819251,,archive
|
||||||
|
"Des abeilles pour résoudre les « conflits » entre les humains
|
||||||
|
|
||||||
|
et les élépha",https://reporterre.net/Des-abeilles-pour-resoudre-les-conflits-entre-les-humains-et-les-elephants,1599890673,,unread
|
|
2
tests/fixtures/Import/shaarli-bookmarks.html
vendored
2
tests/fixtures/Import/shaarli-bookmarks.html
vendored
|
@ -8,6 +8,6 @@
|
||||||
<DL><p>
|
<DL><p>
|
||||||
<DT><A HREF="https://www.20minutes.fr/sport/4002755-20220928-tarn-lapins-ravagent-terrain-match-rugby-doit-etre-annule" ADD_DATE="1686813518" LAST_MODIFIED="1686813519" PRIVATE="0" TAGS="firefoxos">The Legacy of Firefox OS. In the two years or so since Mozilla… | by Ben Francis | Medium</A>
|
<DT><A HREF="https://www.20minutes.fr/sport/4002755-20220928-tarn-lapins-ravagent-terrain-match-rugby-doit-etre-annule" ADD_DATE="1686813518" LAST_MODIFIED="1686813519" PRIVATE="0" TAGS="firefoxos">The Legacy of Firefox OS. In the two years or so since Mozilla… | by Ben Francis | Medium</A>
|
||||||
<DD>In the two years or so since Mozilla announced the end of Firefox OS as a Mozilla-run project, the B2G source code has found its way into a surprising number of commercial products.
|
<DD>In the two years or so since Mozilla announced the end of Firefox OS as a Mozilla-run project, the B2G source code has found its way into a surprising number of commercial products.
|
||||||
<DT><A HREF="https://www.20minutes.fr/paris/4100740-20240715-jo-paris-2024-courir-capitale-maintenant-quais-fermes" ADD_DATE="1683376565" LAST_MODIFIED="1683376571" PRIVATE="0" TAGS="eleventy,this,javascript,filter,data">Template Filters — Eleventy</A>
|
<DT><A HREF="https://www.20minutes.fr/paris/4100740-20240715-jo-paris-2024-courir-capitale-maintenant-quais-fermes" ADD_DATE="1683376565" LAST_MODIFIED="1686813519" PRIVATE="0" TAGS="firefoxos">JO Paris 2024 : Où courir dans la capitale maintenant que les quais sont fermés ?</A>
|
||||||
</DL><p>
|
</DL><p>
|
||||||
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
|
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
|
||||||
|
|
0
tests/fixtures/Import/test.csv
vendored
Normal file
0
tests/fixtures/Import/test.csv
vendored
Normal file
|
|
@ -553,6 +553,10 @@ import:
|
||||||
page_title: Import > Pocket HTML
|
page_title: Import > Pocket HTML
|
||||||
description: This importer will import all your Pocket bookmarks (via HTML export). Just go to https://getpocket.com/export, then export the HTML file. An HTML file will be downloaded (like "ril_export.html").
|
description: This importer will import all your Pocket bookmarks (via HTML export). Just go to https://getpocket.com/export, then export the HTML file. An HTML file will be downloaded (like "ril_export.html").
|
||||||
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.
|
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.
|
||||||
|
pocket_csv:
|
||||||
|
page_title: Import > Pocket CSV
|
||||||
|
description: This importer will import all your Pocket bookmarks (via CSV export). Just go to https://getpocket.com/export, then export the file. A ZIP file will be downloaded (like "pocket.zip"). Extract it, you will obtain a CSV file, called "part_000000.csv".
|
||||||
|
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:
|
developer:
|
||||||
page_title: API clients management
|
page_title: API clients management
|
||||||
welcome_message: Welcome to the wallabag API
|
welcome_message: Welcome to the wallabag API
|
||||||
|
|
|
@ -550,6 +550,10 @@ import:
|
||||||
page_title: Importer > Pocket HTML
|
page_title: Importer > Pocket HTML
|
||||||
description: Cet importateur importera toutes vos signets Pocket (via exportation HTML). Il suffit d'aller à https://getpocket.com/export, puis d'exporter le fichier HTML. Un fichier HTML sera téléchargé (comme « ril_export.html »).
|
description: Cet importateur importera toutes vos signets Pocket (via exportation HTML). Il suffit d'aller à https://getpocket.com/export, puis d'exporter le fichier HTML. Un fichier HTML sera téléchargé (comme « ril_export.html »).
|
||||||
how_to: Veuillez choisir le fichier de sauvegarde de signets et cliquez sur le bouton ci-dessous pour l'importer. Pensez au fait que le processus peut prendre longtemps puisque tous les articles doivent être récupérés.
|
how_to: Veuillez choisir le fichier de sauvegarde de signets et cliquez sur le bouton ci-dessous pour l'importer. Pensez au fait que le processus peut prendre longtemps puisque tous les articles doivent être récupérés.
|
||||||
|
pocket_csv:
|
||||||
|
page_title: Importer > Pocket CSV
|
||||||
|
description: Cet importateur importera toutes vos signets Pocket (via exportation CSV). Il suffit d'aller à https://getpocket.com/export, puis d'exporter le fichier. Un fichier ZIP sera téléchargé (comme « pocket.zip »). Décompressez le et vous obtiendrez un fichier CSV appelé "part_000000.csv".
|
||||||
|
how_to: Veuillez choisir le fichier de sauvegarde de signets et cliquez sur le bouton ci-dessous pour l'importer. Pensez au fait que le processus peut prendre longtemps puisque tous les articles doivent être récupérés.
|
||||||
omnivore:
|
omnivore:
|
||||||
description: Cet outil va importer tous vos articles depuis Omnivore.
|
description: Cet outil va importer tous vos articles depuis Omnivore.
|
||||||
page_title: Importer > Omnivore
|
page_title: Importer > Omnivore
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue