Merge remote-tracking branch 'origin/2.6' into port/2.6.10

Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
This commit is contained in:
Kevin Decherf 2024-11-11 09:25:31 +01:00
commit 1d661e8c68
46 changed files with 1306 additions and 375 deletions

View file

@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Want to ask something?
url: https://gitter.im/wallabag/wallabag
about: Use Gitter to ask questions.
url: https://matrix.to/#/#wallabag:matrix.org
about: Use Matrix to ask questions.

View file

@ -1,5 +1,27 @@
# Changelog
## [2.6.10](https://github.com/wallabag/wallabag/tree/2.6.10)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.9...2.6.10)
### Improvement
* Add Omnivore import by @nicosomb in https://github.com/wallabag/wallabag/pull/7754
### Fixes
* Update site config & tests by @j0k3r in https://github.com/wallabag/wallabag/pull/7582 (fixes "Key provided is shorter
than 256 bits, only 240 bits provided" https://github.com/wallabag/wallabag/issues/7531)
* Update site config by @yguedidi in https://github.com/wallabag/wallabag/pull/7623
* Replace gitter with matrix by @nicosomb in https://github.com/wallabag/wallabag/pull/7753
## [2.6.9](https://github.com/wallabag/wallabag/tree/2.6.9)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.8...2.6.9)
### Fixes
* Fix same domain pagination by @yguedidi in https://github.com/wallabag/wallabag/pull/7266
* Upgrade PHP dependencies by @yguedidi in https://github.com/wallabag/wallabag/pull/7272
* Use a proper "how to" for elCurator by @j0k3r in https://github.com/wallabag/wallabag/pull/7323
## [2.6.8](https://github.com/wallabag/wallabag/tree/2.6.8)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.7...2.6.8)

View file

@ -1,7 +1,7 @@
# wallabag
![CI](https://github.com/wallabag/wallabag/workflows/CI/badge.svg)
[![Gitter](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/wallabag/wallabag)
[![Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#wallabag:matrix.org)
[![Donation Status](https://img.shields.io/liberapay/goal/wallabag.svg?logo=liberapay)](https://liberapay.com/wallabag/donate)
[![Translation status](https://hosted.weblate.org/widgets/wallabag/-/svg-badge.svg)](https://hosted.weblate.org/engage/wallabag/?utm_source=widget)
![License](https://img.shields.io/github/license/wallabag/wallabag)

View file

@ -277,6 +277,11 @@ old_sound_rabbit_mq:
exchange_options:
name: 'wallabag.import.elcurator'
type: topic
import_omnivore:
connection: default
exchange_options:
name: 'wallabag.import.omnivore'
type: topic
import_firefox:
connection: default
exchange_options:
@ -370,6 +375,15 @@ old_sound_rabbit_mq:
name: 'wallabag.import.elcurator'
callback: wallabag.consumer.amqp.elcurator
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
import_omnivore:
connection: default
exchange_options:
name: 'wallabag.import.omnivore'
type: topic
queue_options:
name: 'wallabag.import.omnivore'
callback: wallabag.consumer.amqp.omnivore
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
import_firefox:
connection: default
exchange_options:

View file

@ -58,6 +58,11 @@ services:
$rabbitMqProducer: '@old_sound_rabbit_mq.import_elcurator_producer'
$redisProducer: '@wallabag.producer.redis.elcurator'
Wallabag\Controller\Import\OmnivoreController:
arguments:
$rabbitMqProducer: '@old_sound_rabbit_mq.import_omnivore_producer'
$redisProducer: '@wallabag.producer.redis.omnivore'
Wallabag\Controller\Import\FirefoxController:
arguments:
$rabbitMqProducer: '@old_sound_rabbit_mq.import_firefox_producer'
@ -324,6 +329,10 @@ services:
tags:
- { name: wallabag.import, alias: delicious }
Wallabag\Import\OmnivoreImport:
tags:
- { name: wallabag.import, alias: omnivore }
Wallabag\Import\FirefoxImport:
tags:
- { name: wallabag.import, alias: firefox }

View file

@ -19,6 +19,7 @@ services:
$elcuratorConsumer: '@old_sound_rabbit_mq.import_elcurator_consumer'
$shaarliConsumer: '@old_sound_rabbit_mq.import_shaarli_consumer'
$pocketHtmlConsumer: '@old_sound_rabbit_mq.import_pocket_html_consumer'
$omnivoreConsumer: '@old_sound_rabbit_mq.import_omnivore_consumer'
wallabag.consumer.amqp.pocket:
class: Wallabag\Consumer\AMQPEntryConsumer
@ -45,6 +46,11 @@ services:
arguments:
$import: '@Wallabag\Import\DeliciousImport'
wallabag.consumer.amqp.omnivore:
class: Wallabag\Consumer\AMQPEntryConsumer
arguments:
$import: '@Wallabag\Import\OmnivoreImport'
wallabag.consumer.amqp.wallabag_v1:
class: Wallabag\Consumer\AMQPEntryConsumer
arguments:

View file

@ -69,6 +69,22 @@ services:
arguments:
$import: '@Wallabag\Import\DeliciousImport'
# Omnivore
wallabag.queue.redis.omnivore:
class: Simpleue\Queue\RedisQueue
arguments:
$queueName: "wallabag.import.omnivore"
wallabag.producer.redis.omnivore:
class: Wallabag\Redis\Producer
arguments:
- "@wallabag.queue.redis.omnivore"
wallabag.consumer.redis.omnivore:
class: Wallabag\Consumer\RedisEntryConsumer
arguments:
$import: '@Wallabag\Import\OmnivoreImport'
# pocket
wallabag.queue.redis.pocket:
class: Simpleue\Queue\RedisQueue

View file

@ -1,5 +1,5 @@
parameters:
wallabag.version: 2.6.8
wallabag.version: 2.6.10
wallabag.paypal_url: "https://liberapay.com/wallabag/donate"
wallabag.languages:
en: 'English'

673
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@ use Wallabag\Import\DeliciousImport;
use Wallabag\Import\ElcuratorImport;
use Wallabag\Import\FirefoxImport;
use Wallabag\Import\InstapaperImport;
use Wallabag\Import\OmnivoreImport;
use Wallabag\Import\PinboardImport;
use Wallabag\Import\PocketHtmlImport;
use Wallabag\Import\ReadabilityImport;
@ -42,6 +43,7 @@ class ImportCommand extends Command
private InstapaperImport $instapaperImport;
private PinboardImport $pinboardImport;
private DeliciousImport $deliciousImport;
private OmnivoreImport $omnivoreImport;
private WallabagV1Import $wallabagV1Import;
private ElcuratorImport $elcuratorImport;
private ShaarliImport $shaarliImport;
@ -61,7 +63,8 @@ class ImportCommand extends Command
WallabagV1Import $wallabagV1Import,
ElcuratorImport $elcuratorImport,
ShaarliImport $shaarliImport,
PocketHtmlImport $pocketHtmlImport
PocketHtmlImport $pocketHtmlImport,
OmnivoreImport $omnivoreImport
) {
$this->entityManager = $entityManager;
$this->tokenStorage = $tokenStorage;
@ -73,6 +76,7 @@ class ImportCommand extends Command
$this->instapaperImport = $instapaperImport;
$this->pinboardImport = $pinboardImport;
$this->deliciousImport = $deliciousImport;
$this->omnivoreImport = $omnivoreImport;
$this->wallabagV1Import = $wallabagV1Import;
$this->elcuratorImport = $elcuratorImport;
$this->shaarliImport = $shaarliImport;
@ -159,6 +163,9 @@ class ImportCommand extends Command
case 'pocket':
$import = $this->pocketHtmlImport;
break;
case 'omnivore':
$import = $this->omnivoreImport;
break;
default:
$import = $this->wallabagV1Import;
}

View file

@ -28,7 +28,7 @@ class RedisWorkerCommand extends Command
protected function configure()
{
$this
->addArgument('serviceName', InputArgument::REQUIRED, 'Service to use: wallabag_v1, wallabag_v2, pocket, readability, pinboard, delicious, firefox, chrome or instapaper')
->addArgument('serviceName', InputArgument::REQUIRED, 'Service to use: wallabag_v1, wallabag_v2, pocket, readability, pinboard, delicious, omnivore, firefox, chrome or instapaper')
->addOption('maxIterations', '', InputOption::VALUE_OPTIONAL, 'Number of iterations before stopping', false)
;
}

View file

@ -22,6 +22,7 @@ class RabbitMQConsumerTotalProxy
private Consumer $elcuratorConsumer;
private Consumer $shaarliConsumer;
private Consumer $pocketHtmlConsumer;
private Consumer $omnivoreConsumer;
public function __construct(
Consumer $pocketConsumer,
@ -35,7 +36,8 @@ class RabbitMQConsumerTotalProxy
Consumer $deliciousConsumer,
Consumer $elcuratorConsumer,
Consumer $shaarliConsumer,
Consumer $pocketHtmlConsumer
Consumer $pocketHtmlConsumer,
Consumer $omnivoreConsumer
) {
$this->pocketConsumer = $pocketConsumer;
$this->readabilityConsumer = $readabilityConsumer;
@ -49,6 +51,7 @@ class RabbitMQConsumerTotalProxy
$this->elcuratorConsumer = $elcuratorConsumer;
$this->shaarliConsumer = $shaarliConsumer;
$this->pocketHtmlConsumer = $pocketHtmlConsumer;
$this->omnivoreConsumer = $omnivoreConsumer;
}
/**
@ -99,6 +102,9 @@ class RabbitMQConsumerTotalProxy
case 'pocket_html':
$consumer = $this->pocketHtmlConsumer;
break;
case 'omnivore':
$consumer = $this->omnivoreConsumer;
break;
default:
return 0;
}

View file

@ -602,7 +602,7 @@ class EntryController extends AbstractController
*
* @param int $page
*
* @Route("/domain/{id}/{page}", requirements={"id" = ".+"}, defaults={"page" = 1}, name="same_domain")
* @Route("/domain/{id}/{page}", requirements={"id" = "\d+"}, defaults={"page" = 1}, name="same_domain")
* @IsGranted("LIST_ENTRIES")
*
* @return Response

View file

@ -59,6 +59,7 @@ class ImportController extends AbstractController
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('elcurator')
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('shaarli')
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('pocket_html')
+ $this->rabbitMQConsumerTotalProxy->getTotalMessage('omnivore')
;
} catch (\Exception $e) {
$rabbitNotInstalled = true;
@ -79,6 +80,7 @@ class ImportController extends AbstractController
+ $redis->llen('wallabag.import.elcurator')
+ $redis->llen('wallabag.import.shaarli')
+ $redis->llen('wallabag.import.pocket_html')
+ $redis->llen('wallabag.import.omnivore')
;
} catch (\Exception $e) {
$redisNotInstalled = true;

View file

@ -0,0 +1,84 @@
<?php
namespace Wallabag\Controller\Import;
use Craue\ConfigBundle\Util\Config;
use OldSound\RabbitMqBundle\RabbitMq\Producer as RabbitMqProducer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
use Wallabag\Controller\AbstractController;
use Wallabag\Form\Type\UploadImportType;
use Wallabag\Import\OmnivoreImport;
use Wallabag\Redis\Producer as RedisProducer;
class OmnivoreController extends AbstractController
{
private RabbitMqProducer $rabbitMqProducer;
private RedisProducer $redisProducer;
public function __construct(RabbitMqProducer $rabbitMqProducer, RedisProducer $redisProducer)
{
$this->rabbitMqProducer = $rabbitMqProducer;
$this->redisProducer = $redisProducer;
}
/**
* @Route("/import/omnivore", name="import_omnivore")
*/
public function indexAction(Request $request, OmnivoreImport $omnivore, Config $craueConfig, TranslatorInterface $translator)
{
$form = $this->createForm(UploadImportType::class);
$form->handleRequest($request);
$omnivore->setUser($this->getUser());
if ($craueConfig->get('import_with_rabbitmq')) {
$omnivore->setProducer($this->rabbitMqProducer);
} elseif ($craueConfig->get('import_with_redis')) {
$omnivore->setProducer($this->redisProducer);
}
if ($form->isSubmitted() && $form->isValid()) {
$file = $form->get('file')->getData();
$markAsRead = $form->get('mark_as_read')->getData();
$name = 'omnivore_' . $this->getUser()->getId() . '.json';
if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag.resource_dir'), $name)) {
$res = $omnivore
->setFilepath($this->getParameter('wallabag.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
->import();
$message = 'flashes.import.notice.failed';
if (true === $res) {
$summary = $omnivore->getSummary();
$message = $translator->trans('flashes.import.notice.summary', [
'%imported%' => $summary['imported'],
'%skipped%' => $summary['skipped'],
]);
if (0 < $summary['queued']) {
$message = $translator->trans('flashes.import.notice.summary_with_queue', [
'%queued%' => $summary['queued'],
]);
}
unlink($this->getParameter('wallabag.resource_dir') . '/' . $name);
}
$this->addFlash('notice', $message);
return $this->redirect($this->generateUrl('homepage'));
}
$this->addFlash('notice', 'flashes.import.notice.failed_on_file');
}
return $this->render('Import/Omnivore/index.html.twig', [
'form' => $form->createView(),
'import' => $omnivore,
]);
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace Wallabag\Import;
use Wallabag\Entity\Entry;
class OmnivoreImport extends AbstractImport
{
private $filepath;
public function getName()
{
return 'Omnivore';
}
public function getUrl()
{
return 'import_omnivore';
}
public function getDescription()
{
return 'import.omnivore.description';
}
/**
* Set file path to the json file.
*
* @param string $filepath
*/
public function setFilepath($filepath)
{
$this->filepath = $filepath;
return $this;
}
public function import()
{
if (!$this->user) {
$this->logger->error('OmnivoreImport: user is not defined');
return false;
}
if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
$this->logger->error('OmnivoreImport: unable to read file', ['filepath' => $this->filepath]);
return false;
}
$data = json_decode(file_get_contents($this->filepath), true);
if (empty($data)) {
$this->logger->error('OmnivoreImport: no entries in imported file');
return false;
}
if ($this->producer) {
$this->parseEntriesForProducer($data);
return true;
}
$this->parseEntries($data);
return true;
}
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['url'])) {
return false;
}
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;
}
$data = [
'title' => $importedEntry['title'],
'url' => $importedEntry['url'],
'is_archived' => ('Archived' === $importedEntry['state']) || $this->markAsRead,
'is_starred' => false,
'created_at' => $importedEntry['savedAt'],
'tags' => $importedEntry['labels'],
'published_by' => [$importedEntry['author']],
'published_at' => $importedEntry['publishedAt'],
'preview_picture' => $importedEntry['thumbnail'],
];
$entry = new Entry($this->user);
$entry->setUrl($data['url']);
$entry->setTitle($data['title']);
// update entry with content (in case fetching failed, the given entry will be return)
$this->fetchContent($entry, $data['url'], $data);
if (!empty($data['tags'])) {
$this->tagsAssigner->assignTagsToEntry(
$entry,
$data['tags'],
$this->em->getUnitOfWork()->getScheduledEntityInsertions()
);
}
$entry->updateArchived($data['is_archived']);
$entry->setCreatedAt(\DateTime::createFromFormat('Y-m-d\TH:i:s.u\Z', $data['created_at']));
if (null !== $data['published_at']) {
$entry->setPublishedAt(\DateTime::createFromFormat('Y-m-d\TH:i:s.u\Z', $data['published_at']));
}
$entry->setPublishedBy($data['published_by']);
$entry->setPreviewPicture($data['preview_picture']);
$this->em->persist($entry);
++$this->importedEntries;
return $entry;
}
protected function setEntryAsRead(array $importedEntry)
{
return $importedEntry;
}
}

View file

@ -1,3 +1,45 @@
{% extends "Import/WallabagV1/index.html.twig" %}
{% extends "layout.html.twig" %}
{% block title %}{{ 'import.elcurator.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 }}</blockquote>
<p>{{ 'import.elcurator.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>
<div class="input-field col s6 with-checkbox">
<h6>{{ 'import.form.mark_as_read_title'|trans }}</h6>
{{ form_widget(form.mark_as_read) }}
{{ form_label(form.mark_as_read) }}
</div>
</div>
{{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
{{ form_rest(form) }}
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,45 @@
{% extends "layout.html.twig" %}
{% block title %}{{ 'import.omnivore.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 }}</blockquote>
<p>{{ 'import.omnivore.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>
<div class="input-field col s6 with-checkbox">
<h6>{{ 'import.form.mark_as_read_title'|trans }}</h6>
{{ form_widget(form.mark_as_read) }}
{{ form_label(form.mark_as_read) }}
</div>
</div>
{{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
{{ form_rest(form) }}
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -104,7 +104,7 @@
<ul>
<li><a href="https://github.com/wallabag/wallabag/issues/">{{ 'quickstart.support.github'|trans }}</a></li>
<li><a href="mailto:hello@wallabag.org">{{ 'quickstart.support.email'|trans }}</a></li>
<li><a href="https://gitter.im/wallabag/wallabag">{{ 'quickstart.support.gitter'|trans }}</a></li>
<li><a href="https://matrix.to/#/#wallabag:matrix.org">{{ 'quickstart.support.matrix'|trans }}</a></li>
</ul>
</div>
</div>

View file

@ -24,6 +24,6 @@ class ImportControllerTest extends WallabagTestCase
$crawler = $client->request('GET', '/import/');
$this->assertSame(200, $client->getResponse()->getStatusCode());
$this->assertSame(12, $crawler->filter('blockquote')->count());
$this->assertSame(13, $crawler->filter('blockquote')->count());
}
}

View file

@ -0,0 +1,203 @@
<?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 OmnivoreControllerTest extends WallabagTestCase
{
public function testImportOmnivore()
{
$this->logInAs('admin');
$client = $this->getTestClient();
$crawler = $client->request('GET', '/import/omnivore');
$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 testImportOmnivoreWithRabbitEnabled()
{
$this->logInAs('admin');
$client = $this->getTestClient();
$client->getContainer()->get(Config::class)->set('import_with_rabbitmq', 1);
$crawler = $client->request('GET', '/import/omnivore');
$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 testImportOmnivoreBadFile()
{
$this->logInAs('admin');
$client = $this->getTestClient();
$crawler = $client->request('GET', '/import/omnivore');
$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 testImportOmnivoreWithRedisEnabled()
{
$this->checkRedis();
$this->logInAs('admin');
$client = $this->getTestClient();
$client->getContainer()->get(Config::class)->set('import_with_redis', 1);
$crawler = $client->request('GET', '/import/omnivore');
$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/omnivore.json', 'omnivore.json');
$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.omnivore'));
$client->getContainer()->get(Config::class)->set('import_with_redis', 0);
}
public function testImportOmnivoreWithFile()
{
$this->logInAs('admin');
$client = $this->getTestClient();
$crawler = $client->request('GET', '/import/omnivore');
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
$file = new UploadedFile(__DIR__ . '/../../fixtures/Import/omnivore.json', 'omnivore.json');
$data = [
'upload_import_file[file]' => $file,
];
$client->submit($form, $data);
$this->assertSame(302, $client->getResponse()->getStatusCode());
$crawler = $client->followRedirect();
$content = $client->getContainer()
->get(EntityManagerInterface::class)
->getRepository(Entry::class)
->findByUrlAndUserId(
'https://www.lemonde.fr/economie/article/2024/10/29/malgre-la-crise-du-marche-des-montres-breitling-etend-son-reseau-commercial-et-devoile-ses-ambitions_6365425_3234.html',
$this->getLoggedInUserId()
);
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
$this->assertStringContainsString('flashes.import.notice.summary', $body[0]);
$this->assertInstanceOf(Entry::class, $content);
$tags = $content->getTagsLabel();
$this->assertContains('rss', $tags, 'It includes the "rss" tag');
$this->assertGreaterThanOrEqual(2, \count($tags));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertSame('2024-10-29', $content->getCreatedAt()->format('Y-m-d'));
}
public function testImportOmnivoreWithFileAndMarkAllAsRead()
{
$this->logInAs('admin');
$client = $this->getTestClient();
$crawler = $client->request('GET', '/import/omnivore');
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
$file = new UploadedFile(__DIR__ . '/../../fixtures/Import/omnivore.json', 'omnivore-read.json');
$data = [
'upload_import_file[file]' => $file,
'upload_import_file[mark_as_read]' => 1,
];
$client->submit($form, $data);
$this->assertSame(302, $client->getResponse()->getStatusCode());
$crawler = $client->followRedirect();
$content1 = $client->getContainer()
->get(EntityManagerInterface::class)
->getRepository(Entry::class)
->findByUrlAndUserId(
'https://www.lemonde.fr/economie/article/2024/10/29/l-union-europeenne-adopte-jusqu-a-35-de-surtaxes-sur-les-voitures-electriques-importees-de-chine_6365258_3234.html',
$this->getLoggedInUserId()
);
$this->assertInstanceOf(Entry::class, $content1);
$content2 = $client->getContainer()
->get(EntityManagerInterface::class)
->getRepository(Entry::class)
->findByUrlAndUserId(
'https://www.lemonde.fr/les-decodeurs/article/2024/10/29/presidentielle-americaine-2024-comment-le-calendrier-de-l-election-et-des-affaires-judiciaires-de-trump-s-entremelent_6210916_3211.html',
$this->getLoggedInUserId()
);
$this->assertInstanceOf(Entry::class, $content2);
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
$this->assertStringContainsString('flashes.import.notice.summary', $body[0]);
}
public function testImportOmnivoreWithEmptyFile()
{
$this->logInAs('admin');
$client = $this->getTestClient();
$crawler = $client->request('GET', '/import/omnivore');
$form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
$file = new UploadedFile(__DIR__ . '/../../fixtures/Import/test.txt', 'test.txt');
$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]);
}
}

343
tests/fixtures/Import/omnivore.json vendored Normal file
View file

@ -0,0 +1,343 @@
[
{
"id": "20db074a-34e1-4f55-b0e9-161e367946f6",
"slug": "malgre-la-crise-du-marche-des-montres-breitling-etend-son-reseau-192daf3a84e",
"title": "Malgré la crise du marché des montres, Breitling étend son réseau commercial et dévoile ses ambitions",
"description": "La marque suisse  peu présente en Chine  veut sétendre ailleurs en Asie et nexclut pas des acquisitions. En France, après sêtre installée sur les Champs-Elysées, elle ouvre boutique à Lille et à Monaco.",
"author": "Juliette Garnier",
"url": "https://www.lemonde.fr/economie/article/2024/10/29/malgre-la-crise-du-marche-des-montres-breitling-etend-son-reseau-commercial-et-devoile-ses-ambitions_6365425_3234.html",
"state": "Archived",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/234/0/6192/3096/1440/720/60/0/5ee3f32_1730201062245-063-1432929408.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T16:30:11.000Z",
"updatedAt": "2024-10-31T13:01:28.320Z",
"publishedAt": "2024-10-29T16:30:11.000Z"
},
{
"id": "5ace624c-ba30-48cc-82ba-5a4d585e0cd4",
"slug": "espagne-l-enquete-visant-l-epouse-de-pedro-sanchez-elargie-ce-de-192d9fe5ee4",
"title": "Espagne : lenquête visant lépouse de Pedro Sanchez élargie, ce dernier fait part de sa « tranquillité absolue »",
"description": "Begoña Gomez fait lobjet dune enquête pour corruption et trafic dinfluence, ouverte après des plaintes déposées par deux associations réputées proches de lextrême droite.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/international/article/2024/10/29/espagne-l-enquete-visant-l-epouse-de-pedro-sanchez-elargie-ce-dernier-fait-part-de-sa-tranquillite-absolue_6365392_3210.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/385/0/3266/1633/1440/720/60/0/54ca5e3_2024-10-29t141242z-866115530-rc2g8aaxq4l9-rtrmadp-3-spain-argentina.JPG",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T16:21:32.000Z",
"updatedAt": "2024-10-29T20:36:19.400Z",
"publishedAt": "2024-10-29T16:21:32.000Z"
},
{
"id": "1d72bb2e-2b3d-4d2d-8f17-90f441024358",
"slug": "montpellier-enquete-ouverte-apres-la-mort-d-une-jeune-femme-des--192d9fe4e61",
"title": "Montpellier : enquête ouverte après la mort dune jeune femme des suites dune méningite, malgré des appels au SAMU et aux pompiers",
"description": "Malgré deux appels aux secours, lun au 15 et lautre au 18, ce sont deux amis qui ont conduit la femme de 25 ans à une clinique montpelliéraine, avant quelle ne soit transférée au CHU et ne meure.",
"author": "Le Monde",
"url": "https://www.lemonde.fr/societe/article/2024/10/29/montpellier-enquete-ouverte-apres-la-mort-d-une-jeune-femme-des-suites-d-une-meningite-malgre-des-appels-au-samu-et-aux-pompiers_6365359_3224.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/24/187/0/2250/1125/1440/720/60/0/4e171be_1729786778722-frame-159.jpg",
"labels": [
"RSS",
"TEST"
],
"savedAt": "2024-10-29T16:09:19.000Z",
"updatedAt": "2024-10-31T13:03:21.779Z",
"publishedAt": "2024-10-29T16:09:19.000Z"
},
{
"id": "5ac06f9c-52e8-47df-984c-038c501819cb",
"slug": "tuberculose-le-nombre-de-cas-dans-le-monde-se-stabilise-apres-le-192daa35669",
"title": "Tuberculose : le nombre de cas dans le monde se stabilise après le regain des années Covid",
"description": "Lincidence de la maladie est en baisse de 8,3 % par rapport aux chiffres de 2015, mais reste loin de lobjectif initialement fixé de diviser par deux le nombre de malades dici à 2025.",
"author": "Delphine Roucaute",
"url": "https://www.lemonde.fr/planete/article/2024/10/29/tuberculose-le-nombre-de-cas-dans-le-monde-se-stabilise-apres-le-regain-des-annees-covid_6365326_3244.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/501/0/6009/3004/1440/720/60/0/01bc1cc_1730215288364-000-34ne6t2.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T16:02:03.000Z",
"updatedAt": "2024-10-29T23:36:30.655Z",
"publishedAt": "2024-10-29T16:02:03.000Z"
},
{
"id": "2f870f6d-79a9-45a4-8a64-e4cd3e7c4488",
"slug": "l-union-europeenne-adopte-jusqu-a-35-de-surtaxes-sur-les-voiture-192d9fe4fa0",
"title": "LUnion européenne adopte jusquà 35 % de surtaxes sur les voitures électriques importées de Chine",
"description": "Lobjectif affiché est de rétablir des conditions de concurrence équitables avec des constructeurs accusés de profiter de subventions publiques massives.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/economie/article/2024/10/29/l-union-europeenne-adopte-jusqu-a-35-de-surtaxes-sur-les-voitures-electriques-importees-de-chine_6365258_3234.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/03/131/0/2405/1202/1440/720/60/0/9f89e19_5860742-01-06.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T15:36:53.000Z",
"updatedAt": "2024-10-29T20:36:15.460Z",
"publishedAt": "2024-10-29T15:36:53.000Z"
},
{
"id": "fe9efcb1-1782-46c3-805d-c9b8074bee3b",
"slug": "l-ex-patron-de-la-dgse-bernard-bajolet-sera-juge-pour-complicite-192da0f4619",
"title": "Lex-patron de la DGSE Bernard Bajolet sera jugé pour complicité de tentative dextorsion",
"description": "Lhomme daffaires Alain Duménil accuse le service de renseignement davoir fait usage de la contrainte pour lui réclamer de largent en 2016.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/societe/article/2024/10/29/l-ex-patron-de-la-dgse-bernard-bajolet-sera-juge-pour-complicite-de-tentative-d-extorsion_6365225_3224.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/99/0/4804/2402/1440/720/60/0/e26408c_1730213831930-000-32hg2qa.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T15:32:35.000Z",
"updatedAt": "2024-10-29T20:54:47.245Z",
"publishedAt": "2024-10-29T15:32:35.000Z"
},
{
"id": "885df5b1-b564-4535-8ad7-f65bb934375d",
"slug": "la-cour-d-appel-de-paris-confirme-le-proces-pour-viol-du-rappeur-192da4a24d7",
"title": "La cour dappel de Paris confirme le procès pour viol du rappeur Naps",
"description": "Lartiste est soupçonné davoir violé une jeune femme pendant son sommeil à lautomne 2021.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/societe/article/2024/10/29/la-cour-d-appel-de-paris-confirme-le-proces-pour-viol-du-rappeur-naps_6365192_3224.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/369/0/4430/2215/1440/720/60/0/78d02d3_1730214584579-000-9t294r.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T15:26:15.000Z",
"updatedAt": "2024-10-29T21:59:05.276Z",
"publishedAt": "2024-10-29T15:26:15.000Z"
},
{
"id": "647e36c0-2782-42b0-8694-8599b61e912a",
"slug": "les-serbes-apres-leur-medaille-de-bronze-aux-jo-on-a-bu-pendant--192d9ed5eef",
"title": "Les Serbes après leur médaille de bronze aux JO : \"On a bu pendant huit heures !\"",
"description": "Lors de la cérémonie de remise de médailles des Jeux Olympiques de Paris, les Serbes se sont fait remarquer en titubant sur le podium. La raison est simple...",
"author": "La rédaction",
"url": "https://www.basketeurope.com/les-serbes-apres-leur-medaille-de-bronze-aux-j0-on-a-bu-pendant-huit-heures/",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://www.basketeurope.com/content/images/2024/10/Marinkovic.webp",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T13:59:23.000Z",
"updatedAt": "2024-10-29T20:17:45.252Z",
"publishedAt": "2024-10-29T13:59:23.000Z"
},
{
"id": "40c17460-d4bc-4408-aafb-3f6ffbe8d413",
"slug": "a-quoi-ressemble-le-parcours-du-tour-de-france-2025-192d9fe6f1d",
"title": "A quoi ressemble le parcours du Tour de France 2025 ?",
"description": "Le parcours de la prochaine Grande Boucle cycliste a été dévoilé mardi. Le peloton sélancera de Lille pour retrouver, trois semaines plus tard, la traditionnelle arrivée sur les Champs-Elysées, à Paris. Entre-temps, il lui faudra enchaîner les cols mythiques.",
"author": "Valentin Moinard",
"url": "https://www.lemonde.fr/sport/article/2024/10/29/cyclisme-le-tour-de-france-2025-fera-la-part-belle-aux-grimpeurs_6364955_3242.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/07/07/410/0/5994/2997/1440/720/60/0/1df95b2_5013615-01-06.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T13:12:05.000Z",
"updatedAt": "2024-10-29T20:36:23.653Z",
"publishedAt": "2024-10-29T13:12:05.000Z"
},
{
"id": "d4eb58ef-1cab-4aef-aee1-89dca60b8a80",
"slug": "arrets-maladie-des-fonctionnaires-les-arguments-discutables-du-g-192d9fe680a",
"title": "Arrêts maladie des fonctionnaires : les arguments discutables du gouvernement pour justifier sa réforme",
"description": "Alors que lexécutif souhaite ne plus payer les trois premiers jours dabsence des agents publics, le fait quil prenne peu en compte lamélioration de la qualité de vie au travail lui vaut de vives critiques, de la part des syndicats, mais aussi de personnalités ayant lexpérience du terrain.",
"author": "Bertrand Bissuel",
"url": "https://www.lemonde.fr/politique/article/2024/10/29/arrets-maladie-des-fonctionnaires-les-arguments-discutables-du-gouvernement-pour-justifier-sa-reforme_6364919_823448.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/265/0/6720/3360/1440/720/60/0/2f2f937_1730191618529-cbi1223010.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T13:00:08.000Z",
"updatedAt": "2024-10-29T20:36:21.703Z",
"publishedAt": "2024-10-29T13:00:08.000Z"
},
{
"id": "ff9c411a-e91f-424b-a570-f92b311026a5",
"slug": "premium-jean-denys-choulet-selectionneur-du-kosovo-ma-nationalit-192db836507",
"title": "[Premium] Jean-Denys Choulet, sélectionneur du Kosovo : \"Ma nationalité, c'est le basket\"",
"description": "Huit mois après son licenciement de la Chorale de Roanne, Jean-Denys Choulet a retrouvé un poste en tant que sélectionneur du Kosovo. À 66 ans, il ne se voyait pas quitter le milieu du basket et reste ouvert à l'idée de diriger un club.",
"author": "Morgan Parmentier",
"url": "https://www.basketeurope.com/premium-jean-denys-choulet-ma-nationalite-cest-le-basket/",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://www.basketeurope.com/content/images/size/w1200/2024/10/choulet-jd-chorale-roanne-tuan-nguyen.webp",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T12:31:47.000Z",
"updatedAt": "2024-10-30T03:41:14.412Z",
"publishedAt": "2024-10-29T12:31:47.000Z"
},
{
"id": "54ae4346-03c0-407e-b204-b09351174365",
"slug": "pedocriminalite-l-eglise-doit-mieux-sanctionner-les-auteurs-et-a-192da2d8b8f",
"title": "Pédocriminalité : lEglise doit mieux sanctionner les auteurs et aider les victimes, selon un rapport du Vatican",
"description": "En avril 2022, le pape François avait demandé à une commission pontificale un rapport sur la protection des mineurs dans lEglise. Très attendu, il vient dêtre publié par le Saint-Siège.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/international/article/2024/10/29/pedocriminalite-l-eglise-doit-mieux-sanctionner-les-auteurs-et-aider-les-victimes-selon-un-rapport-du-vatican_6364916_3210.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/27/688/0/8256/4128/1440/720/60/0/a7b4e07_5084272-01-06.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T12:26:36.000Z",
"updatedAt": "2024-10-29T21:27:50.999Z",
"publishedAt": "2024-10-29T12:26:36.000Z"
},
{
"id": "b2d30e8c-c344-4460-a583-4a2955fdc197",
"slug": "cybercriminalite-les-stealers-redline-et-meta-vises-par-une-oper-192d90d1624",
"title": "Cybercriminalité : les « stealers » Redline et META visés par une opération policière internationale",
"description": "Le marché des identifiants dérobés est devenu un secteur central de la cybercriminalité. Les deux virus visés par cette opération policière, baptisée « Magnus », ont permis le vol de plus de 227 millions de mots de passe en 2024.",
"author": "Florian Reynaud",
"url": "https://www.lemonde.fr/pixels/article/2024/10/29/cybercriminalite-les-stealers-redline-et-meta-vises-par-une-operation-policiere-internationale_6364915_4408996.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/10/252/0/3008/1504/1440/720/60/0/b3dbd8e_1728546840972-papier-271-16.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T12:21:06.000Z",
"updatedAt": "2024-10-29T16:12:46.658Z",
"publishedAt": "2024-10-29T12:21:06.000Z"
},
{
"id": "a4a6e509-beab-4577-99db-2f1db819d669",
"slug": "au-maroc-emmanuel-macron-appelle-a-plus-de-resultats-contre-l-im-192d90d159a",
"title": "Au Maroc, Emmanuel Macron appelle à plus de « résultats » contre limmigration illégale et réaffirme son soutien à la « souveraineté marocaine » au Sahara occidental",
"description": "Le chef de lEtat français a également proposé au roi du Maroc, Mohammed VI, de signer un nouveau « cadre stratégique » bilatéral en 2025 à Paris, soixante-dix ans après la déclaration de la Celle-Saint-Cloud qui scella lindépendance du Maroc de la France.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/international/article/2024/10/29/au-maroc-emmanuel-macron-appelle-a-plus-de-resultats-contre-l-immigration-illegale-et-reaffirme-son-soutien-a-la-souverainete-marocaine-au-sahara-occidental_6364914_3210.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/350/0/4201/2100/1440/720/60/0/c37301c_5103313-01-06.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T12:14:53.000Z",
"updatedAt": "2024-10-29T16:12:46.456Z",
"publishedAt": "2024-10-29T12:14:53.000Z"
},
{
"id": "0ab9e8c7-c88b-4a31-af3e-62ec4766b99d",
"slug": "prison-de-noumea-l-etat-condamne-car-trop-lent-a-ameliorer-les-c-192d90d0722",
"title": "Prison de Nouméa : lEtat condamné car trop lent à améliorer les conditions de détention",
"description": "En 2020, le Conseil dEtat avait exigé des mesures urgentes pour les droits des détenus au Camp-Est, mais ladministration a pris du retard et les travaux nauront pas lieu avant 2028, selon lObservatoire international des prisons.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/societe/article/2024/10/29/prison-de-noumea-l-etat-condamne-car-trop-lent-a-ameliorer-les-conditions-de-detention_6364912_3224.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/520/0/4160/2080/1440/720/60/0/9ec59fb_1730203377797-cdo-cellule-case-g-cp-nouma-a-2.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T12:08:18.000Z",
"updatedAt": "2024-10-29T16:12:42.744Z",
"publishedAt": "2024-10-29T12:08:18.000Z"
},
{
"id": "fe79a70e-d1e1-43fe-8555-094209d1b48d",
"slug": "tour-de-france-femmes-2025-la-course-traversera-l-hexagone-d-oue-192da131a9a",
"title": "Tour de France Femmes 2025 : la course traversera lHexagone dOuest en Est, de la Bretagne aux Alpes",
"description": "Le parcours de la quatrième édition de la course cycliste a été présenté mardi. Du 26 juillet au 3 août, il fera la part belle aux grimpeuses, qui auront trois étapes finales dans le massif alpin pour sillustrer.",
"author": "Valentin Moinard",
"url": "https://www.lemonde.fr/sport/article/2024/10/29/tour-de-france-femmes-2025-de-la-bretagne-aux-alpes-la-course-traversera-la-france-d-ouest-en-est_6364908_3242.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/08/17/1194/0/7268/3634/1440/720/60/0/8bafa27_5442255-01-06.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T11:52:45.000Z",
"updatedAt": "2024-10-29T20:58:58.164Z",
"publishedAt": "2024-10-29T11:52:45.000Z"
},
{
"id": "54687e28-21e1-42b4-bb92-cc5f39716464",
"slug": "en-direct-guerre-au-proche-orient-le-bombardement-israelien-sur--192da214287",
"title": "En direct, guerre au Proche-Orient : le bombardement israélien sur le nord de la bande de Gaza a fait 93 morts, selon un nouveau bilan de la défense civile",
"description": "Un précédent bilan, établi par la même source, faisait état de 55 morts. Lattaque aérienne, qui a eu lieu dans la nuit de lundi à mardi, a visé la ville de Beit Lahya, dans le nord de la bande de Gaza.",
"author": "Seb2000",
"url": "https://www.lemonde.fr/international/live/2024/10/29/en-direct-guerre-au-proche-orient-le-bombardement-israelien-sur-le-nord-de-la-bande-de-gaza-a-fait-93-morts-selon-un-nouveau-bilan-de-la-defense-civile_6362390_3210.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/303/0/3644/1822/1440/720/60/0/6b6faba_1730210101426-468617.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T11:52:34.000Z",
"updatedAt": "2024-10-29T21:14:26.095Z",
"publishedAt": "2024-10-29T11:52:34.000Z"
},
{
"id": "a2b54509-62ad-4ab7-a68a-2a970ac25952",
"slug": "au-chili-le-gouvernement-de-gauche-malmene-aux-elections-locales-192da0e7d74",
"title": "Au Chili, le gouvernement de gauche malmené aux élections locales",
"description": "La droite de la coalition Chile Vamos sort renforcée des élections municipales et régionales, tandis que lextrême droite progresse, sans enregistrer la percée quelle espérait.",
"author": "Flora Genoux",
"url": "https://www.lemonde.fr/international/article/2024/10/29/au-chili-le-gouvernement-de-gauche-malmene-aux-elections-locales_6364875_3210.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/720/0/8640/4320/1440/720/60/0/3632d71_1730193220296-852876.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T11:31:53.000Z",
"updatedAt": "2024-10-29T20:53:55.779Z",
"publishedAt": "2024-10-29T11:31:53.000Z"
},
{
"id": "9c68ff83-1927-4377-a3b0-a048516a725d",
"slug": "en-isere-lyes-louffok-est-le-candidat-insoumis-investi-a-l-elect-192d90d319e",
"title": "En Isère, Lyes Louffok est le candidat « insoumis » investi à lélection législative partielle",
"description": "Le siège est vacant depuis la démission dHugo Prevost (LFI), accusé de violences sexistes et sexuelles.",
"author": "Le Monde avec AFP",
"url": "https://www.lemonde.fr/politique/article/2024/10/29/en-isere-lyes-louffok-est-le-candidat-insoumis-investi-a-l-election-legislative-partielle_6364842_823448.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/10/29/552/0/6628/3314/1440/720/60/0/607f0f6_1730199775062-000-34r33w7.jpg",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T11:24:36.000Z",
"updatedAt": "2024-10-29T16:12:53.630Z",
"publishedAt": "2024-10-29T11:24:36.000Z"
},
{
"id": "1015c224-bd79-4ed9-9268-8fa9803a52cd",
"slug": "presidentielle-americaine-2024-comment-le-calendrier-de-l-electi-192d90d3440",
"title": "Présidentielle américaine 2024 : comment le calendrier de lélection et des affaires judiciaires de Trump sentremêlent",
"description": "Le verdict du procès visant lancien président ne devrait être connu quaprès lélection, et le reste des poursuites pénales reste incertain. « Le Monde » vous propose de suivre le déroulé, mis à jour continuellement, de cette année décisive pour les Etats-Unis.",
"author": "Gary Dagorn, Jean-Philippe Lefief",
"url": "https://www.lemonde.fr/les-decodeurs/article/2024/10/29/presidentielle-americaine-2024-comment-le-calendrier-de-l-election-et-des-affaires-judiciaires-de-trump-s-entremelent_6210916_3211.html",
"state": "Active",
"readingProgress": 0,
"thumbnail": "https://img.lemde.fr/2024/01/12/0/0/1500/750/1440/720/60/0/e9367e3_1705065713486-chrono-media-appel.png",
"labels": [
"RSS"
],
"savedAt": "2024-10-29T11:17:19.000Z",
"updatedAt": "2024-10-29T16:12:54.352Z",
"publishedAt": "2024-10-29T11:17:19.000Z"
}
]

View file

@ -354,7 +354,6 @@ tag:
quickstart:
support:
title: Podpora
gitter: Na Gitteru
email: E-mailem
github: Na GitHubu
description: Pokud potřebujete pomoc, jsme tu pro vás.

View file

@ -467,7 +467,7 @@ quickstart:
description: Wenn du Hilfe brauchst, wir sind für dich da.
github: Auf GitHub
email: Über E-Mail
gitter: Auf Gitter
matrix: Auf Matrix
tag:
page_title: Tags
list:

View file

@ -248,7 +248,7 @@ tag:
page_title: Ετικέτες
quickstart:
support:
gitter: Στο Gitter
matrix: Στο Matrix
email: Με email
github: Στο GitHub
description: Αν χρειάζεστε βοήθεια, είμαστε εδώ για εσάς.

View file

@ -468,7 +468,7 @@ quickstart:
description: If you need some help, we are here for you.
github: On GitHub
email: By email
gitter: On Gitter
matrix: On Matrix
tag:
confirm:
delete: Delete the %name% tag
@ -513,6 +513,11 @@ import:
elcurator:
page_title: 'Import > elCurator'
description: 'This importer will import all your elCurator articles.'
how_to: Please select your elCurator export and click on the button below to upload and import it.
omnivore:
page_title: 'Import > Omnivore'
description: 'This importer will import all your Omnivore articles.'
how_to: Please unzip your Omnivore export, then upload each JSON file named "metadata_x_to_y.json" one by one.
readability:
page_title: Import > Readability
description: This importer will import all your Readability articles.

View file

@ -485,7 +485,7 @@ quickstart:
description: 'Si necesitas ayuda, estamos a tu disposición.'
github: 'En GitHub'
email: 'Por correo electrónico'
gitter: 'En Gitter'
matrix: 'En Matrix'
tag:
page_title: 'Etiquetas'
list:

View file

@ -282,7 +282,6 @@ quickstart:
description: به کمک نیاز دارید؟ ما پشتیبان شما هستیم.
github: روی گیت‌هاب
email: با ایمیل
gitter: روی گیتر
tag:
page_title: برچسب‌ها
list:

View file

@ -469,7 +469,7 @@ quickstart:
description: Parce que vous avez peut-être besoin de nous poser une question, nous sommes disponibles pour vous.
github: Sur GitHub
email: Par courriel
gitter: Sur Gitter
matrix: Sur Matrix
tag:
confirm:
delete: Supprimer le tag %name%
@ -507,7 +507,7 @@ import:
wallabag_v1:
page_title: Importer > wallabag v1
description: Cet outil va importer toutes vos données de wallabag v1. Sur votre page de configuration de wallabag v1, cliquez sur « Export JSON » dans la section « Exporter vos données de wallabag ». Vous allez récupérer un fichier « wallabag-export-1-xxxx-xx-xx.json ».
how_to: Choisissez le fichier de votre export wallabag v1 et cliquez sur le bouton ci-dessous pour limporter.
how_to: Choisissez le fichier de votre export wallabag et cliquez sur le bouton ci-dessous pour limporter.
wallabag_v2:
page_title: Importer > wallabag v2
description: Cet outil va importer tous vos articles dune autre instance de wallabag v2. Allez dans tous vos articles, puis, sur la barre latérale, cliquez sur « JSON ». Vous allez récupérer un fichier « All articles.json ».
@ -537,6 +537,7 @@ import:
elcurator:
description: Cet outil va importer tous vos articles depuis elCurator.
page_title: Importer > elCurator
how_to: Choisissez le fichier de votre export elCurator et cliquez sur le bouton ci-dessous pour limporter.
delicious:
page_title: Importer > del.icio.us
how_to: Choisissez le fichier de votre export Delicious et cliquez sur le bouton ci-dessous pour l'importer.

View file

@ -497,7 +497,7 @@ tag:
delete: Eliminar a etiqueta %name%
quickstart:
support:
gitter: En Gitter
matrix: En Matrix
email: Por email
github: En GitHub
description: Se precisas axuda, aquí estamos para ti.

View file

@ -647,7 +647,6 @@ quickstart:
use_docker: Koristi Docker za instliranje wallabaga
support:
github: Na GitHubu
gitter: Na Gitteru
title: Podrška
email: Putem e-maila
description: Ako trebaš pomoć, spremni smo ti pomoći.

View file

@ -382,7 +382,7 @@ quickstart:
description: Ha segítségre van szüksége, itt vagyunk az Ön számára.
github: A GitHub-on
email: E-mailben
gitter: A Gitter-en
matrix: A Matrix-en
tag:
page_title: Címkék
list:

View file

@ -401,7 +401,7 @@ quickstart:
description: Se hai bisogno di aiuto, siamo qui per te.
github: Su GitHub
email: Per e-mail
gitter: Su Gitter
matrix: Su Matrix
tag:
page_title: Etichette
list:

View file

@ -462,7 +462,7 @@ quickstart:
description: 何か助けが必要な場合は、私たちがお役に立ちます。
github: GitHub 上で
email: メールで
gitter: Gitter 上で
matrix: Matrix 上で
tag:
list:
number_on_the_page: '{0} タグはありません。|{1} 1 つタグがあります。|]1,Inf[ %count% タグがあります。'

View file

@ -642,7 +642,7 @@ quickstart:
more: 더보기…
page_title: 빠른시작
support:
gitter: Gitter 에서
matrix: Matrix 에서
email: 이메일로
github: GitHub에서
description: 도움이 필요하시면 저희가 도와 드리겠습니다.

View file

@ -526,7 +526,7 @@ quickstart:
title: Sett opp programmet
description: For å få applikasjon til og passe deg, ta en titt på konfigurasjonen til wallabag.
support:
gitter: På Gitter
matrix: På Matrix
email: Per e-post
github: På GitHub
title: Støtte

View file

@ -463,7 +463,7 @@ quickstart:
support:
description: Wij zijn er voor u als u hulp nodig heeft.
title: Ondersteuning
gitter: Op Gitter
matrix: Op Matrix
email: Per e-mail
github: Op GitHub
docs:

View file

@ -484,7 +484,7 @@ quickstart:
description: Perque avètz benlèu besonh de nos pausar una question, sèm disponibles per vosautres.
github: Sus GitHub
email: Per e-mail
gitter: Sus Gitter
matrix: Sus Matrix
tag:
page_title: Etiquetas
list:

View file

@ -485,7 +485,6 @@ quickstart:
description: Jeżeli potrzebujesz pomocy, jesteśmy tutaj dla ciebie.
github: na GitHubie
email: przez e-mail
gitter: na Gitterze
tag:
page_title: Tagi
list:

View file

@ -322,7 +322,7 @@ quickstart:
description: 'Se você precisa de ajuda, nós estamos aqui.'
github: 'No GitHub'
email: 'Por e-mail'
gitter: 'No Gitter'
matrix: 'No Matrix'
tag:
page_title: 'Tags'
list:

View file

@ -469,7 +469,7 @@ quickstart:
description: 'Если Вам нужна помощь, мы здесь чтобы помочь Вам.'
github: 'На GitHub'
email: 'По email'
gitter: 'На Gitter'
matrix: 'На Matrix'
tag:
page_title: 'Теги'
list:

View file

@ -370,7 +370,7 @@ quickstart:
description: 'ถ้าคุณต้องการการชวยเหลอบางอย่าง, พวกเราจะอยู่ที่นี้เพื่อคุณ'
github: 'บน GitHub'
email: 'โดยอีเมล'
gitter: 'บน Gitter'
matrix: 'บน Matrix'
tag:
page_title: 'แท็ก'
list:

View file

@ -471,7 +471,7 @@ quickstart:
description: Eğer yardıma ihtiyacınız varsa, biz her daim senin için burada olacağız.
github: GitHub
email: E-posta
gitter: Gitter
matrix: Matrix
more: Daha fazlası
admin:
title: Yönetim

View file

@ -421,7 +421,7 @@ quickstart:
description: Якщо вам потрібна допомога, ми завжди поруч.
github: На GitHub
email: Електронною поштою
gitter: В Gitter
matrix: В Matrix
tag:
page_title: Теги
list:

View file

@ -484,7 +484,7 @@ quickstart:
description: '如果你需要帮助,我们在这里。'
github: 'GitHub 上'
email: '通过 Email'
gitter: 'Gitter 上'
matrix: 'Matrix 上'
tag:
page_title: '标签'
list:

Binary file not shown.