aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--Gruntfile.js1
-rw-r--r--app/DoctrineMigrations/Version20160410190541.php46
-rw-r--r--app/DoctrineMigrations/Version20160812120952.php25
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml6
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml6
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml6
-rwxr-xr-xapp/Resources/static/themes/baggy/css/print.css4
-rwxr-xr-xapp/Resources/static/themes/material/css/main.css19
-rwxr-xr-xapp/Resources/static/themes/material/css/print.css15
-rw-r--r--app/config/config.yml3
-rw-r--r--app/config/parameters.yml.dist1
-rw-r--r--app/config/security.yml1
-rw-r--r--docs/de/conf.py55
-rw-r--r--docs/de/requirements.txt2
-rw-r--r--docs/de/user/errors_during_fetching.rst2
-rw-r--r--docs/en/user/errors_during_fetching.rst2
-rw-r--r--docs/en/user/import.rst21
-rw-r--r--docs/fr/user/errors_during_fetching.rst2
-rw-r--r--docs/fr/user/import.rst20
-rw-r--r--package.json1
-rw-r--r--src/Wallabag/ApiBundle/Controller/WallabagRestController.php72
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php5
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php100
-rw-r--r--src/Wallabag/CoreBundle/Controller/ExportController.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/TagController.php44
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php5
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php7
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php42
-rw-r--r--src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php34
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntryRepository.php29
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml6
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.da.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.de.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.es.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml24
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.it.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml16
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml10
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/_title.html.twig15
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig12
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig44
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Static/quickstart.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig6
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig19
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig22
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig5
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/share.html.twig40
-rw-r--r--src/Wallabag/ImportBundle/Controller/ReadabilityController.php65
-rw-r--r--src/Wallabag/ImportBundle/Import/ReadabilityImport.php179
-rw-r--r--src/Wallabag/ImportBundle/Resources/config/services.yml10
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig43
-rw-r--r--src/Wallabag/UserBundle/Controller/RegistrationController.php18
-rw-r--r--src/Wallabag/UserBundle/Controller/SecurityController.php21
-rw-r--r--src/Wallabag/UserBundle/DependencyInjection/Configuration.php8
-rw-r--r--src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php1
-rw-r--r--src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml11
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Security/login.html.twig6
-rw-r--r--tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php113
-rw-r--r--tests/Wallabag/CoreBundle/Command/InstallCommandTest.php2
-rw-r--r--tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php53
-rw-r--r--tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php15
-rw-r--r--tests/Wallabag/CoreBundle/Controller/TagControllerTest.php31
-rw-r--r--tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php2
-rw-r--r--tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php122
-rw-r--r--tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php150
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/readability-read.json25
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/readability.json25
-rw-r--r--var/SymfonyRequirements.php13
82 files changed, 1713 insertions, 89 deletions
diff --git a/.travis.yml b/.travis.yml
index 65e7e304..c343d5ae 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -62,6 +62,7 @@ matrix:
62 env: DB=sqlite ASSETS=build 62 env: DB=sqlite ASSETS=build
63 allow_failures: 63 allow_failures:
64 - php: hhvm-3.12 64 - php: hhvm-3.12
65 - php: 7.1
65 - php: nightly 66 - php: nightly
66 67
67# exclude v1 branches 68# exclude v1 branches
diff --git a/Gruntfile.js b/Gruntfile.js
index c7419549..8dc5b83b 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -45,6 +45,7 @@ module.exports = function (grunt) {
45 src: [ 45 src: [
46 '<%= appDir %>/themes/material/js/init.js', 46 '<%= appDir %>/themes/material/js/init.js',
47 '<%= appDir %>/themes/_global/js/restoreScroll.js', 47 '<%= appDir %>/themes/_global/js/restoreScroll.js',
48 'node_modules/jquery.tinydot/src/jquery.tinydot.js',
48 ], 49 ],
49 dest: '<%= buildDir %>/material.js', 50 dest: '<%= buildDir %>/material.js',
50 }, 51 },
diff --git a/app/DoctrineMigrations/Version20160410190541.php b/app/DoctrineMigrations/Version20160410190541.php
new file mode 100644
index 00000000..4014857b
--- /dev/null
+++ b/app/DoctrineMigrations/Version20160410190541.php
@@ -0,0 +1,46 @@
1<?php
2
3namespace Application\Migrations;
4
5use Doctrine\DBAL\Migrations\AbstractMigration;
6use Doctrine\DBAL\Schema\Schema;
7use Symfony\Component\DependencyInjection\ContainerAwareInterface;
8use Symfony\Component\DependencyInjection\ContainerInterface;
9
10class Version20160410190541 extends AbstractMigration implements ContainerAwareInterface
11{
12 /**
13 * @var ContainerInterface
14 */
15 private $container;
16
17 public function setContainer(ContainerInterface $container = null)
18 {
19 $this->container = $container;
20 }
21
22 private function getTable($tableName)
23 {
24 return $this->container->getParameter('database_table_prefix') . $tableName;
25 }
26
27 /**
28 * @param Schema $schema
29 */
30 public function up(Schema $schema)
31 {
32 $this->addSql('ALTER TABLE `'.$this->getTable('entry').'` ADD `uuid` LONGTEXT DEFAULT NULL');
33 $this->addSql("INSERT INTO `".$this->getTable('craue_config_setting')."` (`name`, `value`, `section`) VALUES ('share_public', '1', 'entry')");
34 }
35
36 /**
37 * @param Schema $schema
38 */
39 public function down(Schema $schema)
40 {
41 $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'sqlite', 'This down migration can\'t be executed on SQLite databases, because SQLite don\'t support DROP COLUMN.');
42
43 $this->addSql('ALTER TABLE `'.$this->getTable('entry').'` DROP `uuid`');
44 $this->addSql("DELETE FROM `".$this->getTable('craue_config_setting')."` WHERE `name` = 'share_public'");
45 }
46}
diff --git a/app/DoctrineMigrations/Version20160812120952.php b/app/DoctrineMigrations/Version20160812120952.php
index 58f070c7..9adfdc8b 100644
--- a/app/DoctrineMigrations/Version20160812120952.php
+++ b/app/DoctrineMigrations/Version20160812120952.php
@@ -4,15 +4,32 @@ namespace Application\Migrations;
4 4
5use Doctrine\DBAL\Migrations\AbstractMigration; 5use Doctrine\DBAL\Migrations\AbstractMigration;
6use Doctrine\DBAL\Schema\Schema; 6use Doctrine\DBAL\Schema\Schema;
7use Symfony\Component\DependencyInjection\ContainerAwareInterface;
8use Symfony\Component\DependencyInjection\ContainerInterface;
7 9
8class Version20160812120952 extends AbstractMigration 10class Version20160812120952 extends AbstractMigration implements ContainerAwareInterface
9{ 11{
10 /** 12 /**
13 * @var ContainerInterface
14 */
15 private $container;
16
17 public function setContainer(ContainerInterface $container = null)
18 {
19 $this->container = $container;
20 }
21
22 private function getTable($tableName)
23 {
24 return $this->container->getParameter('database_table_prefix') . $tableName;
25 }
26
27 /**
11 * @param Schema $schema 28 * @param Schema $schema
12 */ 29 */
13 public function up(Schema $schema) 30 public function up(Schema $schema)
14 { 31 {
15 $this->addSql('ALTER TABLE wallabag_oauth2_clients ADD name CLOB DEFAULT NULL COLLATE BINARY'); 32 $this->addSql('ALTER TABLE '.$this->getTable('oauth2_clients').' ADD name longtext COLLATE \'utf8_unicode_ci\' DEFAULT NULL');
16 } 33 }
17 34
18 /** 35 /**
@@ -21,7 +38,7 @@ class Version20160812120952 extends AbstractMigration
21 public function down(Schema $schema) 38 public function down(Schema $schema)
22 { 39 {
23 $this->abortIf($this->connection->getDatabasePlatform()->getName() == 'sqlite', 'Migration can only be executed safely on \'mysql\' or \'postgresql\'.'); 40 $this->abortIf($this->connection->getDatabasePlatform()->getName() == 'sqlite', 'Migration can only be executed safely on \'mysql\' or \'postgresql\'.');
24 $this->addSql('ALTER TABLE wallabag_oauth2_clients DROP COLUMN name; 41
25'); 42 $this->addSql('ALTER TABLE '.$this->getTable('oauth2_clients').' DROP COLUMN name');
26 } 43 }
27} 44}
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml
index c46fdb14..3478d638 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID for din side hos Piwik
27piwik_enabled: Aktiver Piwik 27piwik_enabled: Aktiver Piwik
28demo_mode_enabled: "Aktiver demo-indstilling? (anvendes kun til wallabags offentlige demo)" 28demo_mode_enabled: "Aktiver demo-indstilling? (anvendes kun til wallabags offentlige demo)"
29demo_mode_username: "Demobruger" 29demo_mode_username: "Demobruger"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml
index fa2093b5..f655a27f 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID deiner Webseite in Piwik
27piwik_enabled: Piwik aktivieren 27piwik_enabled: Piwik aktivieren
28demo_mode_enabled: "Test-Modus aktivieren? (nur für die öffentliche wallabag-Demo genutzt)" 28demo_mode_enabled: "Test-Modus aktivieren? (nur für die öffentliche wallabag-Demo genutzt)"
29demo_mode_username: "Test-Benutzer" 29demo_mode_username: "Test-Benutzer"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml
index b627376e..48d0ec4b 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID of your website in Piwik
27piwik_enabled: Enable Piwik 27piwik_enabled: Enable Piwik
28demo_mode_enabled: "Enable demo mode ? (only used for the wallabag public demo)" 28demo_mode_enabled: "Enable demo mode ? (only used for the wallabag public demo)"
29demo_mode_username: "Demo user" 29demo_mode_username: "Demo user"
30share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml
index af1657e4..7aac9adf 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID de tu website de Piwik
27piwik_enabled: Activar Piwik 27piwik_enabled: Activar Piwik
28demo_mode_enabled: "Activar modo demo (sólo usado para la demo de wallabag)" 28demo_mode_enabled: "Activar modo demo (sólo usado para la demo de wallabag)"
29demo_mode_username: "Nombre de usuario demo" 29demo_mode_username: "Nombre de usuario demo"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml
index 7cb4e833..613cf86d 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml
@@ -22,3 +22,9 @@ export: "برون‌سپاری"
22import: "درون‌ریزی" 22import: "درون‌ریزی"
23misc: "غیره" 23misc: "غیره"
24modify_settings: "اعمال" 24modify_settings: "اعمال"
25# piwik_host: Host of your website in Piwik
26# piwik_site_id: ID of your website in Piwik
27# piwik_enabled: Enable Piwik
28# demo_mode_enabled: "Enable demo mode ? (only used for the wallabag public demo)"
29# demo_mode_username: "Demo user"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml
index 084eb6df..f21f2439 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID de votre site dans Piwik
27piwik_enabled: Activer Piwik 27piwik_enabled: Activer Piwik
28demo_mode_enabled: "Activer le mode démo ? (utiliser uniquement pour la démo publique de wallabag)" 28demo_mode_enabled: "Activer le mode démo ? (utiliser uniquement pour la démo publique de wallabag)"
29demo_mode_username: "Utilisateur de la démo" 29demo_mode_username: "Utilisateur de la démo"
30share_public: Autoriser une URL publique pour les articles
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml
index e4417139..1202edd5 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID del tuo sito in Piwik
27piwik_enabled: Abilita Piwik 27piwik_enabled: Abilita Piwik
28demo_mode_enabled: "Abilita modalità demo ? (usato solo per la demo pubblica di wallabag)" 28demo_mode_enabled: "Abilita modalità demo ? (usato solo per la demo pubblica di wallabag)"
29demo_mode_username: "Utente Demo" 29demo_mode_username: "Utente Demo"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml
index 67880b8b..dd91ee49 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml
@@ -27,3 +27,4 @@ piwik_site_id: ID de vòstre site dins Piwik
27piwik_enabled: Activar Piwik 27piwik_enabled: Activar Piwik
28demo_mode_enabled: "Activar lo mode demostracion ? (utilizar solament per la demostracion publica de wallabag)" 28demo_mode_enabled: "Activar lo mode demostracion ? (utilizar solament per la demostracion publica de wallabag)"
29demo_mode_username: "Utilizaire de la demostracion" 29demo_mode_username: "Utilizaire de la demostracion"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml
index 87ca5060..93b36c8f 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml
@@ -22,3 +22,9 @@ export: "eksport"
22import: "import" 22import: "import"
23misc: "różne" 23misc: "różne"
24modify_settings: "zatwierdz" 24modify_settings: "zatwierdz"
25# piwik_host: Host of your website in Piwik
26# piwik_site_id: ID of your website in Piwik
27# piwik_enabled: Enable Piwik
28# demo_mode_enabled: "Enable demo mode ? (only used for the wallabag public demo)"
29# demo_mode_username: "Demo user"
30# share_public: Allow public url for entries
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml
index f5ff8c6a..326c9f90 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml
@@ -22,3 +22,9 @@ export: "exportă"
22import: "importă" 22import: "importă"
23misc: "diverse" 23misc: "diverse"
24modify_settings: "aplică" 24modify_settings: "aplică"
25# piwik_host: Host of your website in Piwik
26# piwik_site_id: ID of your website in Piwik
27# piwik_enabled: Enable Piwik
28# demo_mode_enabled: "Enable demo mode ? (only used for the wallabag public demo)"
29# demo_mode_username: "Demo user"
30# share_public: Allow public url for entries
diff --git a/app/Resources/static/themes/baggy/css/print.css b/app/Resources/static/themes/baggy/css/print.css
index 6f187ff5..f7f6a8ad 100755
--- a/app/Resources/static/themes/baggy/css/print.css
+++ b/app/Resources/static/themes/baggy/css/print.css
@@ -26,7 +26,9 @@
26 div.tools, 26 div.tools,
27 header div, 27 header div,
28 .messages, 28 .messages,
29 .entrie + .results { 29 .entrie + .results,
30 #article .mbm a,
31 #article-informations {
30 display: none !important; 32 display: none !important;
31 } 33 }
32 34
diff --git a/app/Resources/static/themes/material/css/main.css b/app/Resources/static/themes/material/css/main.css
index 99892401..f4230734 100755
--- a/app/Resources/static/themes/material/css/main.css
+++ b/app/Resources/static/themes/material/css/main.css
@@ -91,6 +91,7 @@ body {
91 91
92body.login main { 92body.login main {
93 padding: 0; 93 padding: 0;
94 min-height: 100vh;
94} 95}
95 96
96.border-bottom { 97.border-bottom {
@@ -256,6 +257,10 @@ nav input {
256 display: none; 257 display: none;
257} 258}
258 259
260.input-field.nav-panel-add, .input-field.nav-panel-add form {
261 height: 100%;
262}
263
259/* ========================================================================== 264/* ==========================================================================
260 2 = Side-nav 265 2 = Side-nav
261 ========================================================================== */ 266 ========================================================================== */
@@ -346,6 +351,12 @@ main ul.row {
346 351
347.card .card-content .card-title { 352.card .card-content .card-title {
348 line-height: 32px; 353 line-height: 32px;
354 max-height: 64px;
355 display: block;
356}
357
358.card .card-content i.right, .card .card-reveal i.right {
359 margin-left: 0;
349} 360}
350 361
351.card .card-entry-labels { 362.card .card-entry-labels {
@@ -634,6 +645,10 @@ main ul.row {
634 content: "\eae6"; 645 content: "\eae6";
635} 646}
636 647
648.icon-link::before {
649 content: "\e9cb";
650}
651
637footer [class^="icon-"], 652footer [class^="icon-"],
638footer [class*=" icon-"] { 653footer [class*=" icon-"] {
639 font-size: 2em; 654 font-size: 2em;
@@ -660,3 +675,7 @@ div.settings div.input-field ul {
660div.settings div.file-field div { 675div.settings div.file-field div {
661 margin-top: inherit; 676 margin-top: inherit;
662} 677}
678
679.input-field label.active {
680 font-size: 1rem;
681}
diff --git a/app/Resources/static/themes/material/css/print.css b/app/Resources/static/themes/material/css/print.css
index a16be71e..1eb96735 100755
--- a/app/Resources/static/themes/material/css/print.css
+++ b/app/Resources/static/themes/material/css/print.css
@@ -26,10 +26,23 @@
26 div.tools, 26 div.tools,
27 header div, 27 header div,
28 .messages, 28 .messages,
29 .entry + .results { 29 .entry + .results,
30 #slide-out,
31 .progress, .hide-on-large-only,
32 #article > aside,
33 #article .mbm a
34 {
30 display: none !important; 35 display: none !important;
31 } 36 }
32 37
38 main {
39 padding-left: 0 !important;
40 }
41
42 #article {
43 margin: inherit !important;
44 }
45
33 article { 46 article {
34 border: none !important; 47 border: none !important;
35 } 48 }
diff --git a/app/config/config.yml b/app/config/config.yml
index eb53fc5d..31bd8a8c 100644
--- a/app/config/config.yml
+++ b/app/config/config.yml
@@ -51,6 +51,9 @@ wallabag_core:
51 reading_speed: 1 51 reading_speed: 1
52 cache_lifetime: 10 52 cache_lifetime: 10
53 53
54wallabag_user:
55 registration_enabled: "%fosuser_registration%"
56
54wallabag_import: 57wallabag_import:
55 allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain'] 58 allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain']
56 resource_dir: "%kernel.root_dir%/../web/uploads/import" 59 resource_dir: "%kernel.root_dir%/../web/uploads/import"
diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist
index d45839f4..d092e139 100644
--- a/app/config/parameters.yml.dist
+++ b/app/config/parameters.yml.dist
@@ -34,6 +34,7 @@ parameters:
34 twofactor_sender: no-reply@wallabag.org 34 twofactor_sender: no-reply@wallabag.org
35 35
36 # fosuser stuff 36 # fosuser stuff
37 fosuser_registration: true
37 fosuser_confirmation: true 38 fosuser_confirmation: true
38 39
39 from_email: no-reply@wallabag.org 40 from_email: no-reply@wallabag.org
diff --git a/app/config/security.yml b/app/config/security.yml
index e24e03df..1f30e58b 100644
--- a/app/config/security.yml
+++ b/app/config/security.yml
@@ -60,6 +60,7 @@ security:
60 - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } 60 - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
61 - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } 61 - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
62 - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } 62 - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
63 - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY }
63 - { path: ^/settings, roles: ROLE_SUPER_ADMIN } 64 - { path: ^/settings, roles: ROLE_SUPER_ADMIN }
64 - { path: ^/annotations, roles: ROLE_USER } 65 - { path: ^/annotations, roles: ROLE_USER }
65 - { path: ^/, roles: ROLE_USER } 66 - { path: ^/, roles: ROLE_USER }
diff --git a/docs/de/conf.py b/docs/de/conf.py
new file mode 100644
index 00000000..8f2d130d
--- /dev/null
+++ b/docs/de/conf.py
@@ -0,0 +1,55 @@
1# -*- coding: utf-8 -*-
2#
3# wallabag documentation build configuration file, created by
4# sphinx-quickstart on Fri Oct 16 06:47:23 2015.
5
6import sys
7import os
8
9extensions = []
10templates_path = ['_templates']
11source_suffix = '.rst'
12master_doc = 'index'
13project = u'wallabag-fr'
14copyright = u'2013-2016, Nicolas Lœuillet - MIT Licence'
15version = '2.0.0'
16release = version
17exclude_patterns = ['_build']
18pygments_style = 'sphinx'
19html_theme = 'default'
20html_static_path = ['_static']
21htmlhelp_basename = 'wallabagdedoc'
22
23latex_elements = {
24}
25
26latex_documents = [
27 ('index', 'wallabag-de.tex', u'wallabag Documentation',
28 u'Nicolas Lœuillet', 'manual'),
29]
30
31man_pages = [
32 ('index', 'wallabagde', u'wallabag Documentation',
33 [u'Nicolas Lœuillet'], 1)
34]
35
36texinfo_documents = [
37 ('index', 'wallabag', u'wallabag Documentation',
38 u'Nicolas Lœuillet', 'wallabag', 'wallabag is an opensource read-it-later.',
39 'Miscellaneous'),
40]
41
42##### Guzzle sphinx theme
43
44import guzzle_sphinx_theme
45html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator'
46html_theme_path = guzzle_sphinx_theme.html_theme_path()
47html_theme = 'guzzle_sphinx_theme'
48
49# Custom sidebar templates, maps document names to template names.
50html_sidebars = {
51 '**': ['logo-text.html', 'globaltoc.html', 'searchbox.html']
52}
53
54# Register the theme as an extension to generate a sitemap.xml
55extensions.append("guzzle_sphinx_theme")
diff --git a/docs/de/requirements.txt b/docs/de/requirements.txt
new file mode 100644
index 00000000..06fc8973
--- /dev/null
+++ b/docs/de/requirements.txt
@@ -0,0 +1,2 @@
1Sphinx>=1.3.0,<1.4.0
2guzzle_sphinx_theme>=0.7.0,<0.8.0
diff --git a/docs/de/user/errors_during_fetching.rst b/docs/de/user/errors_during_fetching.rst
index b8e3e999..29621559 100644
--- a/docs/de/user/errors_during_fetching.rst
+++ b/docs/de/user/errors_during_fetching.rst
@@ -12,7 +12,7 @@ Das kann verschiedene Ursachen haben:
12Wie kann ich helfen das zu beheben? 12Wie kann ich helfen das zu beheben?
13----------------------------------- 13-----------------------------------
14 14
15- `indem du uns eine Mail mit der URL des Artikels sendest <mailto:hello\@wallabag.org>`_ 15- `indem du uns eine Mail mit der URL des Artikels sendest <mailto:hello@wallabag.org>`_
16- indem du versuchst das Laden des Artikels durch Erstellen einer Datei für den Artikel 16- indem du versuchst das Laden des Artikels durch Erstellen einer Datei für den Artikel
17 selbst zu beheben 17 selbst zu beheben
18 Du kannst `dieses Tool <http://siteconfig.fivefilters.org/>`__ nutzen. 18 Du kannst `dieses Tool <http://siteconfig.fivefilters.org/>`__ nutzen.
diff --git a/docs/en/user/errors_during_fetching.rst b/docs/en/user/errors_during_fetching.rst
index da6ee745..68892750 100644
--- a/docs/en/user/errors_during_fetching.rst
+++ b/docs/en/user/errors_during_fetching.rst
@@ -12,7 +12,7 @@ There may be several reasons:
12How can I help to fix that? 12How can I help to fix that?
13--------------------------- 13---------------------------
14 14
15- `by sending us an email with the article's URL <mailto:hello\@wallabag.org>`_ 15- `by sending us an email with the article's URL <mailto:hello@wallabag.org>`_
16- by trying to fix this article by yourself :) by creating a file for the article. 16- by trying to fix this article by yourself :) by creating a file for the article.
17 You can use `this tool <http://siteconfig.fivefilters.org/>`__. 17 You can use `this tool <http://siteconfig.fivefilters.org/>`__.
18 18
diff --git a/docs/en/user/import.rst b/docs/en/user/import.rst
index 63210484..e6c37d72 100644
--- a/docs/en/user/import.rst
+++ b/docs/en/user/import.rst
@@ -30,14 +30,25 @@ You need to authorize wallabag to interact with your Pocket account.
30Your data will be imported. Data import can be a demanding process for your server 30Your data will be imported. Data import can be a demanding process for your server
31(we need to work on this import to improve it). 31(we need to work on this import to improve it).
32 32
33From Instapaper
34---------------
35
36*Feature not yet implemented in wallabag v2.*
37
38From Readability 33From Readability
39---------------- 34----------------
40 35
36Export your Readability data
37~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38
39On the tools (`https://www.readability.com/tools/<https://www.readability.com/tools/>`_) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).
40
41Import your data into wallabag 2.x
42~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43
44Click on ``Import`` link in the menu, on ``Import contents`` in Readability section
45and then select your json file and upload it.
46
47Your data will be imported. Data import can be a demanding process for your server (we need to work on this import to improve it).
48
49From Instapaper
50---------------
51
41*Feature not yet implemented in wallabag v2.* 52*Feature not yet implemented in wallabag v2.*
42 53
43From HTML or JSON file 54From HTML or JSON file
diff --git a/docs/fr/user/errors_during_fetching.rst b/docs/fr/user/errors_during_fetching.rst
index 0f26fbc8..74290bef 100644
--- a/docs/fr/user/errors_during_fetching.rst
+++ b/docs/fr/user/errors_during_fetching.rst
@@ -12,7 +12,7 @@ Il peut y avoir plusieurs raisons :
12Comment puis-je aider pour réparer ça ? 12Comment puis-je aider pour réparer ça ?
13--------------------------------------- 13---------------------------------------
14 14
15- `en nous envoyant un email avec l'URL de l'article <mailto:hello\@wallabag.org>`_ 15- `en nous envoyant un email avec l'URL de l'article <mailto:hello@wallabag.org>`_
16- en essayant de réparer cet article par vous-même :) en créant un fichier pour l'article. 16- en essayant de réparer cet article par vous-même :) en créant un fichier pour l'article.
17 Vous pouvez utiliser `cet outil <http://siteconfig.fivefilters.org/>`__. 17 Vous pouvez utiliser `cet outil <http://siteconfig.fivefilters.org/>`__.
18 18
diff --git a/docs/fr/user/import.rst b/docs/fr/user/import.rst
index e6c2fa02..99ac602b 100644
--- a/docs/fr/user/import.rst
+++ b/docs/fr/user/import.rst
@@ -30,15 +30,27 @@ Vous devez autoriser wallabag à se connecter à votre compte Pocket.
30Vos données vont être importées. L'import de données est une action qui peut être couteuse 30Vos données vont être importées. L'import de données est une action qui peut être couteuse
31pour votre serveur (nous devons encore travailler pour améliorer cet import). 31pour votre serveur (nous devons encore travailler pour améliorer cet import).
32 32
33Depuis Readability
34------------------
35
36Exportez vos données de Readability
37~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38
39Sur la page des outils (`https://www.readability.com/tools/<https://www.readability.com/tools/>`_), cliquez sur "Export your data" dans la section "Data Export". Vous allez recevoir un email avec un lien pour télécharger le json.
40
41Importez vos données dans wallabag 2.x
42~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43
44Cliquez sur le lien ``Importer`` dans le menu, sur ``Importer les contenus`` dans
45la section Readability et ensuite sélectionnez votre fichier json pour l'uploader.
46
47Vos données vont être importées. L'import de données est une action qui peut être couteuse pour votre serveur (nous devons encore travailler pour améliorer cet import).
48
33Depuis Instapaper 49Depuis Instapaper
34----------------- 50-----------------
35 51
36*Fonctionnalité pas encore implémentée dans wallabag v2.* 52*Fonctionnalité pas encore implémentée dans wallabag v2.*
37 53
38Depuis Readability
39------------------
40
41*Fonctionnalité pas encore implémentée dans wallabag v2.*
42 54
43Depuis un fichier HTML ou JSON 55Depuis un fichier HTML ou JSON
44------------------------------ 56------------------------------
diff --git a/package.json b/package.json
index 3ed7a49f..39a10e9c 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
28 "jquery": "^2.2.1", 28 "jquery": "^2.2.1",
29 "jquery-ui": "^1.10.5", 29 "jquery-ui": "^1.10.5",
30 "jquery.cookie": "^1.4.1", 30 "jquery.cookie": "^1.4.1",
31 "jquery.tinydot": "^0.2.1",
31 "load-grunt-tasks": "^3.4.1", 32 "load-grunt-tasks": "^3.4.1",
32 "materialize-css": "0.97.5", 33 "materialize-css": "0.97.5",
33 "npm": "^3.8.3", 34 "npm": "^3.8.3",
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
index 03eb9b08..869fdc56 100644
--- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
@@ -334,6 +334,77 @@ class WallabagRestController extends FOSRestController
334 * 334 *
335 * @ApiDoc( 335 * @ApiDoc(
336 * requirements={ 336 * requirements={
337 * {"name"="tag", "dataType"="string", "required"=true, "requirement"="\w+", "description"="Tag as a string"}
338 * }
339 * )
340 *
341 * @return Response
342 */
343 public function deleteTagLabelAction(Request $request)
344 {
345 $this->validateAuthentication();
346 $label = $request->request->get('tag', '');
347
348 $tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label);
349
350 if (empty($tag)) {
351 throw $this->createNotFoundException('Tag not found');
352 }
353
354 $this->getDoctrine()
355 ->getRepository('WallabagCoreBundle:Entry')
356 ->removeTag($this->getUser()->getId(), $tag);
357
358 $json = $this->get('serializer')->serialize($tag, 'json');
359
360 return $this->renderJsonResponse($json);
361 }
362
363 /**
364 * Permanently remove some tags from **every** entry.
365 *
366 * @ApiDoc(
367 * requirements={
368 * {"name"="tags", "dataType"="string", "required"=true, "format"="tag1,tag2", "description"="Tags as strings (comma splitted)"}
369 * }
370 * )
371 *
372 * @return Response
373 */
374 public function deleteTagsLabelAction(Request $request)
375 {
376 $this->validateAuthentication();
377
378 $tagsLabels = $request->request->get('tags', '');
379
380 $tags = [];
381
382 foreach (explode(',', $tagsLabels) as $tagLabel) {
383 $tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel);
384
385 if (!empty($tagEntity)) {
386 $tags[] = $tagEntity;
387 }
388 }
389
390 if (empty($tags)) {
391 throw $this->createNotFoundException('Tags not found');
392 }
393
394 $this->getDoctrine()
395 ->getRepository('WallabagCoreBundle:Entry')
396 ->removeTags($this->getUser()->getId(), $tags);
397
398 $json = $this->get('serializer')->serialize($tags, 'json');
399
400 return $this->renderJsonResponse($json);
401 }
402
403 /**
404 * Permanently remove one tag from **every** entry.
405 *
406 * @ApiDoc(
407 * requirements={
337 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"} 408 * {"name"="tag", "dataType"="integer", "requirement"="\w+", "description"="The tag"}
338 * } 409 * }
339 * ) 410 * )
@@ -352,6 +423,7 @@ class WallabagRestController extends FOSRestController
352 423
353 return $this->renderJsonResponse($json); 424 return $this->renderJsonResponse($json);
354 } 425 }
426
355 /** 427 /**
356 * Retrieve version number. 428 * Retrieve version number.
357 * 429 *
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index e134ced5..143def4f 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -242,6 +242,11 @@ class InstallCommand extends ContainerAwareCommand
242 242
243 $settings = [ 243 $settings = [
244 [ 244 [
245 'name' => 'share_public',
246 'value' => '1',
247 'section' => 'entry',
248 ],
249 [
245 'name' => 'carrot', 250 'name' => 'carrot',
246 'value' => '1', 251 'value' => '1',
247 'section' => 'entry', 252 'section' => 'entry',
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index ccdf9406..624576b5 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -4,7 +4,6 @@ namespace Wallabag\CoreBundle\Controller;
4 4
5use Pagerfanta\Adapter\DoctrineORMAdapter; 5use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Pagerfanta\Pagerfanta;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 7use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller; 8use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
@@ -13,6 +12,7 @@ use Wallabag\CoreBundle\Entity\Entry;
13use Wallabag\CoreBundle\Form\Type\EntryFilterType; 12use Wallabag\CoreBundle\Form\Type\EntryFilterType;
14use Wallabag\CoreBundle\Form\Type\EditEntryType; 13use Wallabag\CoreBundle\Form\Type\EditEntryType;
15use Wallabag\CoreBundle\Form\Type\NewEntryType; 14use Wallabag\CoreBundle\Form\Type\NewEntryType;
15use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
16 16
17class EntryController extends Controller 17class EntryController extends Controller
18{ 18{
@@ -226,6 +226,10 @@ class EntryController extends Controller
226 $repository = $this->get('wallabag_core.entry_repository'); 226 $repository = $this->get('wallabag_core.entry_repository');
227 227
228 switch ($type) { 228 switch ($type) {
229 case 'untagged':
230 $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId());
231
232 break;
229 case 'starred': 233 case 'starred':
230 $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); 234 $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId());
231 break; 235 break;
@@ -257,9 +261,10 @@ class EntryController extends Controller
257 } 261 }
258 262
259 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery()); 263 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery());
260 $entries = new Pagerfanta($pagerAdapter);
261 264
262 $entries->setMaxPerPage($this->getUser()->getConfig()->getItemsPerPage()); 265 $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')
266 ->prepare($pagerAdapter, $page);
267
263 try { 268 try {
264 $entries->setCurrentPage($page); 269 $entries->setCurrentPage($page);
265 } catch (OutOfRangeCurrentPageException $e) { 270 } catch (OutOfRangeCurrentPageException $e) {
@@ -434,7 +439,7 @@ class EntryController extends Controller
434 */ 439 */
435 private function checkUserAction(Entry $entry) 440 private function checkUserAction(Entry $entry)
436 { 441 {
437 if ($this->getUser()->getId() != $entry->getUser()->getId()) { 442 if (null === $this->getUser() || $this->getUser()->getId() != $entry->getUser()->getId()) {
438 throw $this->createAccessDeniedException('You can not access this entry.'); 443 throw $this->createAccessDeniedException('You can not access this entry.');
439 } 444 }
440 } 445 }
@@ -450,4 +455,91 @@ class EntryController extends Controller
450 { 455 {
451 return $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($entry->getUrl(), $this->getUser()->getId()); 456 return $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($entry->getUrl(), $this->getUser()->getId());
452 } 457 }
458
459 /**
460 * Get public URL for entry (and generate it if necessary).
461 *
462 * @param Entry $entry
463 *
464 * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share")
465 *
466 * @return \Symfony\Component\HttpFoundation\Response
467 */
468 public function shareAction(Entry $entry)
469 {
470 $this->checkUserAction($entry);
471
472 if (null === $entry->getUuid()) {
473 $entry->generateUuid();
474
475 $em = $this->getDoctrine()->getManager();
476 $em->persist($entry);
477 $em->flush();
478 }
479
480 return $this->redirect($this->generateUrl('share_entry', [
481 'uuid' => $entry->getUuid(),
482 ]));
483 }
484
485 /**
486 * Disable public sharing for an entry.
487 *
488 * @param Entry $entry
489 *
490 * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share")
491 *
492 * @return \Symfony\Component\HttpFoundation\Response
493 */
494 public function deleteShareAction(Entry $entry)
495 {
496 $this->checkUserAction($entry);
497
498 $entry->cleanUuid();
499
500 $em = $this->getDoctrine()->getManager();
501 $em->persist($entry);
502 $em->flush();
503
504 return $this->redirect($this->generateUrl('view', [
505 'id' => $entry->getId(),
506 ]));
507 }
508
509 /**
510 * Ability to view a content publicly.
511 *
512 * @param Entry $entry
513 *
514 * @Route("/share/{uuid}", requirements={"uuid" = ".+"}, name="share_entry")
515 * @Cache(maxage="25200", smaxage="25200", public=true)
516 *
517 * @return \Symfony\Component\HttpFoundation\Response
518 */
519 public function shareEntryAction(Entry $entry)
520 {
521 if (!$this->get('craue_config')->get('share_public')) {
522 throw $this->createAccessDeniedException('Sharing an entry is disabled for this user.');
523 }
524
525 return $this->render(
526 '@WallabagCore/themes/share.html.twig',
527 ['entry' => $entry]
528 );
529 }
530
531 /**
532 * Shows untagged articles for current user.
533 *
534 * @param Request $request
535 * @param int $page
536 *
537 * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"})
538 *
539 * @return \Symfony\Component\HttpFoundation\Response
540 */
541 public function showUntaggedEntriesAction(Request $request, $page)
542 {
543 return $this->showEntries('untagged', $request, $page);
544 }
453} 545}
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php
index 944c755d..6191d5d7 100644
--- a/src/Wallabag/CoreBundle/Controller/ExportController.php
+++ b/src/Wallabag/CoreBundle/Controller/ExportController.php
@@ -46,7 +46,7 @@ class ExportController extends Controller
46 * 46 *
47 * @Route("/export/{category}.{format}", name="export_entries", requirements={ 47 * @Route("/export/{category}.{format}", name="export_entries", requirements={
48 * "format": "epub|mobi|pdf|json|xml|txt|csv", 48 * "format": "epub|mobi|pdf|json|xml|txt|csv",
49 * "category": "all|unread|starred|archive" 49 * "category": "all|unread|starred|archive|tag_entries|untagged"
50 * }) 50 * })
51 * 51 *
52 * @return \Symfony\Component\HttpFoundation\Response 52 * @return \Symfony\Component\HttpFoundation\Response
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php
index 8645fb44..1cbc413d 100644
--- a/src/Wallabag/CoreBundle/Controller/TagController.php
+++ b/src/Wallabag/CoreBundle/Controller/TagController.php
@@ -2,12 +2,15 @@
2 2
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Pagerfanta\Adapter\ArrayAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 7use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 8use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
8use Wallabag\CoreBundle\Entity\Entry; 10use Wallabag\CoreBundle\Entity\Entry;
9use Wallabag\CoreBundle\Entity\Tag; 11use Wallabag\CoreBundle\Entity\Tag;
10use Wallabag\CoreBundle\Form\Type\NewTagType; 12use Wallabag\CoreBundle\Form\Type\NewTagType;
13use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
11 14
12class TagController extends Controller 15class TagController extends Controller
13{ 16{
@@ -90,4 +93,45 @@ class TagController extends Controller
90 ] 93 ]
91 ); 94 );
92 } 95 }
96
97 /**
98 * @param Tag $tag
99 * @param int $page
100 *
101 * @Route("/tag/list/{slug}/{page}", name="tag_entries", defaults={"page" = "1"})
102 * @ParamConverter("tag", options={"mapping": {"slug": "slug"}})
103 *
104 * @return \Symfony\Component\HttpFoundation\Response
105 */
106 public function showEntriesForTagAction(Tag $tag, $page, Request $request)
107 {
108 $entriesByTag = $this->getDoctrine()
109 ->getRepository('WallabagCoreBundle:Entry')
110 ->findAllByTagId($this->getUser()->getId(), $tag->getId());
111
112 $pagerAdapter = new ArrayAdapter($entriesByTag);
113
114 $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')
115 ->prepare($pagerAdapter, $page);
116
117 try {
118 $entries->setCurrentPage($page);
119 } catch (OutOfRangeCurrentPageException $e) {
120 if ($page > 1) {
121 return $this->redirect($this->generateUrl($request->get('_route'), [
122 'slug' => $tag->getSlug(),
123 'page' => $entries->getNbPages(),
124 ]), 302);
125 }
126 }
127
128 return $this->render(
129 'WallabagCoreBundle:Entry:entries.html.twig',
130 [
131 'form' => null,
132 'entries' => $entries,
133 'currentPage' => $page,
134 ]
135 );
136 }
93} 137}
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
index 09058796..b4309304 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
@@ -16,6 +16,11 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
16 { 16 {
17 $settings = [ 17 $settings = [
18 [ 18 [
19 'name' => 'share_public',
20 'value' => '1',
21 'section' => 'entry',
22 ],
23 [
19 'name' => 'carrot', 24 'name' => 'carrot',
20 'value' => '1', 25 'value' => '1',
21 'section' => 'entry', 26 'section' => 'entry',
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
index 8553dced..09e99f36 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
@@ -28,6 +28,13 @@ class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
28 28
29 $this->addReference('bar-tag', $tag2); 29 $this->addReference('bar-tag', $tag2);
30 30
31 $tag3 = new Tag();
32 $tag3->setLabel('baz');
33
34 $manager->persist($tag3);
35
36 $this->addReference('baz-tag', $tag3);
37
31 $manager->flush(); 38 $manager->flush();
32 } 39 }
33 40
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index ceae78b0..4d7e001b 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -40,6 +40,15 @@ class Entry
40 /** 40 /**
41 * @var string 41 * @var string
42 * 42 *
43 * @ORM\Column(name="uuid", type="text", nullable=true)
44 *
45 * @Groups({"entries_for_user", "export_all"})
46 */
47 private $uuid;
48
49 /**
50 * @var string
51 *
43 * @ORM\Column(name="title", type="text", nullable=true) 52 * @ORM\Column(name="title", type="text", nullable=true)
44 * 53 *
45 * @Groups({"entries_for_user", "export_all"}) 54 * @Groups({"entries_for_user", "export_all"})
@@ -595,4 +604,37 @@ class Entry
595 { 604 {
596 return $this->language; 605 return $this->language;
597 } 606 }
607
608 /**
609 * @return string
610 */
611 public function getUuid()
612 {
613 return $this->uuid;
614 }
615
616 /**
617 * @param string $uuid
618 *
619 * @return Entry
620 */
621 public function setUuid($uuid)
622 {
623 $this->uuid = $uuid;
624
625 return $this;
626 }
627
628 public function generateUuid()
629 {
630 if (null === $this->uuid) {
631 // @see http://blog.kevingomez.fr/til/2015/07/26/why-is-uniqid-slow/ for true parameter
632 $this->uuid = uniqid('', true);
633 }
634 }
635
636 public function cleanUuid()
637 {
638 $this->uuid = null;
639 }
598} 640}
diff --git a/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
new file mode 100644
index 00000000..f9066bee
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Helper/PreparePagerForEntries.php
@@ -0,0 +1,34 @@
1<?php
2
3namespace Wallabag\CoreBundle\Helper;
4
5use Pagerfanta\Adapter\AdapterInterface;
6use Pagerfanta\Pagerfanta;
7use Symfony\Component\Routing\Router;
8use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
9
10class PreparePagerForEntries
11{
12 private $user;
13 private $router;
14
15 public function __construct(TokenStorage $token, Router $router)
16 {
17 $this->user = $token->getToken()->getUser();
18 $this->router = $router;
19 }
20
21 /**
22 * @param AdapterInterface $adapter
23 * @param int $page
24 *
25 * @return null|Pagerfanta
26 */
27 public function prepare(AdapterInterface $adapter, $page = 1)
28 {
29 $entries = new Pagerfanta($adapter);
30 $entries->setMaxPerPage($this->user->getConfig()->getItemsPerPage());
31
32 return $entries;
33 }
34}
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
index 4b205f6e..24d1a57a 100644
--- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
@@ -88,6 +88,22 @@ class EntryRepository extends EntityRepository
88 } 88 }
89 89
90 /** 90 /**
91 * Retrieves untagged entries for a user.
92 *
93 * @param int $userId
94 *
95 * @return QueryBuilder
96 */
97 public function getBuilderForUntaggedByUser($userId)
98 {
99 return $this
100 ->getBuilderByUser($userId)
101 ->leftJoin('e.tags', 't')
102 ->groupBy('e.id')
103 ->having('count(t.id) = 0');
104 }
105
106 /**
91 * Find Entries. 107 * Find Entries.
92 * 108 *
93 * @param int $userId 109 * @param int $userId
@@ -226,6 +242,19 @@ class EntryRepository extends EntityRepository
226 } 242 }
227 243
228 /** 244 /**
245 * Remove tags from all user entries.
246 *
247 * @param int $userId
248 * @param Array<Tag> $tags
249 */
250 public function removeTags($userId, $tags)
251 {
252 foreach ($tags as $tag) {
253 $this->removeTag($userId, $tag);
254 }
255 }
256
257 /**
229 * Find all entries that are attached to a give tag id. 258 * Find all entries that are attached to a give tag id.
230 * 259 *
231 * @param int $userId 260 * @param int $userId
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index b70d9b8c..1c1457e7 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -121,3 +121,9 @@ services:
121 class: Wallabag\CoreBundle\Helper\Redirect 121 class: Wallabag\CoreBundle\Helper\Redirect
122 arguments: 122 arguments:
123 - "@router" 123 - "@router"
124
125 wallabag_core.helper.prepare_pager_for_entries:
126 class: Wallabag\CoreBundle\Helper\PreparePagerForEntries
127 arguments:
128 - "@security.token_storage"
129 - "@router"
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
index c24475d2..073dee28 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
@@ -139,6 +139,8 @@ entry:
139 # starred: 'Starred entries' 139 # starred: 'Starred entries'
140 # archived: 'Archived entries' 140 # archived: 'Archived entries'
141 # filtered: 'Filtered entries' 141 # filtered: 'Filtered entries'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.' 145 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
144 reading_time: 'estimeret læsetid' 146 reading_time: 'estimeret læsetid'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Tliføj et tag' 188 add_a_tag: 'Tliføj et tag'
187 share_content: 'Deling' 189 share_content: 'Deling'
188 # share_email_label: 'Email' 190 # share_email_label: 'Email'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'Download' 193 download: 'Download'
190 # print: 'Print' 194 # print: 'Print'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 # pocket: 'Migrate from Pocket' 292 # pocket: 'Migrate from Pocket'
289 # wallabag_v1: 'Migrate from wallabag v1' 293 # wallabag_v1: 'Migrate from wallabag v1'
290 # wallabag_v2: 'Migrate from wallabag v2' 294 # wallabag_v2: 'Migrate from wallabag v2'
295 # readability: 'Migrate from Readability'
291 # developer: 296 # developer:
292 # title: 'Developers' 297 # title: 'Developers'
293 # create_application: 'Create your third application' 298 # create_application: 'Create your third application'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Tags' 314 page_title: 'Tags'
310 list: 315 list:
311 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' 316 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.'
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 # page_title: 'Import' 320 # page_title: 'Import'
@@ -336,6 +342,10 @@ import:
336 # wallabag_v2: 342 # wallabag_v2:
337 # page_title: 'Import > Wallabag v2' 343 # page_title: 'Import > Wallabag v2'
338 # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' 344 # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.'
345 # readability:
346 # page_title: 'Import > Readability'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 # page_title: 'Developer' 351 # page_title: 'Developer'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
index 384ec09a..4cfd240f 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'Favorisierte Einträge' 139 starred: 'Favorisierte Einträge'
140 archived: 'Archivierte Einträge' 140 archived: 'Archivierte Einträge'
141 filtered: 'Gefilterte Einträge' 141 filtered: 'Gefilterte Einträge'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: '{0} Es gibt keine Einträge.|{1} Es gibt einen Eintrag.|]1,Inf[ Es gibt %count% Einträge.' 145 number_on_the_page: '{0} Es gibt keine Einträge.|{1} Es gibt einen Eintrag.|]1,Inf[ Es gibt %count% Einträge.'
144 reading_time: 'geschätzte Lesezeit' 146 reading_time: 'geschätzte Lesezeit'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Tag hinzufügen' 188 add_a_tag: 'Tag hinzufügen'
187 share_content: 'Teilen' 189 share_content: 'Teilen'
188 share_email_label: 'E-Mail' 190 share_email_label: 'E-Mail'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'Herunterladen' 193 download: 'Herunterladen'
190 print: 'Drucken' 194 print: 'Drucken'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'von Pocket migrieren' 292 pocket: 'von Pocket migrieren'
289 wallabag_v1: 'von wallabag v1 migrieren' 293 wallabag_v1: 'von wallabag v1 migrieren'
290 wallabag_v2: 'von wallabag v2 migrieren' 294 wallabag_v2: 'von wallabag v2 migrieren'
295 readability: 'von Readability migrieren'
291 developer: 296 developer:
292 title: 'Entwickler' 297 title: 'Entwickler'
293 create_application: 'Erstelle eine Anwendung und nutze die wallabag API' 298 create_application: 'Erstelle eine Anwendung und nutze die wallabag API'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Tags' 314 page_title: 'Tags'
310 list: 315 list:
311 number_on_the_page: '{0} Es gibt keine Tags.|{1} Es gibt einen Tag.|]1,Inf[ Es gibt %count% Tags.' 316 number_on_the_page: '{0} Es gibt keine Tags.|{1} Es gibt einen Tag.|]1,Inf[ Es gibt %count% Tags.'
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 page_title: 'Importieren' 320 page_title: 'Importieren'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'Aus wallabag v2 importieren' 343 page_title: 'Aus wallabag v2 importieren'
338 description: 'Dieser Import wird all deine Artikel aus wallabag v2 importieren. Gehe auf "Alle Artikel" und dann, in der Exportieren-Seitenleiste auf "JSON". Dabei erhältst du eine "All articles.json"-Datei.' 344 description: 'Dieser Import wird all deine Artikel aus wallabag v2 importieren. Gehe auf "Alle Artikel" und dann, in der Exportieren-Seitenleiste auf "JSON". Dabei erhältst du eine "All articles.json"-Datei.'
345 readability:
346 page_title: 'Aus Readability importieren'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 page_title: 'Entwickler' 351 page_title: 'Entwickler'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index ea860564..42374b40 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'Starred entries' 139 starred: 'Starred entries'
140 archived: 'Archived entries' 140 archived: 'Archived entries'
141 filtered: 'Filtered entries' 141 filtered: 'Filtered entries'
142 filtered_tags: 'Filtered by tags'
143 untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: '{0} There are no entries.|{1} There is one entry.|]1,Inf[ There are %count% entries.' 145 number_on_the_page: '{0} There are no entries.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
144 reading_time: 'estimated reading time' 146 reading_time: 'estimated reading time'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Add a tag' 188 add_a_tag: 'Add a tag'
187 share_content: 'Share' 189 share_content: 'Share'
188 share_email_label: 'Email' 190 share_email_label: 'Email'
191 public_link: 'public link'
192 delete_public_link: 'delete public link'
189 download: 'Download' 193 download: 'Download'
190 print: 'Print' 194 print: 'Print'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'Migrate from Pocket' 292 pocket: 'Migrate from Pocket'
289 wallabag_v1: 'Migrate from wallabag v1' 293 wallabag_v1: 'Migrate from wallabag v1'
290 wallabag_v2: 'Migrate from wallabag v2' 294 wallabag_v2: 'Migrate from wallabag v2'
295 readability: 'Migrate from Readability'
291 developer: 296 developer:
292 title: 'Developers' 297 title: 'Developers'
293 create_application: 'Create your third application' 298 create_application: 'Create your third application'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Tags' 314 page_title: 'Tags'
310 list: 315 list:
311 number_on_the_page: '{0} There are no tags.|{1} There is one tag.|]1,Inf[ There are %count% tags.' 316 number_on_the_page: '{0} There are no tags.|{1} There is one tag.|]1,Inf[ There are %count% tags.'
317 see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 page_title: 'Import' 320 page_title: 'Import'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'Import > Wallabag v2' 343 page_title: 'Import > Wallabag v2'
338 description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' 344 description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.'
345 readability:
346 page_title: 'Import > Readability'
347 description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 page_title: 'Developer' 351 page_title: 'Developer'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
index f64e95d5..ee84cc62 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'Artículos favoritos' 139 starred: 'Artículos favoritos'
140 archived: 'Artículos archivados' 140 archived: 'Artículos archivados'
141 filtered: 'Artículos filtrados' 141 filtered: 'Artículos filtrados'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: '{0} No hay artículos.|{1} Hay un artículo.|]1,Inf[ Hay %count% artículos.' 145 number_on_the_page: '{0} No hay artículos.|{1} Hay un artículo.|]1,Inf[ Hay %count% artículos.'
144 reading_time: 'tiempo estimado de lectura' 146 reading_time: 'tiempo estimado de lectura'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Añadir una etiqueta' 188 add_a_tag: 'Añadir una etiqueta'
187 share_content: 'Compartir' 189 share_content: 'Compartir'
188 share_email_label: 'Dirección e-mail' 190 share_email_label: 'Dirección e-mail'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'Descargar' 193 download: 'Descargar'
190 print: 'Imprimir' 194 print: 'Imprimir'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'Migrar desde Pocket' 292 pocket: 'Migrar desde Pocket'
289 wallabag_v1: 'Migrar desde wallabag v1' 293 wallabag_v1: 'Migrar desde wallabag v1'
290 wallabag_v2: 'Migrar desde wallabag v2' 294 wallabag_v2: 'Migrar desde wallabag v2'
295 readability: 'Migrar desde Readability'
291 developer: 296 developer:
292 title: 'Promotores' 297 title: 'Promotores'
293 create_application: 'Cree su tercera aplicación' 298 create_application: 'Cree su tercera aplicación'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Etiquetas' 314 page_title: 'Etiquetas'
310 list: 315 list:
311 number_on_the_page: '{0} No hay ninguna etiqueta.|{1} Hay una etiqueta.|]1,Inf[ Hay %count% etiquetas.' 316 number_on_the_page: '{0} No hay ninguna etiqueta.|{1} Hay una etiqueta.|]1,Inf[ Hay %count% etiquetas.'
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 page_title: 'Importar' 320 page_title: 'Importar'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'Importar > Wallabag v2' 343 page_title: 'Importar > Wallabag v2'
338 description: 'Va a importar sus artículos de otra instancia de wallabag v2. Vaya a Todos los artículos, entonces, en la barra lateral, oprima en "JSON". Usted tendrá un fichero "All articles.json"' 344 description: 'Va a importar sus artículos de otra instancia de wallabag v2. Vaya a Todos los artículos, entonces, en la barra lateral, oprima en "JSON". Usted tendrá un fichero "All articles.json"'
345 readability:
346 page_title: 'Importar > Readability'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 page_title: 'Promotor' 351 page_title: 'Promotor'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
index e3592a78..e9af1e8d 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'مقاله‌های برگزیده' 139 starred: 'مقاله‌های برگزیده'
140 archived: 'مقاله‌های بایگانی‌شده' 140 archived: 'مقاله‌های بایگانی‌شده'
141 filtered: 'مقاله‌های فیلترشده' 141 filtered: 'مقاله‌های فیلترشده'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: '{0} هیج مقاله‌ای نیست.|{1} یک مقاله هست.|]1,Inf[ %count% مقاله هست.' 145 number_on_the_page: '{0} هیج مقاله‌ای نیست.|{1} یک مقاله هست.|]1,Inf[ %count% مقاله هست.'
144 reading_time: 'زمان تخمینی برای خواندن' 146 reading_time: 'زمان تخمینی برای خواندن'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'افزودن برچسب' 188 add_a_tag: 'افزودن برچسب'
187 share_content: 'هم‌رسانی' 189 share_content: 'هم‌رسانی'
188 share_email_label: 'نشانی ایمیل' 190 share_email_label: 'نشانی ایمیل'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'بارگیری' 193 download: 'بارگیری'
190 print: 'چاپ' 194 print: 'چاپ'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'مهاجرت از Pocket' 292 pocket: 'مهاجرت از Pocket'
289 wallabag_v1: 'مهاجرت از نسخهٔ یکم wallabag' 293 wallabag_v1: 'مهاجرت از نسخهٔ یکم wallabag'
290 wallabag_v2: 'مهاجرت از نسخهٔ دوم wallabag' 294 wallabag_v2: 'مهاجرت از نسخهٔ دوم wallabag'
295 readability: 'مهاجرت از نسخهٔ دوم Readability'
291 developer: 296 developer:
292 title: 'برنامه‌نویسان' 297 title: 'برنامه‌نویسان'
293 create_application: 'برنامهٔ wallabag خود را بسازید' 298 create_application: 'برنامهٔ wallabag خود را بسازید'
@@ -309,18 +314,19 @@ tag:
309 page_title: 'برچسب‌ها' 314 page_title: 'برچسب‌ها'
310 list: 315 list:
311 number_on_the_page: '{0} هیچ برچسبی نیست.|{1} یک برچسب هست.|]1,Inf[ %count% برچسب هست.' 316 number_on_the_page: '{0} هیچ برچسبی نیست.|{1} یک برچسب هست.|]1,Inf[ %count% برچسب هست.'
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 page_title: 'درون‌ریزی' 320 page_title: 'درون‌ریزی'
315 page_description: 'به درون‌ریز wallabag خوش آمدید. لطفاً سرویس قبلی خود را که می‌خواهید از آن مهاجرت کنید انتخاب کنید.' 321 page_description: 'به درون‌ریز wallabag خوش آمدید. لطفاً سرویس قبلی خود را که می‌خواهید از آن مهاجرت کنید انتخاب کنید.'
316 action: 322 action:
317 import_contents: 'درون‌ریزی مقاله‌ها' 323 import_contents: 'درون‌ریزی مقاله‌ها'
318 form: 324 form:
319 mark_as_read_title: 'علامت‌زدن همه به عنوان خوانده‌شده؟' 325 mark_as_read_title: 'علامت‌زدن همه به عنوان خوانده‌شده؟'
320 mark_as_read_label: 'همهٔ مقاله‌های درون‌ریزی شده را به عنوان خوانده‌شده علامت بزن' 326 mark_as_read_label: 'همهٔ مقاله‌های درون‌ریزی شده را به عنوان خوانده‌شده علامت بزن'
321 file_label: 'پرونده' 327 file_label: 'پرونده'
322 save_label: 'بارگذاری پرونده' 328 save_label: 'بارگذاری پرونده'
323 pocket: 329 pocket:
324 page_title: 'درون‌ریزی > Pocket' 330 page_title: 'درون‌ریزی > Pocket'
325 description: "این برنامه همهٔ داده‌های Pocket شما را درون‌ریزی می‌کند. سرویس Pocket اجازه نمی‌دهد که متن مقاله‌ها را درون‌ریزی کنیم، بنابراین wallabag متن مقاله‌ها را دوباره از اینترنت دریافت می‌کند." 331 description: "این برنامه همهٔ داده‌های Pocket شما را درون‌ریزی می‌کند. سرویس Pocket اجازه نمی‌دهد که متن مقاله‌ها را درون‌ریزی کنیم، بنابراین wallabag متن مقاله‌ها را دوباره از اینترنت دریافت می‌کند."
326 config_missing: 332 config_missing:
@@ -329,13 +335,17 @@ import:
329 user_message: 'مدیر سرور شما باید یک API Key برای Pocket تعریف کند.' 335 user_message: 'مدیر سرور شما باید یک API Key برای Pocket تعریف کند.'
330 authorize_message: 'شما می‌توانید داده‌هایتان را از حساب Pocket خود درون‌ریزی کنید. روی دکمهٔ زیر کلیک کنید و به برنامه اجازه دهید تا به getpocket.com وصل شود.' 336 authorize_message: 'شما می‌توانید داده‌هایتان را از حساب Pocket خود درون‌ریزی کنید. روی دکمهٔ زیر کلیک کنید و به برنامه اجازه دهید تا به getpocket.com وصل شود.'
331 connect_to_pocket: 'به Pocket وصل شو و داده‌ها را دریافت کن' 337 connect_to_pocket: 'به Pocket وصل شو و داده‌ها را دریافت کن'
332 wallabag_v1: 338 wallabag_v1:
333 page_title: 'درون‌ریزی > Wallabag v1' 339 page_title: 'درون‌ریزی > Wallabag v1'
334 description: 'این برنامه همهٔ داده‌های شما را در نسخهٔ ۱ wallabag درون‌ریزی می‌کند. در صفحهٔ تنظیمات، روی "JSON export" در بخش "Export your wallabag data" کلیک کنید. با این کار شما پرونده‌ای به شکل "wallabag-export-1-xxxx-xx-xx.json" دریافت خواهید کرد.' 340 description: 'این برنامه همهٔ داده‌های شما را در نسخهٔ ۱ wallabag درون‌ریزی می‌کند. در صفحهٔ تنظیمات، روی "JSON export" در بخش "Export your wallabag data" کلیک کنید. با این کار شما پرونده‌ای به شکل "wallabag-export-1-xxxx-xx-xx.json" دریافت خواهید کرد.'
335 how_to: 'لطفاً پرونده را انتخاب کنید و روی دکمهٔ زیر کلیک کنید تا بارگذاری و درون‌ریزی شود.' 341 how_to: 'لطفاً پرونده را انتخاب کنید و روی دکمهٔ زیر کلیک کنید تا بارگذاری و درون‌ریزی شود.'
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'درون‌ریزی > Wallabag v2' 343 page_title: 'درون‌ریزی > Wallabag v2'
338 description: 'این برنامه همهٔ داده‌های شما را در نسخهٔ ۲ wallabag درون‌ریزی می‌کند. به بخش «همهٔ مقاله‌ها» بروید و در بخش «برون‌ریزی» روی "JSON" کلیک کنید. با این کار شما پرونده‌ای به شکل "All articles.json" دریافت خواهید کرد.' 344 description: 'این برنامه همهٔ داده‌های شما را در نسخهٔ ۲ wallabag درون‌ریزی می‌کند. به بخش «همهٔ مقاله‌ها» بروید و در بخش «برون‌ریزی» روی "JSON" کلیک کنید. با این کار شما پرونده‌ای به شکل "All articles.json" دریافت خواهید کرد.'
345 readability:
346 page_title: 'درون‌ریزی > Readability'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 # page_title: 'Developer' 351 # page_title: 'Developer'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index 9e47d600..402cdf4a 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'Articles favoris' 139 starred: 'Articles favoris'
140 archived: 'Articles lus' 140 archived: 'Articles lus'
141 filtered: 'Articles filtrés' 141 filtered: 'Articles filtrés'
142 filtered_tags: 'Articles filtrés par tags'
143 untagged: 'Article sans tag'
142 list: 144 list:
143 number_on_the_page: "{0} Il n'y a pas d'articles.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles." 145 number_on_the_page: "{0} Il n'y a pas d'articles.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles."
144 reading_time: 'durée de lecture' 146 reading_time: 'durée de lecture'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Ajouter un tag' 188 add_a_tag: 'Ajouter un tag'
187 share_content: 'Partager' 189 share_content: 'Partager'
188 share_email_label: 'Email' 190 share_email_label: 'Email'
191 public_link: 'Lien public'
192 delete_public_link: 'Supprimer lien public'
189 download: 'Télécharger' 193 download: 'Télécharger'
190 print: 'Imprimer' 194 print: 'Imprimer'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'Migrer depuis Pocket' 292 pocket: 'Migrer depuis Pocket'
289 wallabag_v1: 'Migrer depuis wallabag v1' 293 wallabag_v1: 'Migrer depuis wallabag v1'
290 wallabag_v2: 'Migrer depuis wallabag v2' 294 wallabag_v2: 'Migrer depuis wallabag v2'
295 readability: 'Migrer depuis Readability'
291 developer: 296 developer:
292 title: 'Pour les développeurs' 297 title: 'Pour les développeurs'
293 create_application: 'Créer votre application tierce' 298 create_application: 'Créer votre application tierce'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Tags' 314 page_title: 'Tags'
310 list: 315 list:
311 number_on_the_page: "{0} Il n'y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." 316 number_on_the_page: "{0} Il n'y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags."
317 see_untagged_entries: 'Voir les articles sans tag'
312 318
313import: 319import:
314 page_title: 'Importer' 320 page_title: 'Importer'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'Importer > Wallabag v2' 343 page_title: 'Importer > Wallabag v2'
338 description: "Cet outil va importer tous vos articles d'une 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\"" 344 description: "Cet outil va importer tous vos articles d'une 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\""
345 readability:
346 page_title: 'Importer > Readability'
347 description: 'Cet outil va importer toutes vos données de Readability. Sur la page des outils (https://www.readability.com/tools/), cliquez sur "Export your data" dans la section "Data Export". Vous allez recevoir un email avec un lien pour télécharger le json.'
348 how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l'importer."
339 349
340developer: 350developer:
341 page_title: 'Développeur' 351 page_title: 'Développeur'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
index 3760c2d6..3aee4816 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'Contenuti preferiti' 139 starred: 'Contenuti preferiti'
140 archived: 'Contenuti archiviati' 140 archived: 'Contenuti archiviati'
141 filtered: 'Contenuti filtrati' 141 filtered: 'Contenuti filtrati'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: "{0} Non ci sono contenuti.|{1} C'è un contenuto.|]1,Inf[ Ci sono %count% contenuti." 145 number_on_the_page: "{0} Non ci sono contenuti.|{1} C'è un contenuto.|]1,Inf[ Ci sono %count% contenuti."
144 reading_time: 'tempo di lettura stimato' 146 reading_time: 'tempo di lettura stimato'
@@ -185,6 +187,8 @@ entry:
185 add_a_tag: 'Aggiungi un tag' 187 add_a_tag: 'Aggiungi un tag'
186 share_content: 'Condividi' 188 share_content: 'Condividi'
187 share_email_label: 'E-mail' 189 share_email_label: 'E-mail'
190 # public_link: 'public link'
191 # delete_public_link: 'delete public link'
188 download: 'Download' 192 download: 'Download'
189 print: 'Stampa' 193 print: 'Stampa'
190 problem: 194 problem:
@@ -287,6 +291,7 @@ quickstart:
287 pocket: 'Trasferisci da Pocket' 291 pocket: 'Trasferisci da Pocket'
288 wallabag_v1: 'Trasferisci da wallabag v1' 292 wallabag_v1: 'Trasferisci da wallabag v1'
289 wallabag_v2: 'Trasferisci da wallabag v2' 293 wallabag_v2: 'Trasferisci da wallabag v2'
294 readability: 'Trasferisci da Readability'
290 developer: 295 developer:
291 title: 'Sviluppatori' 296 title: 'Sviluppatori'
292 create_application: 'Crea la tua applicazione' 297 create_application: 'Crea la tua applicazione'
@@ -308,6 +313,7 @@ tag:
308 page_title: 'Tags' 313 page_title: 'Tags'
309 list: 314 list:
310 number_on_the_page: "{0} Non ci sono tag.|{1} C'è un tag.|]1,Inf[ ci sono %count% tag." 315 number_on_the_page: "{0} Non ci sono tag.|{1} C'è un tag.|]1,Inf[ ci sono %count% tag."
316 # see_untagged_entries: 'See untagged entries'
311 317
312import: 318import:
313 page_title: 'Importa' 319 page_title: 'Importa'
@@ -335,6 +341,10 @@ import:
335 wallabag_v2: 341 wallabag_v2:
336 page_title: 'Importa da > Wallabag v2' 342 page_title: 'Importa da > Wallabag v2'
337 description: 'Questo importatore copierà tutti i tuoi dati da un wallabag v2. Vai in "Tutti i contenuti", e, nella sidebar di esportazione, clicca su "JSON". Otterrai un file "Tutti i contenuti.json".' 343 description: 'Questo importatore copierà tutti i tuoi dati da un wallabag v2. Vai in "Tutti i contenuti", e, nella sidebar di esportazione, clicca su "JSON". Otterrai un file "Tutti i contenuti.json".'
344 readability:
345 page_title: 'Importa da > Readability'
346 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
347 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
338 348
339developer: 349developer:
340 page_title: 'Sviluppatori' 350 page_title: 'Sviluppatori'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
index 1e23168b..855f2361 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
@@ -139,6 +139,8 @@ entry:
139 starred: 'Articles favorits' 139 starred: 'Articles favorits'
140 archived: 'Articles legits' 140 archived: 'Articles legits'
141 filtered: 'Articles filtrats' 141 filtered: 'Articles filtrats'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: "{0} I a pas cap d'article.|{1} I a un article.|]1,Inf[ I a %count% articles." 145 number_on_the_page: "{0} I a pas cap d'article.|{1} I a un article.|]1,Inf[ I a %count% articles."
144 reading_time: 'durada de lectura' 146 reading_time: 'durada de lectura'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Ajustar una etiqueta' 188 add_a_tag: 'Ajustar una etiqueta'
187 share_content: 'Partatjar' 189 share_content: 'Partatjar'
188 share_email_label: 'Corrièl' 190 share_email_label: 'Corrièl'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'Telecargar' 193 download: 'Telecargar'
190 print: 'Imprimir' 194 print: 'Imprimir'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'Migrar dempuèi Pocket' 292 pocket: 'Migrar dempuèi Pocket'
289 wallabag_v1: 'Migrar dempuèi wallabag v1' 293 wallabag_v1: 'Migrar dempuèi wallabag v1'
290 wallabag_v2: 'Migrar dempuèi wallabag v2' 294 wallabag_v2: 'Migrar dempuèi wallabag v2'
295 readability: 'Migrar dempuèi Readability'
291 developer: 296 developer:
292 title: 'Pels desvolopadors' 297 title: 'Pels desvolopadors'
293 create_application: 'Crear vòstra aplicacion tèrça' 298 create_application: 'Crear vòstra aplicacion tèrça'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Etiquetas' 314 page_title: 'Etiquetas'
310 list: 315 list:
311 number_on_the_page: "{0} I a pas cap d'etiquetas.|{1} I a una etiqueta.|]1,Inf[ I a %count% etiquetas." 316 number_on_the_page: "{0} I a pas cap d'etiquetas.|{1} I a una etiqueta.|]1,Inf[ I a %count% etiquetas."
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 page_title: 'Importar' 320 page_title: 'Importar'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'Importer > Wallabag v2' 343 page_title: 'Importer > Wallabag v2'
338 description: "Aquesta aisina importarà totas vòstras donadas d'una instància mai de wallabag v2. Anatz dins totes vòstres articles, puèi, sus la barra laterala, clicatz sus \"JSON\". Traparatz un fichièr \"All articles.json\"" 344 description: "Aquesta aisina importarà totas vòstras donadas d'una instància mai de wallabag v2. Anatz dins totes vòstres articles, puèi, sus la barra laterala, clicatz sus \"JSON\". Traparatz un fichièr \"All articles.json\""
345 readability:
346 page_title: 'Importer > Readability'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 page_title: 'Desvolopador' 351 page_title: 'Desvolopador'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
index 0a325c57..da50cd4c 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
@@ -139,12 +139,14 @@ entry:
139 starred: 'Wpisy oznaczone gwiazdką' 139 starred: 'Wpisy oznaczone gwiazdką'
140 archived: 'Zarchiwizowane wpisy' 140 archived: 'Zarchiwizowane wpisy'
141 filtered: 'Odfiltrowane wpisy' 141 filtered: 'Odfiltrowane wpisy'
142 filtered_tags: 'Filtrowane po tagach'
143 untagged: 'Odtaguj wpisy'
142 list: 144 list:
143 number_on_the_page: '{0} Nie ma wpisów.|{1} Jest jeden wpis.|]1,Inf[ Są %count% wpisy.' 145 number_on_the_page: '{0} Nie ma wpisów.|{1} Jest jeden wpis.|]1,Inf[ Są %count% wpisy.'
144 reading_time: 'szacunkowy czas czytania' 146 reading_time: 'szacunkowy czas czytania'
145 reading_time_minutes: 'szacunkowy czas czytania: %readingTime% min' 147 reading_time_minutes: 'szacunkowy czas czytania: %readingTime% min'
146 reading_time_less_one_minute: 'szacunkowy czas czytania: <small class="inferieur">&lt;</small> 1 min' 148 reading_time_less_one_minute: 'szacunkowy czas czytania: <small class="inferieur">&lt;</small> 1 min'
147 # number_of_tags: '{1}and one other tag|]1,Inf[and %count% other tags' 149 number_of_tags: '{1} i inny tag|]1,Inf[i %count% innych tagów'
148 reading_time_minutes_short: '%readingTime% min' 150 reading_time_minutes_short: '%readingTime% min'
149 reading_time_less_one_minute_short: '<small class="inferieur">&lt;</small> 1 min' 151 reading_time_less_one_minute_short: '<small class="inferieur">&lt;</small> 1 min'
150 original_article: 'oryginał' 152 original_article: 'oryginał'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Dodaj tag' 188 add_a_tag: 'Dodaj tag'
187 share_content: 'Udostępnij' 189 share_content: 'Udostępnij'
188 share_email_label: 'Adres email' 190 share_email_label: 'Adres email'
191 public_link: 'Publiczny link'
192 delete_public_link: 'Usuń publiczny link'
189 download: 'Pobierz' 193 download: 'Pobierz'
190 print: 'Drukuj' 194 print: 'Drukuj'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: 'Migruj z Pocket' 292 pocket: 'Migruj z Pocket'
289 wallabag_v1: 'Migruj z wallabag v1' 293 wallabag_v1: 'Migruj z wallabag v1'
290 wallabag_v2: 'Migruj z wallabag v2' 294 wallabag_v2: 'Migruj z wallabag v2'
295 readability: 'Migruj z Readability'
291 developer: 296 developer:
292 title: 'Deweloperzy' 297 title: 'Deweloperzy'
293 create_application: 'Stwórz swoją aplikację' 298 create_application: 'Stwórz swoją aplikację'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Tagi' 314 page_title: 'Tagi'
310 list: 315 list:
311 number_on_the_page: '{0} Nie ma tagów.|{1} Jest jeden tag.|]1,Inf[ Są %count% tagi.' 316 number_on_the_page: '{0} Nie ma tagów.|{1} Jest jeden tag.|]1,Inf[ Są %count% tagi.'
317 see_untagged_entries: 'Zobacz nieotagowane wpisy'
312 318
313import: 319import:
314 page_title: 'Import' 320 page_title: 'Import'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'Import > Wallabag v2' 343 page_title: 'Import > Wallabag v2'
338 description: 'Ten importer, zaimportuje wszystkie twoje artykułu z wallabag v2. Idź do wszystkich artykułów, a następnie na panelu exportu kliknij na "JSON". Otrzymasz plik "All articles.json".' 344 description: 'Ten importer, zaimportuje wszystkie twoje artykułu z wallabag v2. Idź do wszystkich artykułów, a następnie na panelu exportu kliknij na "JSON". Otrzymasz plik "All articles.json".'
345 readability:
346 page_title: 'Import > Readability'
347 description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Readability. Na stronie narzędzi (https://www.readability.com/tools/), kliknij na "Export your data" w sekcji "Data Export". Otrzymach email z plikiem JSON (plik nie będzie zawierał rozszerzenia .json).'
348 how_to: 'Wybierz swój plik eksportu z Readability i kliknij poniższy przycisk, aby go załadować.'
339 349
340developer: 350developer:
341 page_title: 'Deweloper' 351 page_title: 'Deweloper'
@@ -343,7 +353,7 @@ developer:
343 documentation: 'Dokumentacja' 353 documentation: 'Dokumentacja'
344 how_to_first_app: 'Jak stworzyć moją pierwszą aplikację' 354 how_to_first_app: 'Jak stworzyć moją pierwszą aplikację'
345 full_documentation: 'Pokaż pełne API' 355 full_documentation: 'Pokaż pełne API'
346 # list_methods: 'List API methods' 356 list_methods: 'Lista metod API'
347 clients: 357 clients:
348 title: 'Klienci' 358 title: 'Klienci'
349 create_new: 'Utwórz nowego klienta' 359 create_new: 'Utwórz nowego klienta'
@@ -401,7 +411,7 @@ flashes:
401 notice: 411 notice:
402 entry_already_saved: 'Wpis już został dodany %date%' 412 entry_already_saved: 'Wpis już został dodany %date%'
403 entry_saved: 'Wpis zapisany' 413 entry_saved: 'Wpis zapisany'
404 # entry_saved_failed: 'Failed to save entry' 414 entry_saved_failed: 'Zapis artykułu s nie powiódł'
405 entry_updated: 'Wpis zaktualizowany' 415 entry_updated: 'Wpis zaktualizowany'
406 entry_reloaded: 'Wpis ponownie załadowany' 416 entry_reloaded: 'Wpis ponownie załadowany'
407 entry_reload_failed: 'Błąd ponownego załadowania' 417 entry_reload_failed: 'Błąd ponownego załadowania'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
index 42ad28ee..f41609d0 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
@@ -139,6 +139,8 @@ entry:
139 # starred: 'Starred entries' 139 # starred: 'Starred entries'
140 # archived: 'Archived entries' 140 # archived: 'Archived entries'
141 # filtered: 'Filtered entries' 141 # filtered: 'Filtered entries'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.' 145 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
144 reading_time: 'timp estimat de citire' 146 reading_time: 'timp estimat de citire'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Adaugă un tag' 188 add_a_tag: 'Adaugă un tag'
187 share_content: 'Dă mai departe' 189 share_content: 'Dă mai departe'
188 share_email_label: 'E-mail' 190 share_email_label: 'E-mail'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'Descarcă' 193 download: 'Descarcă'
190 # print: 'Print' 194 # print: 'Print'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 # pocket: 'Migrate from Pocket' 292 # pocket: 'Migrate from Pocket'
289 # wallabag_v1: 'Migrate from wallabag v1' 293 # wallabag_v1: 'Migrate from wallabag v1'
290 # wallabag_v2: 'Migrate from wallabag v2' 294 # wallabag_v2: 'Migrate from wallabag v2'
295 # readability: 'Migrate from Readability'
291 # developer: 296 # developer:
292 # title: 'Developers' 297 # title: 'Developers'
293 # create_application: 'Create your third application' 298 # create_application: 'Create your third application'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Tag-uri' 314 page_title: 'Tag-uri'
310 list: 315 list:
311 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' 316 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.'
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 # page_title: 'Import' 320 # page_title: 'Import'
@@ -336,6 +342,10 @@ import:
336 # wallabag_v2: 342 # wallabag_v2:
337 # page_title: 'Import > Wallabag v2' 343 # page_title: 'Import > Wallabag v2'
338 # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' 344 # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.'
345 # readability:
346 # page_title: 'Import > Readability'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 # page_title: 'Developer' 351 # page_title: 'Developer'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
index a60dfc86..6dfbfa89 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
@@ -139,6 +139,8 @@ entry:
139 # starred: 'Starred entries' 139 # starred: 'Starred entries'
140 # archived: 'Archived entries' 140 # archived: 'Archived entries'
141 # filtered: 'Filtered entries' 141 # filtered: 'Filtered entries'
142 # filtered_tags: 'Filtered by tags'
143 # untagged: 'Untagged entries'
142 list: 144 list:
143 number_on_the_page: '{0} Herhangi bir makale yok.|{1} Burada bir adet makale var.|]1,Inf[ Burada %count% adet makale var.' 145 number_on_the_page: '{0} Herhangi bir makale yok.|{1} Burada bir adet makale var.|]1,Inf[ Burada %count% adet makale var.'
144 reading_time: 'tahmini okuma süresi' 146 reading_time: 'tahmini okuma süresi'
@@ -186,6 +188,8 @@ entry:
186 add_a_tag: 'Bir etiket ekle' 188 add_a_tag: 'Bir etiket ekle'
187 share_content: 'Paylaş' 189 share_content: 'Paylaş'
188 share_email_label: 'E-posta' 190 share_email_label: 'E-posta'
191 # public_link: 'public link'
192 # delete_public_link: 'delete public link'
189 download: 'İndir' 193 download: 'İndir'
190 # print: 'Print' 194 # print: 'Print'
191 problem: 195 problem:
@@ -288,6 +292,7 @@ quickstart:
288 pocket: "Pocket üzerindeki verilerinizi wallabag'e aktarın" 292 pocket: "Pocket üzerindeki verilerinizi wallabag'e aktarın"
289 wallabag_v1: "wallabag v1 üzerindeki verilerinizi wallabag'in yeni sürümüne aktarın" 293 wallabag_v1: "wallabag v1 üzerindeki verilerinizi wallabag'in yeni sürümüne aktarın"
290 wallabag_v2: "wallabag v2 üzerindeki verilerinizi wallabag'in yeni sürümüne aktarın" 294 wallabag_v2: "wallabag v2 üzerindeki verilerinizi wallabag'in yeni sürümüne aktarın"
295 readability: "Readability üzerindeki verilerinizi wallabag'e aktarın'"
291 developer: 296 developer:
292 # title: 'Developers' 297 # title: 'Developers'
293 # create_application: 'Create your third application' 298 # create_application: 'Create your third application'
@@ -309,6 +314,7 @@ tag:
309 page_title: 'Etiketler' 314 page_title: 'Etiketler'
310 list: 315 list:
311 number_on_the_page: '{0} Herhangi bir etiket yok.|{1} Burada bir adet etiket var.|]1,Inf[ Burada %count% adet etiket var.' 316 number_on_the_page: '{0} Herhangi bir etiket yok.|{1} Burada bir adet etiket var.|]1,Inf[ Burada %count% adet etiket var.'
317 # see_untagged_entries: 'See untagged entries'
312 318
313import: 319import:
314 page_title: 'İçe Aktar' 320 page_title: 'İçe Aktar'
@@ -336,6 +342,10 @@ import:
336 wallabag_v2: 342 wallabag_v2:
337 page_title: 'İçe Aktar > Wallabag v2' 343 page_title: 'İçe Aktar > Wallabag v2'
338 # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.' 344 # description: 'This importer will import all your wallabag v2 articles. Go to All articles, then, on the export sidebar, click on "JSON". You will have a "All articles.json" file.'
345 readability:
346 page_title: 'İçe Aktar > Readability'
347 # description: 'This importer will import all your Readability articles. On the tools (https://www.readability.com/tools/) page, click on "Export your data" in the "Data Export" section. You will received an email to download a json (which does not end with .json in fact).'
348 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
339 349
340developer: 350developer:
341 # page_title: 'Developer' 351 # page_title: 'Developer'
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/_title.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/_title.html.twig
new file mode 100644
index 00000000..d1c2f203
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/_title.html.twig
@@ -0,0 +1,15 @@
1{% set currentRoute = app.request.attributes.get('_route') %}
2
3{% if currentRoute == 'starred' %}
4 {{ 'entry.page_titles.starred'|trans }}
5{% elseif currentRoute == 'archive' %}
6 {{ 'entry.page_titles.archived'|trans }}
7{% elseif currentRoute == 'all' %}
8 {{ 'entry.page_titles.filtered'|trans }}
9{% elseif currentRoute == 'tag_entries' %}
10 {{ 'entry.page_titles.filtered_tags'|trans }}
11{% elseif currentRoute == 'untagged' %}
12 {{ 'entry.page_titles.untagged'|trans }}
13{% else %}
14 {{ 'entry.page_titles.unread'|trans }}
15{% endif %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
index 92eecb9b..1554cce4 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
@@ -1,6 +1,8 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %} 1{% extends "WallabagCoreBundle::layout.html.twig" %}
2 2
3{% block title %}{{ 'entry.page_titles.unread'|trans }}{% endblock %} 3{% block title %}
4 {% include "@WallabagCore/themes/_title.html.twig" %}
5{% endblock %}
4 6
5{% block content %} 7{% block content %}
6 {% include "WallabagCoreBundle:Entry:pager.html.twig" with {'entries': entries} %} 8 {% include "WallabagCoreBundle:Entry:pager.html.twig" with {'entries': entries} %}
@@ -44,7 +46,6 @@
44 </div> 46 </div>
45 {% endfor %} 47 {% endfor %}
46 48
47
48 <!-- Export --> 49 <!-- Export -->
49 <aside id="download-form"> 50 <aside id="download-form">
50 {% set currentRoute = app.request.attributes.get('_route') %} 51 {% set currentRoute = app.request.attributes.get('_route') %}
@@ -63,8 +64,10 @@
63 {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml' }) }}">XML</a></li>{% endif %} 64 {% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml' }) }}">XML</a></li>{% endif %}
64 </ul> 65 </ul>
65 </aside> 66 </aside>
67
66 <!-- Filter --> 68 <!-- Filter -->
67 <aside id="filter-form"> 69 {% if form is not null %}
70 <aside id="filter-form" class="">
68 <form method="get" action="{{ path('all') }}"> 71 <form method="get" action="{{ path('all') }}">
69 <h2>{{ 'entry.filters.title'|trans }}</h2> 72 <h2>{{ 'entry.filters.title'|trans }}</h2>
70 <a href="javascript: void(null);" id="filter-form-close" class="close-button--popup close-button">&times;</a> 73 <a href="javascript: void(null);" id="filter-form-close" class="close-button--popup close-button">&times;</a>
@@ -145,6 +148,5 @@
145 </div> 148 </div>
146 </form> 149 </form>
147 </aside> 150 </aside>
148 151 {% endif %}
149 {% include "WallabagCoreBundle:Entry:pager.html.twig" with {'entries': entries} %}
150{% endblock %} 152{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
index ce47a677..675168bb 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
@@ -17,6 +17,7 @@
17 <li><a title="{{ 'entry.view.left_menu.set_as_starred'|trans }}" class="tool icon icon-star {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.set_as_starred'|trans }}</span></a></li> 17 <li><a title="{{ 'entry.view.left_menu.set_as_starred'|trans }}" class="tool icon icon-star {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.set_as_starred'|trans }}</span></a></li>
18 <li><a id="nav-btn-add-tag" title="{{ 'entry.view.left_menu.add_a_tag'|trans }}"><span>{{ 'entry.view.left_menu.add_a_tag'|trans }}</span></a></li> 18 <li><a id="nav-btn-add-tag" title="{{ 'entry.view.left_menu.add_a_tag'|trans }}"><span>{{ 'entry.view.left_menu.add_a_tag'|trans }}</span></a></li>
19 <li><a title="{{ 'entry.view.left_menu.delete'|trans }}" class="tool delete icon icon-trash" href="{{ path('delete_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.delete'|trans }}</span></a></li> 19 <li><a title="{{ 'entry.view.left_menu.delete'|trans }}" class="tool delete icon icon-trash" href="{{ path('delete_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.delete'|trans }}</span></a></li>
20 {% if craue_setting('share_public') %}<li><a href="{{ path('share', {'id': entry.id }) }}" target="_blank" class="tool public" title="{{ 'entry.view.left_menu.public_link'|trans }}"><span>{{ 'entry.view.left_menu.public_link'|trans }}</span></a></li> <li><a href="{{ path('delete_share', {'id': entry.id }) }}" class="tool public" title="{{ 'entry.view.left_menu.delete_public_link'|trans }}"><span>{{ 'entry.view.left_menu.delete_public_link'|trans }}</span></a></li>{% endif %}
20 {% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %} 21 {% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %}
21 {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %} 22 {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %}
22 {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}" target="_blank" class="tool shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %} 23 {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}" target="_blank" class="tool shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %}
@@ -29,29 +30,32 @@
29 <li><a href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.label'|trans }}" class="tool bad-display icon icon-delete"><span>{{ 'entry.view.left_menu.problem.label'|trans }}</span></a></li> 30 <li><a href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.label'|trans }}" class="tool bad-display icon icon-delete"><span>{{ 'entry.view.left_menu.problem.label'|trans }}</span></a></li>
30 </ul> 31 </ul>
31 </div> 32 </div>
32 <div class="link mdi-action-today">
33 {{ 'entry.view.created_at'|trans }}: {{ entry.createdAt|date('Y-m-d') }}
34 </div>
35 33
36 <div class="link mdi-action-query-builder"> 34 <div id="article-informations">
37 {% set readingTime = entry.readingTime / app.user.config.readingSpeed %} 35 <div class="link mdi-action-today">
38 {% if readingTime > 0 %} 36 {{ 'entry.view.created_at'|trans }}: {{ entry.createdAt|date('Y-m-d') }}
39 {{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': readingTime|round})|capitalize }} 37 </div>
40 {% else %}
41 {{ 'entry.list.reading_time_less_one_minute'|trans|raw }}
42 {% endif %}
43 </div>
44 38
45 {% set nbAnnotations = entry.annotations | length %} 39 <div class="link mdi-action-query-builder">
46 <span class="tool link"><i class="material-icons link">comment</i> {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span> 40 {% set readingTime = entry.readingTime / app.user.config.readingSpeed %}
47 <aside class="tags"> 41 {% if readingTime > 0 %}
48 {% for tag in entry.tags %} 42 {{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': readingTime|round})|capitalize }}
49 <span class="label-outline"><i class="material-icons">label_outline</i> {{ tag.label }}</span> <a href="{{ path('remove_tag', { 'entry': entry.id, 'tag': tag.id }) }}"class="nostyle"><i>✘</i></a> 43 {% else %}
50 {% endfor %} 44 {{ 'entry.list.reading_time_less_one_minute'|trans|raw }}
51 <div class="input-field nav-panel-add-tag" style="display: none"> 45 {% endif %}
52 {{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }}
53 </div> 46 </div>
54 </aside> 47
48 {% set nbAnnotations = entry.annotations | length %}
49 <span class="tool link"><i class="material-icons link">comment</i> {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span>
50 <aside class="tags">
51 {% for tag in entry.tags %}
52 <span class="label-outline"><i class="material-icons">label_outline</i> {{ tag.label }}</span> <a href="{{ path('remove_tag', { 'entry': entry.id, 'tag': tag.id }) }}"class="nostyle"><i>✘</i></a>
53 {% endfor %}
54 <div class="input-field nav-panel-add-tag" style="display: none">
55 {{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }}
56 </div>
57 </aside>
58 </div>
55 {% if entry.previewPicture is not null %} 59 {% if entry.previewPicture is not null %}
56 <div><img class="preview" src="{{ entry.previewPicture }}" alt="{{ entry.title|raw }}" /></div> 60 <div><img class="preview" src="{{ entry.previewPicture }}" alt="{{ entry.title|raw }}" /></div>
57 {% endif %} 61 {% endif %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Static/quickstart.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Static/quickstart.html.twig
index b3d3d5a0..ea1c1cbe 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Static/quickstart.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Static/quickstart.html.twig
@@ -39,6 +39,7 @@
39 <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li> 39 <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
40 <li><a href="{{ path('import_wallabag_v1') }}">{{ 'quickstart.migrate.wallabag_v1'|trans }}</a></li> 40 <li><a href="{{ path('import_wallabag_v1') }}">{{ 'quickstart.migrate.wallabag_v1'|trans }}</a></li>
41 <li><a href="{{ path('import_wallabag_v2') }}">{{ 'quickstart.migrate.wallabag_v2'|trans }}</a></li> 41 <li><a href="{{ path('import_wallabag_v2') }}">{{ 'quickstart.migrate.wallabag_v2'|trans }}</a></li>
42 <li><a href="{{ path('import_readability') }}">{{ 'quickstart.migrate.readability'|trans }}</a></li>
42 </ul> 43 </ul>
43 44
44 <h4>{{ 'quickstart.developer.title'|trans }}</h4> 45 <h4>{{ 'quickstart.developer.title'|trans }}</h4>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig
index 524a1d23..50043907 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Tag/tags.html.twig
@@ -9,7 +9,11 @@
9 9
10 <ul> 10 <ul>
11 {% for tag in tags %} 11 {% for tag in tags %}
12 <li id="tag-{{ tag.id|e }}">{{tag.label}} ({{ tag.getEntriesByUserId(app.user.id) | length }})</li> 12 <li id="tag-{{ tag.id|e }}"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.entries.getValues | length }})</a></li>
13 {% endfor %} 13 {% endfor %}
14 </ul> 14 </ul>
15
16 <div>
17 <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }}</a>
18 </div>
15{% endblock %} 19{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
index 11b02294..bf390e89 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
@@ -196,6 +196,7 @@
196 </div> 196 </div>
197 197
198 <div id="set5" class="col s12"> 198 <div id="set5" class="col s12">
199 {% if app.user.config.taggingRules is not empty %}
199 <div class="row"> 200 <div class="row">
200 <div class="input-field col s12"> 201 <div class="input-field col s12">
201 <ul> 202 <ul>
@@ -213,6 +214,7 @@
213 </ul> 214 </ul>
214 </div> 215 </div>
215 </div> 216 </div>
217 {% endif %}
216 218
217 {{ form_start(form.new_tagging_rule) }} 219 {{ form_start(form.new_tagging_rule) }}
218 {{ form_errors(form.new_tagging_rule) }} 220 {{ form_errors(form.new_tagging_rule) }}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
index eca8924e..806a4eef 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
@@ -1,18 +1,7 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %} 1{% extends "WallabagCoreBundle::layout.html.twig" %}
2 2
3{% block title %} 3{% block title %}
4 {% set currentRoute = app.request.attributes.get('_route') %} 4 {% include "@WallabagCore/themes/_title.html.twig" %}
5
6 {% if currentRoute == 'starred' %}
7 {{ 'entry.page_titles.starred'|trans }}
8 {% elseif currentRoute == 'archive' %}
9 {{ 'entry.page_titles.archived'|trans }}
10 {% elseif currentRoute == 'all' %}
11 {{ 'entry.page_titles.filtered'|trans }}
12 {% else %}
13 {{ 'entry.page_titles.unread'|trans }}
14 {% endif %}
15
16{% endblock %} 5{% endblock %}
17 6
18{% block content %} 7{% block content %}
@@ -40,7 +29,7 @@
40 <i class="card-title grey-text text-darken-4 activator material-icons right">more_vert</i> 29 <i class="card-title grey-text text-darken-4 activator material-icons right">more_vert</i>
41 {% endif %} 30 {% endif %}
42 31
43 <span class="card-title"><a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title|striptags }}">{{ entry.title|striptags|raw }}</a></span> 32 <span class="card-title dot-ellipsis dot-resize-update"><a href="{{ path('view', { 'id': entry.id }) }}" title="{{ entry.title|raw }}">{{ entry.title|striptags|raw }}</a></span>
44 33
45 <div class="estimatedTime grey-text"> 34 <div class="estimatedTime grey-text">
46 <span class="tool reading-time"> 35 <span class="tool reading-time">
@@ -122,6 +111,7 @@
122 </div> 111 </div>
123 112
124 <!-- Filters --> 113 <!-- Filters -->
114 {% if form is not null %}
125 <div id="filters" class="side-nav fixed right-aligned"> 115 <div id="filters" class="side-nav fixed right-aligned">
126 <form action="{{ path('all') }}"> 116 <form action="{{ path('all') }}">
127 117
@@ -205,5 +195,6 @@
205 195
206 </form> 196 </form>
207 </div> 197 </div>
208 {% include "WallabagCoreBundle:Entry:pager.html.twig" with {'entries': entries} %} 198 {% endif %}
199
209{% endblock %} 200{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
index 5dd2afb3..9b587c34 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
@@ -99,6 +99,18 @@
99 </a> 99 </a>
100 <div class="collapsible-body"> 100 <div class="collapsible-body">
101 <ul> 101 <ul>
102 {% if craue_setting('share_public') %}
103 <li>
104 <a href="{{ path('share', {'id': entry.id }) }}" target="_blank" class="public icon-link" title="{{ 'entry.view.left_menu.public_link'|trans }}">
105 <span>{{ 'entry.view.left_menu.public_link'|trans }}</span>
106 </a>
107 </li>
108 <li>
109 <a href="{{ path('delete_share', {'id': entry.id }) }}" class="tool public" title="{{ 'entry.view.left_menu.delete_public_link'|trans }}">
110 <span>{{ 'entry.view.left_menu.delete_public_link'|trans }}</span>
111 </a>
112 </li>
113 {% endif %}
102 {% if craue_setting('share_twitter') %} 114 {% if craue_setting('share_twitter') %}
103 <li> 115 <li>
104 <a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="twitter"> 116 <a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="twitter">
@@ -149,7 +161,6 @@
149 </li> 161 </li>
150 {% endif %} 162 {% endif %}
151 163
152
153 <li class="bold"> 164 <li class="bold">
154 <a class="waves-effect collapsible-header"> 165 <a class="waves-effect collapsible-header">
155 <i class="material-icons small">file_download</i> 166 <i class="material-icons small">file_download</i>
@@ -195,17 +206,18 @@
195 </header> 206 </header>
196 <aside> 207 <aside>
197 {% set readingTime = entry.readingTime / app.user.config.readingSpeed %} 208 {% set readingTime = entry.readingTime / app.user.config.readingSpeed %}
198 <span class="link mdi-action-query-builder"> 209 <span class="mdi-action-query-builder"></span>
210 <span class="link">
199 {% if readingTime > 0 %} 211 {% if readingTime > 0 %}
200 {{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }} 212 {{ 'entry.list.reading_time_minutes_short'|trans({'%readingTime%': readingTime|round}) }}
201 {% else %} 213 {% else %}
202 {{ 'entry.list.reading_time_less_one_minute_short'|trans|raw }} 214 {{ 'entry.list.reading_time_less_one_minute_short'|trans|raw }}
203 {% endif %} 215 {% endif %}
204 </span> 216 </span>
205 <span class="link mdi-action-today" title="{{ 'entry.view.created_at'|trans }}"> {{ entry.createdAt|date('Y-m-d') }}</span> 217 <span class="mdi-action-today" title="{{ 'entry.view.created_at'|trans }}"> </span> <span class="link">{{ entry.createdAt|date('Y-m-d') }}</span>
206 <a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool"> 218 <a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool">
207 <span class="link"><i class="material-icons link">link</i> {{ entry.domainName|removeWww }}</span></a> 219 <i class="material-icons link">link</i> <span class="link">{{ entry.domainName|removeWww }}</span></a>
208 <span class="tool link"><i class="material-icons link">comment</i> {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span> 220 <span class="tool"><i class="material-icons link">comment</i> <span class="link">{{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span>
209 <div id="list"> 221 <div id="list">
210 {% for tag in entry.tags %} 222 {% for tag in entry.tags %}
211 <div class="chip"> 223 <div class="chip">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
index 59dd037b..8cbf4ab4 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
@@ -44,6 +44,7 @@
44 <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li> 44 <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
45 <li><a href="{{ path('import_wallabag_v1') }}">{{ 'quickstart.migrate.wallabag_v1'|trans }}</a></li> 45 <li><a href="{{ path('import_wallabag_v1') }}">{{ 'quickstart.migrate.wallabag_v1'|trans }}</a></li>
46 <li><a href="{{ path('import_wallabag_v2') }}">{{ 'quickstart.migrate.wallabag_v2'|trans }}</a></li> 46 <li><a href="{{ path('import_wallabag_v2') }}">{{ 'quickstart.migrate.wallabag_v2'|trans }}</a></li>
47 <li><a href="{{ path('import_readability') }}">{{ 'quickstart.migrate.readability'|trans }}</a></li>
47 </ul> 48 </ul>
48 49
49 <h4>{{ 'quickstart.developer.title'|trans }}</h4> 50 <h4>{{ 'quickstart.developer.title'|trans }}</h4>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
index d958c4b8..1690633a 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
@@ -9,7 +9,10 @@
9 <br /> 9 <br />
10 <ul class="row data"> 10 <ul class="row data">
11 {% for tag in tags %} 11 {% for tag in tags %}
12 <li id="tag-{{ tag.id|e }}" class="col l4 m6 s12">{{tag.label}} ({{ tag.getEntriesByUserId(app.user.id) | length }})</li> 12 <li id="tag-{{ tag.id|e }}" class="col l4 m6 s12"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.entries.getValues | length }})</a></li>
13 {% endfor %} 13 {% endfor %}
14 </ul> 14 </ul>
15 <div>
16 <a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }}</a>
17 </div>
15{% endblock %} 18{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/share.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/share.html.twig
new file mode 100644
index 00000000..b82b3d3d
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/share.html.twig
@@ -0,0 +1,40 @@
1<html>
2 <head>
3 <title>{{ entry.title | raw }}</title>
4 <style>
5 body {
6 margin: 10px;
7 font-family: 'Roboto',Verdana,Geneva,sans-serif;
8 font-size: 16px;
9 color: #000;
10 }
11 header {
12 text-align: center;
13 }
14
15 header h1 {
16 font-size: 1.3em;
17 }
18
19 a,
20 a:hover,
21 a:visited {
22 color: #000;
23 }
24
25 article {
26 margin: 0 auto;
27 width: 600px;
28 }
29 </style>
30 </head>
31 <body>
32 <header>
33 <h1>{{ entry.title | raw }}</h1>
34 <span><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool">{{ entry.domainName|removeWww }}</a></span>
35 </header>
36 <article>
37 {{ entry.content | raw }}
38 </article>
39 </body>
40</html>
diff --git a/src/Wallabag/ImportBundle/Controller/ReadabilityController.php b/src/Wallabag/ImportBundle/Controller/ReadabilityController.php
new file mode 100644
index 00000000..b61aa99c
--- /dev/null
+++ b/src/Wallabag/ImportBundle/Controller/ReadabilityController.php
@@ -0,0 +1,65 @@
1<?php
2
3namespace Wallabag\ImportBundle\Controller;
4
5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
6use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
7use Symfony\Component\HttpFoundation\Request;
8use Wallabag\ImportBundle\Form\Type\UploadImportType;
9
10class ReadabilityController extends Controller
11{
12 /**
13 * @Route("/readability", name="import_readability")
14 */
15 public function indexAction(Request $request)
16 {
17 $form = $this->createForm(UploadImportType::class);
18 $form->handleRequest($request);
19
20 $readability = $this->get('wallabag_import.readability.import');
21
22 if ($form->isValid()) {
23 $file = $form->get('file')->getData();
24 $markAsRead = $form->get('mark_as_read')->getData();
25 $name = 'readability_'.$this->getUser()->getId().'.json';
26
27 if (in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
28 $res = $readability
29 ->setUser($this->getUser())
30 ->setFilepath($this->getParameter('wallabag_import.resource_dir').'/'.$name)
31 ->setMarkAsRead($markAsRead)
32 ->import();
33
34 $message = 'flashes.import.notice.failed';
35
36 if (true === $res) {
37 $summary = $readability->getSummary();
38 $message = $this->get('translator')->trans('flashes.import.notice.summary', [
39 '%imported%' => $summary['imported'],
40 '%skipped%' => $summary['skipped'],
41 ]);
42
43 unlink($this->getParameter('wallabag_import.resource_dir').'/'.$name);
44 }
45
46 $this->get('session')->getFlashBag()->add(
47 'notice',
48 $message
49 );
50
51 return $this->redirect($this->generateUrl('homepage'));
52 } else {
53 $this->get('session')->getFlashBag()->add(
54 'notice',
55 'flashes.import.notice.failed_on_file'
56 );
57 }
58 }
59
60 return $this->render('WallabagImportBundle:Readability:index.html.twig', [
61 'form' => $form->createView(),
62 'import' => $readability,
63 ]);
64 }
65}
diff --git a/src/Wallabag/ImportBundle/Import/ReadabilityImport.php b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
new file mode 100644
index 00000000..37b160c5
--- /dev/null
+++ b/src/Wallabag/ImportBundle/Import/ReadabilityImport.php
@@ -0,0 +1,179 @@
1<?php
2
3namespace Wallabag\ImportBundle\Import;
4
5use Wallabag\CoreBundle\Entity\Entry;
6use Wallabag\UserBundle\Entity\User;
7
8class ReadabilityImport extends AbstractImport
9{
10 private $user;
11 private $skippedEntries = 0;
12 private $importedEntries = 0;
13 private $filepath;
14 private $markAsRead;
15
16 /**
17 * We define the user in a custom call because on the import command there is no logged in user.
18 * So we can't retrieve user from the `security.token_storage` service.
19 *
20 * @param User $user
21 */
22 public function setUser(User $user)
23 {
24 $this->user = $user;
25
26 return $this;
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function getName()
33 {
34 return 'Readability';
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function getUrl()
41 {
42 return 'import_readability';
43 }
44
45 /**
46 * {@inheritdoc}
47 */
48 public function getDescription()
49 {
50 return 'import.readability.description';
51 }
52
53 /**
54 * Set file path to the json file.
55 *
56 * @param string $filepath
57 */
58 public function setFilepath($filepath)
59 {
60 $this->filepath = $filepath;
61
62 return $this;
63 }
64
65 /**
66 * Set whether articles must be all marked as read.
67 *
68 * @param bool $markAsRead
69 */
70 public function setMarkAsRead($markAsRead)
71 {
72 $this->markAsRead = $markAsRead;
73
74 return $this;
75 }
76
77 /**
78 * Get whether articles must be all marked as read.
79 */
80 public function getMarkAsRead()
81 {
82 return $this->markAsRead;
83 }
84
85 /**
86 * {@inheritdoc}
87 */
88 public function getSummary()
89 {
90 return [
91 'skipped' => $this->skippedEntries,
92 'imported' => $this->importedEntries,
93 ];
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function import()
100 {
101 if (!$this->user) {
102 $this->logger->error('ReadabilityImport: user is not defined');
103
104 return false;
105 }
106
107 if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
108 $this->logger->error('ReadabilityImport: unable to read file', ['filepath' => $this->filepath]);
109
110 return false;
111 }
112
113 $data = json_decode(file_get_contents($this->filepath), true);
114
115 if (empty($data) || empty($data['bookmarks'])) {
116 return false;
117 }
118
119 $this->parseEntries($data['bookmarks']);
120
121 return true;
122 }
123
124 /**
125 * Parse and insert all given entries.
126 *
127 * @param $entries
128 */
129 protected function parseEntries($entries)
130 {
131 $i = 1;
132
133 foreach ($entries as $importedEntry) {
134 $existingEntry = $this->em
135 ->getRepository('WallabagCoreBundle:Entry')
136 ->findByUrlAndUserId($importedEntry['article__url'], $this->user->getId());
137
138 if (false !== $existingEntry) {
139 ++$this->skippedEntries;
140 continue;
141 }
142
143 $data = [
144 'title' => $importedEntry['article__title'],
145 'url' => $importedEntry['article__url'],
146 'content_type' => '',
147 'language' => '',
148 'is_archived' => $importedEntry['archive'] || $this->markAsRead,
149 'is_starred' => $importedEntry['favorite'],
150 ];
151
152 $entry = $this->fetchContent(
153 new Entry($this->user),
154 $data['url'],
155 $data
156 );
157
158 // jump to next entry in case of problem while getting content
159 if (false === $entry) {
160 ++$this->skippedEntries;
161 continue;
162 }
163 $entry->setArchived($data['is_archived']);
164 $entry->setStarred($data['is_starred']);
165
166 $this->em->persist($entry);
167 ++$this->importedEntries;
168
169 // flush every 20 entries
170 if (($i % 20) === 0) {
171 $this->em->flush();
172 $this->em->clear($entry);
173 }
174 ++$i;
175 }
176
177 $this->em->flush();
178 }
179}
diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml
index 86b44cb3..520d43af 100644
--- a/src/Wallabag/ImportBundle/Resources/config/services.yml
+++ b/src/Wallabag/ImportBundle/Resources/config/services.yml
@@ -43,3 +43,13 @@ services:
43 - [ setLogger, [ "@logger" ]] 43 - [ setLogger, [ "@logger" ]]
44 tags: 44 tags:
45 - { name: wallabag_import.import, alias: wallabag_v2 } 45 - { name: wallabag_import.import, alias: wallabag_v2 }
46
47 wallabag_import.readability.import:
48 class: Wallabag\ImportBundle\Import\ReadabilityImport
49 arguments:
50 - "@doctrine.orm.entity_manager"
51 - "@wallabag_core.content_proxy"
52 calls:
53 - [ setLogger, [ "@logger" ]]
54 tags:
55 - { name: wallabag_import.import, alias: readability }
diff --git a/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig
new file mode 100644
index 00000000..f527d309
--- /dev/null
+++ b/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig
@@ -0,0 +1,43 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'import.readability.page_title'|trans }}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9 <div class="row">
10 <blockquote>{{ import.description|trans }}</blockquote>
11 <p>{{ 'import.readability.how_to'|trans }}</p>
12
13 <div class="col s12">
14 {{ form_start(form, {'method': 'POST'}) }}
15 {{ form_errors(form) }}
16 <div class="row">
17 <div class="file-field input-field col s12">
18 {{ form_errors(form.file) }}
19 <div class="btn">
20 <span>{{ form.file.vars.label|trans }}</span>
21 {{ form_widget(form.file) }}
22 </div>
23 <div class="file-path-wrapper">
24 <input class="file-path validate" type="text">
25 </div>
26 </div>
27 <div class="input-field col s6 with-checkbox">
28 <h6>{{ 'import.form.mark_as_read_title'|trans }}</h6>
29 {{ form_widget(form.mark_as_read) }}
30 {{ form_label(form.mark_as_read) }}
31 </div>
32 </div>
33
34 {{ form_widget(form.save, { 'attr': {'class': 'btn waves-effect waves-light'} }) }}
35
36 {{ form_rest(form) }}
37 </form>
38 </div>
39 </div>
40 </div>
41 </div>
42</div>
43{% endblock %}
diff --git a/src/Wallabag/UserBundle/Controller/RegistrationController.php b/src/Wallabag/UserBundle/Controller/RegistrationController.php
new file mode 100644
index 00000000..f81f3a7b
--- /dev/null
+++ b/src/Wallabag/UserBundle/Controller/RegistrationController.php
@@ -0,0 +1,18 @@
1<?php
2
3namespace Wallabag\UserBundle\Controller;
4
5use FOS\UserBundle\Controller\RegistrationController as FOSRegistrationController;
6use Symfony\Component\HttpFoundation\Request;
7
8class RegistrationController extends FOSRegistrationController
9{
10 public function registerAction(Request $request)
11 {
12 if ($this->container->getParameter('wallabag_user.registration_enabled')) {
13 return parent::registerAction($request);
14 }
15
16 return $this->redirectToRoute('fos_user_security_login', [], 301);
17 }
18}
diff --git a/src/Wallabag/UserBundle/Controller/SecurityController.php b/src/Wallabag/UserBundle/Controller/SecurityController.php
new file mode 100644
index 00000000..83fa0b20
--- /dev/null
+++ b/src/Wallabag/UserBundle/Controller/SecurityController.php
@@ -0,0 +1,21 @@
1<?php
2
3namespace Wallabag\UserBundle\Controller;
4
5use FOS\UserBundle\Controller\SecurityController as FOSSecurityController;
6
7/**
8 * Extends login form in order to pass the registration_enabled parameter.
9 */
10class SecurityController extends FOSSecurityController
11{
12 protected function renderLogin(array $data)
13 {
14 return $this->render('FOSUserBundle:Security:login.html.twig',
15 array_merge(
16 $data,
17 ['registration_enabled' => $this->container->getParameter('wallabag_user.registration_enabled')]
18 )
19 );
20 }
21}
diff --git a/src/Wallabag/UserBundle/DependencyInjection/Configuration.php b/src/Wallabag/UserBundle/DependencyInjection/Configuration.php
index 4223f8db..971ce1a0 100644
--- a/src/Wallabag/UserBundle/DependencyInjection/Configuration.php
+++ b/src/Wallabag/UserBundle/DependencyInjection/Configuration.php
@@ -12,6 +12,14 @@ class Configuration implements ConfigurationInterface
12 $treeBuilder = new TreeBuilder(); 12 $treeBuilder = new TreeBuilder();
13 $rootNode = $treeBuilder->root('wallabag_user'); 13 $rootNode = $treeBuilder->root('wallabag_user');
14 14
15 $rootNode
16 ->children()
17 ->booleanNode('registration_enabled')
18 ->defaultValue(true)
19 ->end()
20 ->end()
21 ;
22
15 return $treeBuilder; 23 return $treeBuilder;
16 } 24 }
17} 25}
diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
index c12a8937..99040f69 100644
--- a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
+++ b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
@@ -16,6 +16,7 @@ class WallabagUserExtension extends Extension
16 16
17 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 17 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
18 $loader->load('services.yml'); 18 $loader->load('services.yml');
19 $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']);
19 } 20 }
20 21
21 public function getAlias() 22 public function getAlias()
diff --git a/src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml b/src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml
new file mode 100644
index 00000000..53a1afd1
--- /dev/null
+++ b/src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml
@@ -0,0 +1,11 @@
1# Two factor mail
2auth_code:
3 on: 'sus'
4 mailer:
5 subject: "Còdi d'autentificacion wallabag"
6 body:
7 hello: "Bonjorn %user%,"
8 first_para: "Estant qu'avètz activat la dobla autentificacion sus vòtre compte wallabag e que venètz de vos conectar dempuèi un novèl aparelh (ordinador, mobil, etc.) vos mandem un còdi per validar la connexion."
9 second_para: "Vaquí lo còdi a dintrar :"
10 support: "S'avètz un problèma de connexion, dobtetz pas a contacter l'assisténcia : "
11 signature: "La còla de wallabag"
diff --git a/src/Wallabag/UserBundle/Resources/views/Security/login.html.twig b/src/Wallabag/UserBundle/Resources/views/Security/login.html.twig
index 8474b497..938f1a31 100644
--- a/src/Wallabag/UserBundle/Resources/views/Security/login.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Security/login.html.twig
@@ -33,13 +33,15 @@
33 </div> 33 </div>
34 <div class="card-action center"> 34 <div class="card-action center">
35 <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" /> 35 <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
36 <a href="{{ path('fos_user_registration_register') }}" class="waves-effect waves-light grey btn">{{ 'security.login.register'|trans }}</a> 36 {% if registration_enabled %}
37 <a href="{{ path('fos_user_registration_register') }}" class="waves-effect waves-light grey btn">{{ 'security.login.register'|trans }}</a>
38 {% endif %}
37 <button class="btn waves-effect waves-light" type="submit" name="send"> 39 <button class="btn waves-effect waves-light" type="submit" name="send">
38 {{ 'security.login.submit'|trans }} 40 {{ 'security.login.submit'|trans }}
39 <i class="material-icons right">send</i> 41 <i class="material-icons right">send</i>
40 </button> 42 </button>
41 </div> 43 </div>
42 <div class="center"> 44 <div class="row center">
43 <a href="{{ path('fos_user_resetting_request') }}">{{ 'security.login.forgot_password'|trans }}</a> 45 <a href="{{ path('fos_user_resetting_request') }}">{{ 'security.login.forgot_password'|trans }}</a>
44 </div> 46 </div>
45</form> 47</form>
diff --git a/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php
index 528366af..ee5b2ab7 100644
--- a/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php
+++ b/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php
@@ -3,6 +3,7 @@
3namespace Tests\Wallabag\ApiBundle\Controller; 3namespace Tests\Wallabag\ApiBundle\Controller;
4 4
5use Tests\Wallabag\ApiBundle\WallabagApiTestCase; 5use Tests\Wallabag\ApiBundle\WallabagApiTestCase;
6use Wallabag\CoreBundle\Entity\Tag;
6 7
7class WallabagRestControllerTest extends WallabagApiTestCase 8class WallabagRestControllerTest extends WallabagApiTestCase
8{ 9{
@@ -359,7 +360,7 @@ class WallabagRestControllerTest extends WallabagApiTestCase
359 $entry = $this->client->getContainer() 360 $entry = $this->client->getContainer()
360 ->get('doctrine.orm.entity_manager') 361 ->get('doctrine.orm.entity_manager')
361 ->getRepository('WallabagCoreBundle:Entry') 362 ->getRepository('WallabagCoreBundle:Entry')
362 ->findOneWithTags(1); 363 ->findOneWithTags($this->user->getId());
363 364
364 $entry = $entry[0]; 365 $entry = $entry[0];
365 366
@@ -421,7 +422,7 @@ class WallabagRestControllerTest extends WallabagApiTestCase
421 $entry = $this->client->getContainer() 422 $entry = $this->client->getContainer()
422 ->get('doctrine.orm.entity_manager') 423 ->get('doctrine.orm.entity_manager')
423 ->getRepository('WallabagCoreBundle:Entry') 424 ->getRepository('WallabagCoreBundle:Entry')
424 ->findOneWithTags(1); 425 ->findOneWithTags($this->user->getId());
425 $entry = $entry[0]; 426 $entry = $entry[0];
426 427
427 if (!$entry) { 428 if (!$entry) {
@@ -472,7 +473,7 @@ class WallabagRestControllerTest extends WallabagApiTestCase
472 $this->assertEquals($tag['label'], $content['label']); 473 $this->assertEquals($tag['label'], $content['label']);
473 $this->assertEquals($tag['slug'], $content['slug']); 474 $this->assertEquals($tag['slug'], $content['slug']);
474 475
475 $entries = $entry = $this->client->getContainer() 476 $entries = $this->client->getContainer()
476 ->get('doctrine.orm.entity_manager') 477 ->get('doctrine.orm.entity_manager')
477 ->getRepository('WallabagCoreBundle:Entry') 478 ->getRepository('WallabagCoreBundle:Entry')
478 ->findAllByTagId($this->user->getId(), $tag['id']); 479 ->findAllByTagId($this->user->getId(), $tag['id']);
@@ -480,6 +481,112 @@ class WallabagRestControllerTest extends WallabagApiTestCase
480 $this->assertCount(0, $entries); 481 $this->assertCount(0, $entries);
481 } 482 }
482 483
484 public function testDeleteTagByLabel()
485 {
486 $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
487 $entry = $this->client->getContainer()
488 ->get('doctrine.orm.entity_manager')
489 ->getRepository('WallabagCoreBundle:Entry')
490 ->findOneWithTags($this->user->getId());
491
492 $entry = $entry[0];
493
494 $tag = new Tag();
495 $tag->setLabel('Awesome tag for test');
496 $em->persist($tag);
497
498 $entry->addTag($tag);
499
500 $em->persist($entry);
501 $em->flush();
502
503 $this->client->request('DELETE', '/api/tag/label.json', ['tag' => $tag->getLabel()]);
504
505 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
506
507 $content = json_decode($this->client->getResponse()->getContent(), true);
508
509 $this->assertArrayHasKey('label', $content);
510 $this->assertEquals($tag->getLabel(), $content['label']);
511 $this->assertEquals($tag->getSlug(), $content['slug']);
512
513 $entries = $this->client->getContainer()
514 ->get('doctrine.orm.entity_manager')
515 ->getRepository('WallabagCoreBundle:Entry')
516 ->findAllByTagId($this->user->getId(), $tag->getId());
517
518 $this->assertCount(0, $entries);
519 }
520
521 public function testDeleteTagByLabelNotFound()
522 {
523 $this->client->request('DELETE', '/api/tag/label.json', ['tag' => 'does not exist']);
524
525 $this->assertEquals(404, $this->client->getResponse()->getStatusCode());
526 }
527
528 public function testDeleteTagsByLabel()
529 {
530 $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
531 $entry = $this->client->getContainer()
532 ->get('doctrine.orm.entity_manager')
533 ->getRepository('WallabagCoreBundle:Entry')
534 ->findOneWithTags($this->user->getId());
535
536 $entry = $entry[0];
537
538 $tag = new Tag();
539 $tag->setLabel('Awesome tag for tagsLabel');
540 $em->persist($tag);
541
542 $tag2 = new Tag();
543 $tag2->setLabel('Awesome tag for tagsLabel 2');
544 $em->persist($tag2);
545
546 $entry->addTag($tag);
547 $entry->addTag($tag2);
548
549 $em->persist($entry);
550 $em->flush();
551
552 $this->client->request('DELETE', '/api/tags/label.json', ['tags' => $tag->getLabel().','.$tag2->getLabel()]);
553
554 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
555
556 $content = json_decode($this->client->getResponse()->getContent(), true);
557
558 $this->assertCount(2, $content);
559
560 $this->assertArrayHasKey('label', $content[0]);
561 $this->assertEquals($tag->getLabel(), $content[0]['label']);
562 $this->assertEquals($tag->getSlug(), $content[0]['slug']);
563
564 $this->assertArrayHasKey('label', $content[1]);
565 $this->assertEquals($tag2->getLabel(), $content[1]['label']);
566 $this->assertEquals($tag2->getSlug(), $content[1]['slug']);
567
568 $entries = $this->client->getContainer()
569 ->get('doctrine.orm.entity_manager')
570 ->getRepository('WallabagCoreBundle:Entry')
571 ->findAllByTagId($this->user->getId(), $tag->getId());
572
573 $this->assertCount(0, $entries);
574
575 $entries = $this->client->getContainer()
576 ->get('doctrine.orm.entity_manager')
577 ->getRepository('WallabagCoreBundle:Entry')
578 ->findAllByTagId($this->user->getId(), $tag2->getId());
579
580 $this->assertCount(0, $entries);
581 }
582
583 public function testDeleteTagsByLabelNotFound()
584 {
585 $this->client->request('DELETE', '/api/tags/label.json', ['tags' => 'does not exist']);
586
587 $this->assertEquals(404, $this->client->getResponse()->getStatusCode());
588 }
589
483 public function testGetVersion() 590 public function testGetVersion()
484 { 591 {
485 $this->client->request('GET', '/api/version'); 592 $this->client->request('GET', '/api/version');
diff --git a/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php b/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php
index c0133af4..07ff2772 100644
--- a/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php
+++ b/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php
@@ -33,7 +33,7 @@ class InstallCommandTest extends WallabagCoreTestCase
33 } 33 }
34 34
35 /** 35 /**
36 * Ensure next tests will have a clean database 36 * Ensure next tests will have a clean database.
37 */ 37 */
38 public static function tearDownAfterClass() 38 public static function tearDownAfterClass()
39 { 39 {
diff --git a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php
index 5c739c78..a74c17d9 100644
--- a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php
@@ -236,6 +236,16 @@ class EntryControllerTest extends WallabagCoreTestCase
236 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 236 $this->assertEquals(200, $client->getResponse()->getStatusCode());
237 } 237 }
238 238
239 public function testUntagged()
240 {
241 $this->logInAs('admin');
242 $client = $this->getClient();
243
244 $client->request('GET', '/untagged/list');
245
246 $this->assertEquals(200, $client->getResponse()->getStatusCode());
247 }
248
239 public function testStarred() 249 public function testStarred()
240 { 250 {
241 $this->logInAs('admin'); 251 $this->logInAs('admin');
@@ -698,4 +708,47 @@ class EntryControllerTest extends WallabagCoreTestCase
698 $crawler = $client->submit($form, $data); 708 $crawler = $client->submit($form, $data);
699 $this->assertCount(2, $crawler->filter('div[class=entry]')); 709 $this->assertCount(2, $crawler->filter('div[class=entry]'));
700 } 710 }
711
712 public function testCache()
713 {
714 $this->logInAs('admin');
715 $client = $this->getClient();
716
717 $content = $client->getContainer()
718 ->get('doctrine.orm.entity_manager')
719 ->getRepository('WallabagCoreBundle:Entry')
720 ->findOneByUser($this->getLoggedInUserId());
721
722 // no uuid
723 $client->request('GET', '/share/'.$content->getUuid());
724 $this->assertEquals(404, $client->getResponse()->getStatusCode());
725
726 // generating the uuid
727 $client->request('GET', '/share/'.$content->getId());
728 $this->assertEquals(302, $client->getResponse()->getStatusCode());
729
730 // follow link with uuid
731 $crawler = $client->followRedirect();
732 $this->assertEquals(200, $client->getResponse()->getStatusCode());
733 $this->assertContains('max-age=25200', $client->getResponse()->headers->get('cache-control'));
734 $this->assertContains('public', $client->getResponse()->headers->get('cache-control'));
735 $this->assertContains('s-maxage=25200', $client->getResponse()->headers->get('cache-control'));
736 $this->assertNotContains('no-cache', $client->getResponse()->headers->get('cache-control'));
737
738 // sharing is now disabled
739 $client->getContainer()->get('craue_config')->set('share_public', 0);
740 $client->request('GET', '/share/'.$content->getUuid());
741 $this->assertEquals(404, $client->getResponse()->getStatusCode());
742
743 $client->request('GET', '/view/'.$content->getId());
744 $this->assertContains('no-cache', $client->getResponse()->headers->get('cache-control'));
745
746 // removing the share
747 $client->request('GET', '/share/delete/'.$content->getId());
748 $this->assertEquals(302, $client->getResponse()->getStatusCode());
749
750 // share is now disable
751 $client->request('GET', '/share/'.$content->getUuid());
752 $this->assertEquals(404, $client->getResponse()->getStatusCode());
753 }
701} 754}
diff --git a/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php b/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php
index 03355f5a..08f4676e 100644
--- a/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php
@@ -69,4 +69,19 @@ class SecurityControllerTest extends WallabagCoreTestCase
69 $this->assertTrue($user->isTrustedComputer('ABCDEF')); 69 $this->assertTrue($user->isTrustedComputer('ABCDEF'));
70 $this->assertFalse($user->isTrustedComputer('FEDCBA')); 70 $this->assertFalse($user->isTrustedComputer('FEDCBA'));
71 } 71 }
72
73 public function testEnabledRegistration()
74 {
75 $client = $this->getClient();
76
77 if (!$client->getContainer()->getParameter('fosuser_registration')) {
78 $this->markTestSkipped('fosuser_registration is not enabled.');
79
80 return;
81 }
82
83 $client->followRedirects();
84 $crawler = $client->request('GET', '/register');
85 $this->assertContains('registration.submit', $crawler->filter('body')->extract(['_text'])[0]);
86 }
72} 87}
diff --git a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php
index 58450e5f..71652760 100644
--- a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php
@@ -131,4 +131,35 @@ class TagControllerTest extends WallabagCoreTestCase
131 131
132 $this->assertEquals(404, $client->getResponse()->getStatusCode()); 132 $this->assertEquals(404, $client->getResponse()->getStatusCode());
133 } 133 }
134
135 public function testShowEntriesForTagAction()
136 {
137 $this->logInAs('admin');
138 $client = $this->getClient();
139
140 $entry = $client->getContainer()
141 ->get('doctrine.orm.entity_manager')
142 ->getRepository('WallabagCoreBundle:Entry')
143 ->findOneByUsernameAndNotArchived('admin');
144
145 $tag = $client->getContainer()
146 ->get('doctrine.orm.entity_manager')
147 ->getRepository('WallabagCoreBundle:Tag')
148 ->findOneByEntryAndTagLabel($entry, 'foo');
149
150 $crawler = $client->request('GET', '/tag/list/'.$tag->getSlug());
151
152 $this->assertEquals(200, $client->getResponse()->getStatusCode());
153 $this->assertCount(2, $crawler->filter('div[class=entry]'));
154
155 $tag = $client->getContainer()
156 ->get('doctrine.orm.entity_manager')
157 ->getRepository('WallabagCoreBundle:Tag')
158 ->findOneByLabel('baz');
159
160 $crawler = $client->request('GET', '/tag/list/'.$tag->getSlug());
161
162 $this->assertEquals(200, $client->getResponse()->getStatusCode());
163 $this->assertCount(0, $crawler->filter('div[class=entry]'));
164 }
134} 165}
diff --git a/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php b/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php
index 96b5300b..d869cdf9 100644
--- a/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php
+++ b/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php
@@ -24,6 +24,6 @@ class ImportControllerTest extends WallabagCoreTestCase
24 $crawler = $client->request('GET', '/import/'); 24 $crawler = $client->request('GET', '/import/');
25 25
26 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 26 $this->assertEquals(200, $client->getResponse()->getStatusCode());
27 $this->assertEquals(3, $crawler->filter('blockquote')->count()); 27 $this->assertEquals(4, $crawler->filter('blockquote')->count());
28 } 28 }
29} 29}
diff --git a/tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php b/tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php
new file mode 100644
index 00000000..92cf4bfc
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php
@@ -0,0 +1,122 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Controller;
4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8class ReadabilityControllerTest extends WallabagCoreTestCase
9{
10 public function testImportReadability()
11 {
12 $this->logInAs('admin');
13 $client = $this->getClient();
14
15 $crawler = $client->request('GET', '/import/readability');
16
17 $this->assertEquals(200, $client->getResponse()->getStatusCode());
18 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 }
21
22 public function testImportReadabilityWithFile()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $crawler = $client->request('GET', '/import/readability');
28 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
29
30 $file = new UploadedFile(__DIR__.'/../fixtures/readability.json', 'readability.json');
31
32 $data = [
33 'upload_import_file[file]' => $file,
34 ];
35
36 $client->submit($form, $data);
37
38 $this->assertEquals(302, $client->getResponse()->getStatusCode());
39
40 $crawler = $client->followRedirect();
41
42 $content = $client->getContainer()
43 ->get('doctrine.orm.entity_manager')
44 ->getRepository('WallabagCoreBundle:Entry')
45 ->findByUrlAndUserId(
46 'https://venngage.com/blog/hashtags-are-worthless/',
47 $this->getLoggedInUserId()
48 );
49
50 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
51 $this->assertContains('flashes.import.notice.summary', $body[0]);
52 }
53
54 public function testImportReadabilityWithFileAndMarkAllAsRead()
55 {
56 $this->logInAs('admin');
57 $client = $this->getClient();
58
59 $crawler = $client->request('GET', '/import/readability');
60 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
61
62 $file = new UploadedFile(__DIR__.'/../fixtures/readability-read.json', 'readability-read.json');
63
64 $data = [
65 'upload_import_file[file]' => $file,
66 'upload_import_file[mark_as_read]' => 1,
67 ];
68
69 $client->submit($form, $data);
70
71 $this->assertEquals(302, $client->getResponse()->getStatusCode());
72
73 $crawler = $client->followRedirect();
74
75 $content1 = $client->getContainer()
76 ->get('doctrine.orm.entity_manager')
77 ->getRepository('WallabagCoreBundle:Entry')
78 ->findByUrlAndUserId(
79 'https://blog.travis-ci.com/2016-07-28-what-we-learned-from-analyzing-2-million-travis-builds/',
80 $this->getLoggedInUserId()
81 );
82
83 $this->assertTrue($content1->isArchived());
84
85 $content2 = $client->getContainer()
86 ->get('doctrine.orm.entity_manager')
87 ->getRepository('WallabagCoreBundle:Entry')
88 ->findByUrlAndUserId(
89 'https://facebook.github.io/graphql/',
90 $this->getLoggedInUserId()
91 );
92
93 $this->assertTrue($content2->isArchived());
94
95 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
96 $this->assertContains('flashes.import.notice.summary', $body[0]);
97 }
98
99 public function testImportReadabilityWithEmptyFile()
100 {
101 $this->logInAs('admin');
102 $client = $this->getClient();
103
104 $crawler = $client->request('GET', '/import/readability');
105 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
106
107 $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
108
109 $data = [
110 'upload_import_file[file]' => $file,
111 ];
112
113 $client->submit($form, $data);
114
115 $this->assertEquals(302, $client->getResponse()->getStatusCode());
116
117 $crawler = $client->followRedirect();
118
119 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
120 $this->assertContains('flashes.import.notice.failed', $body[0]);
121 }
122}
diff --git a/tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php b/tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php
new file mode 100644
index 00000000..706d707b
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php
@@ -0,0 +1,150 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Import;
4
5use Wallabag\ImportBundle\Import\ReadabilityImport;
6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry;
8use Monolog\Logger;
9use Monolog\Handler\TestHandler;
10
11class ReadabilityImportTest extends \PHPUnit_Framework_TestCase
12{
13 protected $user;
14 protected $em;
15 protected $logHandler;
16 protected $contentProxy;
17
18 private function getReadabilityImport($unsetUser = false)
19 {
20 $this->user = new User();
21
22 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
23 ->disableOriginalConstructor()
24 ->getMock();
25
26 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
27 ->disableOriginalConstructor()
28 ->getMock();
29
30 $wallabag = new ReadabilityImport($this->em, $this->contentProxy);
31
32 $this->logHandler = new TestHandler();
33 $logger = new Logger('test', [$this->logHandler]);
34 $wallabag->setLogger($logger);
35
36 if (false === $unsetUser) {
37 $wallabag->setUser($this->user);
38 }
39
40 return $wallabag;
41 }
42
43 public function testInit()
44 {
45 $readabilityImport = $this->getReadabilityImport();
46
47 $this->assertEquals('Readability', $readabilityImport->getName());
48 $this->assertNotEmpty($readabilityImport->getUrl());
49 $this->assertEquals('import.readability.description', $readabilityImport->getDescription());
50 }
51
52 public function testImport()
53 {
54 $readabilityImport = $this->getReadabilityImport();
55 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability.json');
56
57 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
58 ->disableOriginalConstructor()
59 ->getMock();
60
61 $entryRepo->expects($this->exactly(2))
62 ->method('findByUrlAndUserId')
63 ->will($this->onConsecutiveCalls(false, true));
64
65 $this->em
66 ->expects($this->any())
67 ->method('getRepository')
68 ->willReturn($entryRepo);
69
70 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
71 ->disableOriginalConstructor()
72 ->getMock();
73
74 $this->contentProxy
75 ->expects($this->exactly(1))
76 ->method('updateEntry')
77 ->willReturn($entry);
78
79 $res = $readabilityImport->import();
80
81 $this->assertTrue($res);
82 $this->assertEquals(['skipped' => 1, 'imported' => 1], $readabilityImport->getSummary());
83 }
84
85 public function testImportAndMarkAllAsRead()
86 {
87 $readabilityImport = $this->getReadabilityImport();
88 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability-read.json');
89
90 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
91 ->disableOriginalConstructor()
92 ->getMock();
93
94 $entryRepo->expects($this->exactly(2))
95 ->method('findByUrlAndUserId')
96 ->will($this->onConsecutiveCalls(false, false));
97
98 $this->em
99 ->expects($this->any())
100 ->method('getRepository')
101 ->willReturn($entryRepo);
102
103 $this->contentProxy
104 ->expects($this->exactly(2))
105 ->method('updateEntry')
106 ->willReturn(new Entry($this->user));
107
108 // check that every entry persisted are archived
109 $this->em
110 ->expects($this->any())
111 ->method('persist')
112 ->with($this->callback(function ($persistedEntry) {
113 return $persistedEntry->isArchived();
114 }));
115
116 $res = $readabilityImport->setMarkAsRead(true)->import();
117
118 $this->assertTrue($res);
119
120 $this->assertEquals(['skipped' => 0, 'imported' => 2], $readabilityImport->getSummary());
121 }
122
123 public function testImportBadFile()
124 {
125 $readabilityImport = $this->getReadabilityImport();
126 $readabilityImport->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx');
127
128 $res = $readabilityImport->import();
129
130 $this->assertFalse($res);
131
132 $records = $this->logHandler->getRecords();
133 $this->assertContains('ReadabilityImport: unable to read file', $records[0]['message']);
134 $this->assertEquals('ERROR', $records[0]['level_name']);
135 }
136
137 public function testImportUserNotDefined()
138 {
139 $readabilityImport = $this->getReadabilityImport(true);
140 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability.json');
141
142 $res = $readabilityImport->import();
143
144 $this->assertFalse($res);
145
146 $records = $this->logHandler->getRecords();
147 $this->assertContains('ReadabilityImport: user is not defined', $records[0]['message']);
148 $this->assertEquals('ERROR', $records[0]['level_name']);
149 }
150}
diff --git a/tests/Wallabag/ImportBundle/fixtures/readability-read.json b/tests/Wallabag/ImportBundle/fixtures/readability-read.json
new file mode 100644
index 00000000..c60767dc
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/readability-read.json
@@ -0,0 +1,25 @@
1{
2 "bookmarks": [
3 {
4 "article__excerpt": "This is a guest post from Moritz Beller from the Delft University of Technology in The Netherlands. His team produced amazing research on several million Travis CI builds, creating invaluable&hellip;",
5 "favorite": false,
6 "date_archived": "2016-08-02T06:49:30",
7 "article__url": "https://blog.travis-ci.com/2016-07-28-what-we-learned-from-analyzing-2-million-travis-builds/",
8 "date_added": "2016-08-01T05:24:16",
9 "date_favorited": null,
10 "article__title": "Travis",
11 "archive": true
12 },
13 {
14 "article__excerpt": "The GraphQL Type system describes the capabilities of a GraphQL server and is used to determine if a query is valid. The type system also describes the input types of query variables to determine if&hellip;",
15 "favorite": false,
16 "date_archived": "2016-07-19T06:48:31",
17 "article__url": "https://facebook.github.io/graphql/",
18 "date_added": "2016-06-24T17:50:16",
19 "date_favorited": null,
20 "article__title": "GraphQL",
21 "archive": true
22 }
23 ],
24 "recommendations": []
25}
diff --git a/tests/Wallabag/ImportBundle/fixtures/readability.json b/tests/Wallabag/ImportBundle/fixtures/readability.json
new file mode 100644
index 00000000..34379905
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/readability.json
@@ -0,0 +1,25 @@
1{
2 "bookmarks": [
3 {
4 "article__excerpt": "When Twitter started it had so much promise to change the way we communicate. But now it has been ruined by the amount of garbage and hate we have to wade through. It&#x2019;s like that polluted&hellip;",
5 "favorite": false,
6 "date_archived": null,
7 "article__url": "https://venngage.com/blog/hashtags-are-worthless/",
8 "date_added": "2016-08-25T12:05:00",
9 "date_favorited": null,
10 "article__title": "We Looked At 167,943 Tweets & Found Out Hashtags Are Worthless",
11 "archive": false
12 },
13 {
14 "article__excerpt": "TL;DR: Re-use your DOM elements and remove the ones that are far away from the viewport. Use placeholders to account for delayed data. Here&#x2019;s a demo and the code for the infinite&hellip;",
15 "favorite": false,
16 "date_archived": "2016-08-26T12:21:54",
17 "article__url": "https://developers.google.com/web/updates/2016/07/infinite-scroller?imm_mid=0e6839&cmp=em-webops-na-na-newsltr_20160805",
18 "date_added": "2016-08-06T05:35:26",
19 "date_favorited": null,
20 "article__title": "Complexities of an infinite scroller | Web Updates",
21 "archive": true
22 }
23 ],
24 "recommendations": []
25}
diff --git a/var/SymfonyRequirements.php b/var/SymfonyRequirements.php
index 841338f4..0a5de546 100644
--- a/var/SymfonyRequirements.php
+++ b/var/SymfonyRequirements.php
@@ -681,10 +681,17 @@ class SymfonyRequirements extends RequirementCollection
681 681
682 if (class_exists('Symfony\Component\Intl\Intl')) { 682 if (class_exists('Symfony\Component\Intl\Intl')) {
683 $this->addRecommendation( 683 $this->addRecommendation(
684 \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(), 684 \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(),
685 sprintf('intl ICU version installed on your system (%s) should match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()), 685 sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
686 'In most cases you should be fine, but please verify there is no inconsistencies between data provided by Symfony and the intl extension. See https://github.com/symfony/symfony/issues/15007 for an example of inconsistencies you might run into.' 686 'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.'
687 ); 687 );
688 if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) {
689 $this->addRecommendation(
690 \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(),
691 sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
692 'To avoid internationalization data incosistencies upgrade the symfony/intl component.'
693 );
694 }
688 } 695 }
689 696
690 $this->addPhpIniRecommendation( 697 $this->addPhpIniRecommendation(