*/
public function up(Schema $schema)
{
- $this->addSql('ALTER TABLE '.$this->getTable('oauth2_clients').' ADD name longtext COLLATE \'utf8_unicode_ci\' DEFAULT NULL');
+ if ($this->connection->getDatabasePlatform()->getName() == 'sqlite') {
+ $this->addSql('ALTER TABLE '.$this->getTable('oauth2_clients').' ADD name longtext DEFAULT NULL');
+ } else {
+ $this->addSql('ALTER TABLE '.$this->getTable('oauth2_clients').' ADD name longtext COLLATE \'utf8_unicode_ci\' DEFAULT NULL');
+ }
}
/**
.card .card-content .card-title {
line-height: 32px;
max-height: 64px;
- display: block;
}
.card .card-content i.right,
}
.card .card-action a {
- color: #fff;
+ color: #fff !important;
margin: 0;
}
.card .card-action a:hover {
- color: #fff;
+ color: #fff !important;
}
.settings .div_tabs {
registration_enabled: "%fosuser_registration%"
wallabag_import:
- allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain']
+ allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain', 'text/csv']
resource_dir: "%kernel.root_dir%/../web/uploads/import"
# Twig Configuration
strict_variables: "%kernel.debug%"
form_themes:
- "LexikFormFilterBundle:Form:form_div_layout.html.twig"
+ exception_controller: wallabag_core.exception_controller:showAction
# Doctrine Configuration
doctrine:
exchange_options:
name: 'wallabag.import.readability'
type: topic
+ import_instapaper:
+ connection: default
+ exchange_options:
+ name: 'wallabag.import.instapaper'
+ type: topic
import_wallabag_v1:
connection: default
exchange_options:
queue_options:
name: 'wallabag.import.readability'
callback: wallabag_import.consumer.amqp.readability
+ import_instapaper:
+ connection: default
+ exchange_options:
+ name: 'wallabag.import.instapaper'
+ type: topic
+ queue_options:
+ name: 'wallabag.import.instapaper'
+ callback: wallabag_import.consumer.amqp.instapaper
import_wallabag_v1:
connection: default
exchange_options:
type: annotation
prefix: /import
+wallabag_user:
+ resource: "@WallabagUserBundle/Controller/"
+ type: annotation
+ prefix: /users
+
wallabag_api:
resource: "@WallabagApiBundle/Resources/config/routing.yml"
prefix: /
- { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/settings, roles: ROLE_SUPER_ADMIN }
- { path: ^/annotations, roles: ROLE_USER }
+ - { path: ^/users, roles: ROLE_SUPER_ADMIN }
- { path: ^/, roles: ROLE_USER }
- "@wallabag_core.tag_repository"
- "@security.token_storage"
- "%wallabag_core.cache_lifetime%"
+ - "@translator"
tags:
- { name: twig.extension }
ARG timezone='Europe/Paris'
RUN apt-get update && apt-get install -y \
- libmcrypt-dev libicu-dev libpq-dev libxml2-dev \
+ libmcrypt-dev libicu-dev libpq-dev libxml2-dev libpng12-dev libjpeg-dev \
+ && /usr/local/bin/docker-php-ext-configure gd --with-jpeg-dir=/usr/include \
&& docker-php-ext-install \
- iconv mcrypt mbstring intl pdo pdo_mysql pdo_pgsql
+ iconv mcrypt mbstring intl pdo pdo_mysql pdo_pgsql gd
RUN echo "date.timezone="$timezone > /usr/local/etc/php/conf.d/date_timezone.ini
master_doc = 'index'
project = u'wallabag-fr'
copyright = u'2013-2016, Nicolas Lœuillet - MIT Licence'
-version = '2.0.0'
+version = '2.1.0'
release = version
exclude_patterns = ['_build']
pygments_style = 'sphinx'
Eigenschaften mit den kommentierten zu ersetzen (mit Werten
mit ``env.`` Präfix)
#. ``composer install`` die Projektabhängigkeiten
-#. ``php app/console wallabag:install``, um das Schema zu erstellen
+#. ``php bin/console wallabag:install``, um das Schema zu erstellen
#. ``docker-compose up`` um die Container laufen zu lassen
#. Schließlich öffne http://localhost:8080/, um dein frisch
installiertes wallabag zu finden.
--- /dev/null
+Installiere RabbitMQ für asynchrone Aufgaben
+============================================
+
+Um asynchrone Aufgaben zu starten (nützlich z.B. für große Imports), können wir RabbitMQ nutzen.
+
+Voraussetzungen
+---------------
+
+Du musst RabbitMQ auf deinem Server installiert haben.
+
+Installation
+~~~~~~~~~~~~
+
+.. code:: bash
+
+ wget https://www.rabbitmq.com/rabbitmq-signing-key-public.asc
+ apt-key add rabbitmq-signing-key-public.asc
+ apt-get update
+ apt-get install rabbitmq-server
+
+Konfiguration und Starten
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: bash
+
+ rabbitmq-plugins enable rabbitmq_management # (useful to have a web interface, available at http://localhost:15672/ (guest/guest)
+ rabbitmq-server -detached
+
+RabbitMQ stoppen
+~~~~~~~~~~~~~~~
+
+.. code:: bash
+
+ rabbitmqctl stop
+
+
+Konfigure RabbitMQ in wallabag
+------------------------------
+
+Bearbeite die Datei ``parameters.yml``, um die RabbitMQ Konfiguration einzurichten. Die Standardkonfiguration sollte ok sein:
+
+.. code:: yaml
+
+ rabbitmq_host: localhost
+ rabbitmq_port: 5672
+ rabbitmq_user: guest
+ rabbitmq_password: guest
+
+
+Starte den RabbitMQ Consumer
+----------------------------
+
+Abhängig von welchem Service du importieren möchtest, solltest du einen Cron Job aktivieren (oder mehrere, wenn du viele unterstützen willst):
+
+.. code:: bash
+
+ # for Pocket import
+ bin/console rabbitmq:consumer import_pocket -w
+
+ # for Readability import
+ bin/console rabbitmq:consumer import_readability -w
+
+ # for Instapaper import
+ bin/console rabbitmq:consumer import_instapaper -w
+
+ # for wallabag v1 import
+ bin/console rabbitmq:consumer import_wallabag_v1 -w
+
+ # for wallabag v2 import
+ bin/console rabbitmq:consumer import_wallabag_v2 -w
+
+ # for Firefox import
+ bin/console rabbitmq:consumer import_firefox -w
+
+ # for Chrome import
+ bin/console rabbitmq:consumer import_chrome -w
+
--- /dev/null
+Installiere Redis für asynchrone Aufgaben
+=========================================
+
+Um asynchrone Aufgaben zu starten (nützlich z.B. für große Imports), können wir Redis nutzen.
+
+Voraussetzungen
+---------------
+
+Du musst Redis auf deinem Server installiert haben.
+
+Installation
+~~~~~~~~~~~~
+
+.. code:: bash
+
+ apt-get install redis-server
+
+Starten
+~~~~~~
+
+Der Redis Service läuft eventuell schon direkt nach der Installation. Falls nicht kannst du ihn wie folgt starten:
+
+.. code:: bash
+
+ redis-server
+
+
+Konfigure Redis in wallabag
+---------------------------
+
+Bearbeite die Datei ``parameters.yml``, um die RabbitMQ Konfiguration einzurichten. Die Standardkonfiguration sollte ok sein:
+
+.. code:: yaml
+
+ redis_host: localhost
+ redis_port: 6379
+
+
+Starte den Redis Consumer
+-------------------------
+
+Abhängig von welchem Service du importieren möchtest, solltest du einen Cron Job aktivieren (oder mehrere, wenn du viele unterstützen willst):
+
+.. code:: bash
+
+ # for Pocket import
+ bin/console wallabag:import:redis-worker pocket -vv >> /path/to/wallabag/var/logs/redis-pocket.log
+
+ # for Readability import
+ bin/console wallabag:import:redis-worker readability -vv >> /path/to/wallabag/var/logs/redis-readability.log
+
+ # for Instapaper import
+ bin/console wallabag:import:redis-worker instapaper -vv >> /path/to/wallabag/var/logs/redis-instapaper.log
+
+ # for wallabag v1 import
+ bin/console wallabag:import:redis-worker wallabag_v1 -vv >> /path/to/wallabag/var/logs/redis-wallabag_v1.log
+
+ # for wallabag v2 import
+ bin/console wallabag:import:redis-worker wallabag_v2 -vv >> /path/to/wallabag/var/logs/redis-wallabag_v2.log
+
+ # for Firefox import
+ bin/console wallabag:import:redis-worker firefox -vv >> /path/to/wallabag/var/logs/redis-firefox.log
+
+ # for Chrome import
+ bin/console wallabag:import:redis-worker instapaper -vv >> /path/to/wallabag/var/logs/redis-chrome.log
+
+Wenn du den Import nur für ein paar Nachrichten und nicht für alle starten willst, kannst du die Nummer (im folgenden Beispiel 12) angeben. Der Redis Worker wird dann nach der 12. Nachricht stoppen:
+
+.. code:: bash
+
+ bin/console wallabag:import:redis-worker pocket -vv --maxIterations=12
user/faq
user/installation
- user/upgrade
+ user/upgrade-2.0.x-2.1.y
+ user/upgrade-2.0.x-2.0.y
user/migration
user/import
user/create_account
developer/documentation
developer/translate
developer/maintenance
+ developer/redis
+ developer/rabbitmq
-Wallabag updaten
-================
+Wallabag updaten 2.0.x -> 2.1.x
+===============================
Update auf einem dedizierten Webserver
--------------------------------------
-Das neueste Release ist auf https://www.wallabag.org/pages/download-wallabag.html veröffentlicht. Um deine wallabag Installation auf die neueste Version upzudaten, führe die folgenden Kommandos in deinem wallabag Ordner aus (ersetze ``2.1.0`` mit der neuesten Releasenummer):
+Das neueste Release ist auf https://www.wallabag.org/pages/download-wallabag.html veröffentlicht. Um deine wallabag Installation auf die neueste Version upzudaten, führe die folgenden Kommandos in deinem wallabag Ordner aus (ersetze ``2.0.8`` mit der neuesten Releasenummer):
::
git fetch origin
git fetch --tags
- git checkout 2.1.0
- ./install.sh
+ git checkout 2.0.8
+ SYMFONY_ENV=prod composer install --no-dev -o --prefer-dist
+ php bin/console cache:clear --env=prod
Update auf einem Shared Webhosting
----------------------------------
--- /dev/null
+Wallabag updaten
+================
+
+.. warning::
+Wenn du den Import von Pocket durch das Hinzufügen des Consumer Key in den internen Einstellungen konfiguriert hast, fertige bitte ein Backup deines Keys an, bevor du auf das neue Release migrierst: Du wirst den Key nach dem Update in der Konfiguration erneut eintragen müssen.
+
+Update auf einem dedizierten Webserver
+--------------------------------------
+
+Das neueste Release ist auf https://www.wallabag.org/pages/download-wallabag.html veröffentlicht. Um deine wallabag-Installation auf die neueste Version zu aktualisieren, führe die folgenden Kommandos in deinem wallabag-Ordner aus (ersetze ``2.1.0`` mit der neuesten Releasenummer):
+
+::
+
+ git fetch origin
+ git fetch --tags
+ git checkout 2.1.0
+ ASSETS=build ./install.sh
+ php bin/console doctrine:migrations:migrate --env=prod
+ php bin/console cache:clear --env=prod
+
+Update auf einem Shared Webhosting
+----------------------------------
+
+Sichere deine ``app/config/parameters.yml`` Datei.
+
+Lade das neueste Release von wallabag herunter:
+
+.. code-block:: bash
+
+ wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package
+
+(md5 hash: ``4f84c725d1d6e3345eae0a406115e5ff``)
+
+Entpacke das Archiv in deinen wallabag-Ordner und ersetze ``app/config/parameters.yml`` mit deiner Datei.
+
+Bitte beachte, dass wir in dieser Version neue Parameter hinzugefügt haben. Du musst die Datei ``app/config/parameters.yml`` bearbeiten und die folgenden Zeilen hinzufügen (ersetze die Werte mit deiner Konfiguration):
+
+.. code-block:: bash
+
+ # RabbitMQ processing
+ rabbitmq_host: localhost
+ rabbitmq_port: 5672
+ rabbitmq_user: guest
+ rabbitmq_password: guest
+
+ # Redis processing
+ redis_host: localhost
+ redis_port: 6379
+
+Wenn du SQLite nutzt, musst auch das ``data/`` Verzeichnis in die neue Installation kopieren.
+
+Leere den ``var/cache`` Ordner.
+
+Du musst einige SQL-Abfragen ausführen, um die Datenbank zu aktualisieren. Wir nehmen in diesem Fall an, dass das Tabellenpräfix ``wallabag_`` ist und eine MySQL-Datenbank genutzt wird:
+
+.. code-block:: sql
+
+ ALTER TABLE `wallabag_entry` ADD `uuid` LONGTEXT DEFAULT NULL;
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('share_public', '1', 'entry');
+ ALTER TABLE `wallabag_oauth2_clients` ADD name longtext COLLATE 'utf8_unicode_ci' DEFAULT NULL;
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('import_with_redis', '0', 'import');
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('import_with_rabbitmq', '0', 'import');
+ ALTER TABLE `wallabag_config` ADD `pocket_consumer_key` VARCHAR(255) DEFAULT NULL;
+ DELETE FROM `wallabag_craue_config_setting` WHERE `name` = 'pocket_consumer_key';
master_doc = 'index'
project = u'wallabag'
copyright = u'2013-2016, Nicolas Lœuillet - MIT Licence'
-version = '2.0.0'
+version = '2.1.0'
release = version
exclude_patterns = ['_build']
pygments_style = 'sphinx'
#. Edit ``app/config/parameters.yml`` to replace ``database_*``
properties with commented ones (with values prefixed by ``env.``)
#. ``composer install`` the project dependencies
-#. ``php app/console wallabag:install`` to create the schema
+#. ``php bin/console wallabag:install`` to create the schema
#. ``docker-compose up`` to run the containers
#. Finally, browse to http://localhost:8080/ to find your freshly
installed wallabag.
# for Pocket import
bin/console rabbitmq:consumer import_pocket -w
- # for Readbility import
+ # for Readability import
bin/console rabbitmq:consumer import_readability -w
+ # for Instapaper import
+ bin/console rabbitmq:consumer import_instapaper -w
+
# for wallabag v1 import
bin/console rabbitmq:consumer import_wallabag_v1 -w
# for wallabag v2 import
bin/console rabbitmq:consumer import_wallabag_v2 -w
+
+ # for Firefox import
+ bin/console rabbitmq:consumer import_firefox -w
+
+ # for Chrome import
+ bin/console rabbitmq:consumer import_chrome -w
Install Redis for asynchronous tasks
-=======================================
+====================================
In order to launch asynchronous tasks (useful for huge imports for example), we can use Redis.
Launch Redis consumer
-------------------------
+---------------------
Depending on which service you want to import from you need to enable one (or many if you want to support many) cron job:
# for Pocket import
bin/console wallabag:import:redis-worker pocket -vv >> /path/to/wallabag/var/logs/redis-pocket.log
- # for Readbility import
+ # for Readability import
bin/console wallabag:import:redis-worker readability -vv >> /path/to/wallabag/var/logs/redis-readability.log
+ # for Instapaper import
+ bin/console wallabag:import:redis-worker instapaper -vv >> /path/to/wallabag/var/logs/redis-instapaper.log
+
# for wallabag v1 import
bin/console wallabag:import:redis-worker wallabag_v1 -vv >> /path/to/wallabag/var/logs/redis-wallabag_v1.log
# for wallabag v2 import
bin/console wallabag:import:redis-worker wallabag_v2 -vv >> /path/to/wallabag/var/logs/redis-wallabag_v2.log
+ # for Firefox import
+ bin/console wallabag:import:redis-worker firefox -vv >> /path/to/wallabag/var/logs/redis-firefox.log
+
+ # for Chrome import
+ bin/console wallabag:import:redis-worker instapaper -vv >> /path/to/wallabag/var/logs/redis-chrome.log
+
If you want to launch the import only for some messages and not all, you can specify this number (here 12) and the worker will stop right after the 12th message :
.. code:: bash
user/faq
user/installation
- user/upgrade
+ user/upgrade-2.0.x-2.1.y
+ user/upgrade-2.0.x-2.0.y
user/migration
user/import
user/create_account
developer/documentation
developer/translate
developer/maintenance
+ developer/redis
+ developer/rabbitmq
Import your data into wallabag 2.x
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Click on ``Import`` link in the menu, on ``Import contents`` in Pocket section
+Click on ``Import`` link in the menu, on ``Import contents`` in Pocket section
and then on ``Connect to Pocket and import data``.
You need to authorize wallabag to interact with your Pocket account.
-Your data will be imported. Data import can be a demanding process for your server
-(we need to work on this import to improve it).
+Your data will be imported. Data import can be a demanding process for your server.
From Readability
----------------
Import your data into wallabag 2.x
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Click on ``Import`` link in the menu, on ``Import contents`` in Readability section
+Click on ``Import`` link in the menu, on ``Import contents`` in Readability section
and then select your json file and upload it.
-Your data will be imported. Data import can be a demanding process for your server (we need to work on this import to improve it).
+Your data will be imported. Data import can be a demanding process for your server.
From Instapaper
---------------
-*Feature not yet implemented in wallabag v2.*
+Export your Instapaper data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On the settings (`https://www.instapaper.com/user<https://www.instapaper.com/user>`_) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like ``instapaper-export.csv``).
+
+Import your data into wallabag 2.x
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Click on ``Import`` link in the menu, on ``Import contents`` in Instapaper section
+and then select your CSV file and upload it.
+
+Your data will be imported. Data import can be a demanding process for your server.
From HTML or JSON file
----------------------
-Upgrade wallabag
-================
+Upgrade from 2.0.x to 2.0.y
+===========================
Upgrade on a dedicated web server
---------------------------------
-The last release is published on https://www.wallabag.org/pages/download-wallabag.html. In order to upgrade your wallabag installation and get the last version, run the following commands in you wallabag folder (replace ``2.1.0`` by the last release number):
+The last release is published on https://www.wallabag.org/pages/download-wallabag.html. In order to upgrade your wallabag installation and get the last version, run the following commands in you wallabag folder (replace ``2.0.8`` by the last release number):
::
git fetch origin
git fetch --tags
- git checkout 2.1.0
- ./install.sh
+ git checkout 2.0.8
+ SYMFONY_ENV=prod composer install --no-dev -o --prefer-dist
+ php bin/console cache:clear --env=prod
Upgrade on a shared hosting
---------------------------
wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package
-(md5 hash of the package: ``4f84c725d1d6e3345eae0a406115e5ff``)
+(md5 hash of the 2.0.8 package: ``4f84c725d1d6e3345eae0a406115e5ff``)
Extract the archive in your wallabag folder and replace ``app/config/parameters.yml`` with yours.
--- /dev/null
+Upgrading from 2.0.x to 2.1.y
+=============================
+
+.. warning::
+Before this migration, if you configured the Pocket import by adding your consumer key in Internal settings, please do a backup of it: you'll have to add it into the Config page after the upgrade.
+
+Upgrade on a dedicated web server
+---------------------------------
+
+The last release is published on https://www.wallabag.org/pages/download-wallabag.html. In order to upgrade your wallabag installation and get the last version, run the following commands in you wallabag folder (replace ``2.1.0`` by the last release number):
+
+::
+
+ git fetch origin
+ git fetch --tags
+ git checkout 2.1.0
+ ASSETS=build ./install.sh
+ php bin/console doctrine:migrations:migrate --env=prod
+ php bin/console cache:clear --env=prod
+
+Upgrade on a shared hosting
+---------------------------
+
+Backup your ``app/config/parameters.yml`` file.
+
+Download the last release of wallabag:
+
+.. code-block:: bash
+
+ wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package
+
+(md5 hash of the package: ``4f84c725d1d6e3345eae0a406115e5ff``)
+
+Extract the archive in your wallabag folder and replace ``app/config/parameters.yml`` with yours.
+
+Please note that we added new parameters in this version. You have to edit ``app/config/parameters.yml`` by adding these lines (replace with your configuration) :
+
+.. code-block:: bash
+
+ # RabbitMQ processing
+ rabbitmq_host: localhost
+ rabbitmq_port: 5672
+ rabbitmq_user: guest
+ rabbitmq_password: guest
+
+ # Redis processing
+ redis_host: localhost
+ redis_port: 6379
+
+If you use SQLite, you must also copy your ``data/`` folder inside the new installation.
+
+Empty ``var/cache`` folder.
+
+You must run some SQL queries to upgrade your database. We assume that the table prefix is ``wallabag_`` and the database server is a MySQL one:
+
+.. code-block:: sql
+
+ ALTER TABLE `wallabag_entry` ADD `uuid` LONGTEXT DEFAULT NULL;
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('share_public', '1', 'entry');
+ ALTER TABLE `wallabag_oauth2_clients` ADD name longtext COLLATE 'utf8_unicode_ci' DEFAULT NULL;
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('import_with_redis', '0', 'import');
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('import_with_rabbitmq', '0', 'import');
+ ALTER TABLE `wallabag_config` ADD `pocket_consumer_key` VARCHAR(255) DEFAULT NULL;
+ DELETE FROM `wallabag_craue_config_setting` WHERE `name` = 'pocket_consumer_key';
master_doc = 'index'
project = u'wallabag-fr'
copyright = u'2013-2016, Nicolas Lœuillet - MIT Licence'
-version = '2.0.0'
+version = '2.1.0'
release = version
exclude_patterns = ['_build']
pygments_style = 'sphinx'
#. Editer ``app/config/parameters.yml`` pour remplacer les propriétés ``database_*``
par les lignes commentées (celles avec des valeurs préfixées par ``env.``)
#. ``composer install`` pour installer les dépendances
-#. ``php app/console wallabag:install`` pour créer le schéma de la BDD
+#. ``php bin/console wallabag:install`` pour créer le schéma de la BDD
#. ``docker-compose up`` pour démarrer les conteneurs
#. Enfin, se rendre sur http://localhost:8080/ pour accéder à une installation
tout propre de wallabag.
--- /dev/null
+Installer RabbitMQ pour des tâches asynchrones
+==============================================
+
+Pour lancer des tâches asynchrones (utile pour des imports importants par exemple), nous pouvons utiliser RabbitMQ.
+
+Pré-requis
+----------
+
+Vous devez installer RabbitMQ sur votre serveur.
+
+Installation
+~~~~~~~~~~~~
+
+.. code:: bash
+
+ wget https://www.rabbitmq.com/rabbitmq-signing-key-public.asc
+ apt-key add rabbitmq-signing-key-public.asc
+ apt-get update
+ apt-get install rabbitmq-server
+
+Configuration et démarrage
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: bash
+
+ rabbitmq-plugins enable rabbitmq_management # (useful to have a web interface, available at http://localhost:15672/ (guest/guest)
+ rabbitmq-server -detached
+
+Arrêter RabbitMQ
+~~~~~~~~~~~~~~~~
+
+.. code:: bash
+
+ rabbitmqctl stop
+
+
+Configurer RabbitMQ dans wallabag
+---------------------------------
+
+Modifiez votre fichier ``parameters.yml`` pour éditer la configuration RabbitMQ. Celle par défaut devrait convenir :
+
+.. code:: yaml
+
+ rabbitmq_host: localhost
+ rabbitmq_port: 5672
+ rabbitmq_user: guest
+ rabbitmq_password: guest
+
+
+Démarrer les clients RabbitMQ
+-----------------------------
+
+En fonction du service dont vous souhaitez importer vos données, vous devez activer un (ou plusieurs si vous souhaitez en supporter plusieurs) cron job :
+
+.. code:: bash
+
+ # for Pocket import
+ bin/console rabbitmq:consumer import_pocket -w
+
+ # for Readability import
+ bin/console rabbitmq:consumer import_readability -w
+
+ # for Instapaper import
+ bin/console rabbitmq:consumer import_instapaper -w
+
+ # for wallabag v1 import
+ bin/console rabbitmq:consumer import_wallabag_v1 -w
+
+ # for wallabag v2 import
+ bin/console rabbitmq:consumer import_wallabag_v2 -w
+
+ # for Firefox import
+ bin/console rabbitmq:consumer import_firefox -w
+
+ # for Chrome import
+ bin/console rabbitmq:consumer import_chrome -w
--- /dev/null
+Installer Redis pour des tâches asynchrones
+===========================================
+
+Pour lancer des tâches asynchrones (utile pour des imports importants par exemple), nous pouvons utiliser Redis.
+
+Pré-requis
+----------
+
+Vous devez installer Redis sur votre serveur.
+
+Installation
+~~~~~~~~~~~~
+
+.. code:: bash
+
+ apt-get install redis-server
+
+Démarrage
+~~~~~~~~~
+
+Le serveur devrait déjà être démarré après l'installation. Si ce n'est pas le cas, vous pouvez le démarrer ainsi :
+
+.. code:: bash
+
+ redis-server
+
+
+Configurer Redis dans wallabag
+-------------------------------
+
+Modifiez votre fichier ``parameters.yml`` pour éditer la configuration Redis. Celle par défaut devrait convenir :
+
+.. code:: yaml
+
+ redis_host: localhost
+ redis_port: 6379
+
+
+Démarrer les clients Redis
+--------------------------
+
+En fonction du service dont vous souhaitez importer vos données, vous devez activer un (ou plusieurs si vous souhaitez en supporter plusieurs) cron job :
+
+.. code:: bash
+
+ # for Pocket import
+ bin/console wallabag:import:redis-worker pocket -vv >> /path/to/wallabag/var/logs/redis-pocket.log
+
+ # for Readability import
+ bin/console wallabag:import:redis-worker readability -vv >> /path/to/wallabag/var/logs/redis-readability.log
+
+ # for Instapaper import
+ bin/console wallabag:import:redis-worker instapaper -vv >> /path/to/wallabag/var/logs/redis-instapaper.log
+
+ # for wallabag v1 import
+ bin/console wallabag:import:redis-worker wallabag_v1 -vv >> /path/to/wallabag/var/logs/redis-wallabag_v1.log
+
+ # for wallabag v2 import
+ bin/console wallabag:import:redis-worker wallabag_v2 -vv >> /path/to/wallabag/var/logs/redis-wallabag_v2.log
+
+ # for Firefox import
+ bin/console wallabag:import:redis-worker firefox -vv >> /path/to/wallabag/var/logs/redis-firefox.log
+
+ # for Chrome import
+ bin/console wallabag:import:redis-worker instapaper -vv >> /path/to/wallabag/var/logs/redis-chrome.log
+
+Si vous souhaitez démarrer l'import pour quelques messages uniquement, vous pouvez spécifier cette valeur en paramètre (ici 12) et le client va s'arrêter après le 12ème message :
+
+.. code:: bash
+
+ bin/console wallabag:import:redis-worker pocket -vv --maxIterations=12
user/faq
user/installation
- user/upgrade
+ user/upgrade-2.0.x-2.1.y
+ user/upgrade-2.0.x-2.0.y
user/migration
user/import
user/create_account
developer/documentation
developer/translate
developer/maintenance
+ developer/redis
+ developer/rabbitmq
Vous devez autoriser wallabag à se connecter à votre compte Pocket.
Vos 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).
+pour votre serveur.
Depuis Readability
------------------
Cliquez sur le lien ``Importer`` dans le menu, sur ``Importer les contenus`` dans
la section Readability et ensuite sélectionnez votre fichier json pour l'uploader.
-Vos 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).
+Vos données vont être importées. L'import de données est une action qui peut être couteuse pour votre serveur.
Depuis Instapaper
-----------------
-*Fonctionnalité pas encore implémentée dans wallabag v2.*
+Exportez vos données de Instapaper
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sur la page des paramètres (`https://www.instapaper.com/user<https://www.instapaper.com/user>`_), cliquez sur "Download .CSV file" dans la section "Export". Un fichier CSV se téléchargera (``instapaper-export.csv``).
+
+Importez vos données dans wallabag 2.x
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Cliquez sur le lien ``Importer`` dans le menu, sur ``Importer les contenus`` dans
+la section Instapaper et ensuite sélectionnez votre fichier CSV pour l'uploader.
+
+Vos données vont être importées. L'import de données est une action qui peut être couteuse pour votre serveur.
Depuis un fichier HTML ou JSON
-Mettre à jour wallabag
-======================
+Mettre à jour de la 2.0.x à la 2.0.y
+====================================
Mise à jour sur un serveur dédié
--------------------------------
-La dernière version de wallabag est publiée à cette adresse : https://www.wallabag.org/pages/download-wallabag.html. Pour mettre à jour votre installation de wallabag, exécutez les commandes suivantes dans votre répertoire d'installation (remplacez ``2.1.0`` par le numéro de la dernière version) :
+La dernière version de wallabag est publiée à cette adresse : https://www.wallabag.org/pages/download-wallabag.html. Pour mettre à jour votre installation de wallabag, exécutez les commandes suivantes dans votre répertoire d'installation (remplacez ``2.0.8`` par le numéro de la dernière version) :
::
git fetch origin
git fetch --tags
- git checkout 2.1.0
- ./install.sh
+ git checkout 2.0.8
+ SYMFONY_ENV=prod composer install --no-dev -o --prefer-dist
+ php bin/console cache:clear --env=prod
Mise à jour sur un hébergement mutualisé
----------------------------------------
wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package
-(hash md5 de l'archive : ``4f84c725d1d6e3345eae0a406115e5ff``)
+(hash md5 de l'archive 2.0.8 : ``4f84c725d1d6e3345eae0a406115e5ff``)
Décompressez l'archive dans votre répertoire d'installation et remplacez le fichier ``app/config/parameters.yml`` avec le votre.
--- /dev/null
+Mettre à jour de la 2.0.x à la 2.1.y
+====================================
+
+.. warning::
+Avant cette migration, si vous aviez configuré l'import depuis Pocket en ajoutant votre consumer key dans les paramètres internes, pensez à effectuer une sauvegarde de celle-ci : vous devrez l'ajouter dans la configuration de wallabag après la mise à jour.
+
+Mise à jour sur un serveur dédié
+--------------------------------
+
+La dernière version de wallabag est publiée à cette adresse : https://www.wallabag.org/pages/download-wallabag.html. Pour mettre à jour votre installation de wallabag, exécutez les commandes suivantes dans votre répertoire d'installation (remplacez ``2.1.0`` par le numéro de la dernière version) :
+
+::
+
+ git fetch origin
+ git fetch --tags
+ git checkout 2.1.0
+ ASSETS=build ./install.sh
+ php bin/console doctrine:migrations:migrate --env=prod
+ php bin/console cache:clear --env=prod
+
+Mise à jour sur un hébergement mutualisé
+----------------------------------------
+
+Effectuez une sauvegarde du fichier ``app/config/parameters.yml``.
+
+Téléchargez la dernière version de wallabag :
+
+.. code-block:: bash
+
+ wget http://wllbg.org/latest-v2-package && tar xvf latest-v2-package
+
+(hash md5 de l'archive : ``4f84c725d1d6e3345eae0a406115e5ff``)
+
+Décompressez l'archive dans votre répertoire d'installation et remplacez le fichier ``app/config/parameters.yml`` avec le votre.
+
+Nous avons ajouté de nouveaux paramètres dans cette nouvelle version. Vous devez donc éditer le fichier ``app/config/parameters.yml`` en ajoutant ces lignes (et en remplaçant par votre configuration) :
+
+.. code-block:: bash
+
+ # RabbitMQ processing
+ rabbitmq_host: localhost
+ rabbitmq_port: 5672
+ rabbitmq_user: guest
+ rabbitmq_password: guest
+
+ # Redis processing
+ redis_host: localhost
+ redis_port: 6379
+
+Si vous utilisez SQLite, vous devez également conserver le contenu du répertoire ``data/``.
+
+Videz le répertoire ``var/cache``.
+
+Vous allez devoir également exécuter des requêtes SQL pour mettre à jour votre base de données. Nous partons du principe que le préfixe de vos tables est ``wallabag_`` et que le serveur SQL est un serveur MySQL :
+
+.. code-block:: sql
+
+ ALTER TABLE `wallabag_entry` ADD `uuid` LONGTEXT DEFAULT NULL;
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('share_public', '1', 'entry');
+ ALTER TABLE `wallabag_oauth2_clients` ADD name longtext COLLATE 'utf8_unicode_ci' DEFAULT NULL;
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('import_with_redis', '0', 'import');
+ INSERT INTO `wallabag_craue_config_setting` (`name`, `value`, `section`) VALUES ('import_with_rabbitmq', '0', 'import');
+ ALTER TABLE `wallabag_config` ADD `pocket_consumer_key` VARCHAR(255) DEFAULT NULL;
+ DELETE FROM `wallabag_craue_config_setting` WHERE `name` = 'pocket_consumer_key';
+
}
}
+ /**
+ * Check if an entry exist by url.
+ *
+ * @ApiDoc(
+ * parameters={
+ * {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}
+ * }
+ * )
+ *
+ * @return JsonResponse
+ */
+ public function getEntriesExistsAction(Request $request)
+ {
+ $this->validateAuthentication();
+
+ $url = $request->query->get('url', '');
+
+ if (empty($url)) {
+ throw $this->createAccessDeniedException('URL is empty?, logged user id: '.$user->getId());
+ }
+
+ $res = $this->getDoctrine()
+ ->getRepository('WallabagCoreBundle:Entry')
+ ->findByUrlAndUserId($url, $this->getUser()->getId());
+
+ $exists = false === $res ? false : true;
+
+ $json = $this->get('serializer')->serialize(['exists' => $exists], 'json');
+
+ return (new JsonResponse())->setJson($json);
+ }
+
/**
* Retrieve all entries. It could be filtered by many options.
*
$order = $request->query->get('order', 'desc');
$page = (int) $request->query->get('page', 1);
$perPage = (int) $request->query->get('perPage', 30);
- $since = $request->query->get('since', 0);
$tags = $request->query->get('tags', '');
+ $since = $request->query->get('since', 0);
$pager = $this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
$pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
$paginatedCollection = $pagerfantaFactory->createRepresentation(
$pager,
- new Route('api_get_entries', [], UrlGeneratorInterface::ABSOLUTE_URL)
+ new Route(
+ 'api_get_entries',
+ [
+ 'archive' => $isArchived,
+ 'starred' => $isStarred,
+ 'sort' => $sort,
+ 'order' => $order,
+ 'page' => $page,
+ 'perPage' => $perPage,
+ 'tags' => $tags,
+ 'since' => $since,
+ ],
+ UrlGeneratorInterface::ABSOLUTE_URL
+ )
);
$json = $this->get('serializer')->serialize($paginatedCollection, 'json');
namespace Wallabag\CoreBundle\Command;
+use FOS\UserBundle\Event\UserEvent;
+use FOS\UserBundle\FOSUserEvents;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArrayInput;
$em->persist($user);
- $config = new Config($user);
- $config->setTheme($this->getContainer()->getParameter('wallabag_core.theme'));
- $config->setItemsPerPage($this->getContainer()->getParameter('wallabag_core.items_on_page'));
- $config->setRssLimit($this->getContainer()->getParameter('wallabag_core.rss_limit'));
- $config->setReadingSpeed($this->getContainer()->getParameter('wallabag_core.reading_speed'));
- $config->setLanguage($this->getContainer()->getParameter('wallabag_core.language'));
-
- $em->persist($config);
+ // dispatch a created event so the associated config will be created
+ $event = new UserEvent($user);
+ $this->getContainer()->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
$this->defaultOutput->writeln('');
use Wallabag\CoreBundle\Entity\TaggingRule;
use Wallabag\CoreBundle\Form\Type\ConfigType;
use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
-use Wallabag\CoreBundle\Form\Type\NewUserType;
use Wallabag\CoreBundle\Form\Type\RssType;
use Wallabag\CoreBundle\Form\Type\TaggingRuleType;
use Wallabag\CoreBundle\Form\Type\UserInformationType;
// handle tagging rule
$taggingRule = new TaggingRule();
- $newTaggingRule = $this->createForm(TaggingRuleType::class, $taggingRule, ['action' => $this->generateUrl('config').'#set5']);
+ $action = $this->generateUrl('config').'#set5';
+
+ if ($request->query->has('tagging-rule')) {
+ $taggingRule = $this->getDoctrine()
+ ->getRepository('WallabagCoreBundle:TaggingRule')
+ ->find($request->query->get('tagging-rule'));
+
+ if ($this->getUser()->getId() !== $taggingRule->getConfig()->getUser()->getId()) {
+ return $this->redirect($action);
+ }
+
+ $action = $this->generateUrl('config').'?tagging-rule='.$taggingRule->getId().'#set5';
+ }
+
+ $newTaggingRule = $this->createForm(TaggingRuleType::class, $taggingRule, ['action' => $action]);
$newTaggingRule->handleRequest($request);
if ($newTaggingRule->isValid()) {
return $this->redirect($this->generateUrl('config').'#set5');
}
- // handle adding new user
- $newUser = $userManager->createUser();
- // enable created user by default
- $newUser->setEnabled(true);
- $newUserForm = $this->createForm(NewUserType::class, $newUser, [
- 'validation_groups' => ['Profile'],
- 'action' => $this->generateUrl('config').'#set6',
- ]);
- $newUserForm->handleRequest($request);
-
- if ($newUserForm->isValid() && $this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) {
- $userManager->updateUser($newUser, true);
-
- $config = new Config($newUser);
- $config->setTheme($this->getParameter('wallabag_core.theme'));
- $config->setItemsPerPage($this->getParameter('wallabag_core.items_on_page'));
- $config->setRssLimit($this->getParameter('wallabag_core.rss_limit'));
- $config->setLanguage($this->getParameter('wallabag_core.language'));
- $config->setReadingSpeed($this->getParameter('wallabag_core.reading_speed'));
-
- $em->persist($config);
-
- $em->flush();
-
- $this->get('session')->getFlashBag()->add(
- 'notice',
- $this->get('translator')->trans('flashes.config.notice.user_added', ['%username%' => $newUser->getUsername()])
- );
-
- return $this->redirect($this->generateUrl('config').'#set6');
- }
-
return $this->render('WallabagCoreBundle:Config:index.html.twig', [
'form' => [
'config' => $configForm->createView(),
'rss' => $rssForm->createView(),
'pwd' => $pwdForm->createView(),
'user' => $userForm->createView(),
- 'new_user' => $newUserForm->createView(),
'new_tagging_rule' => $newTaggingRule->createView(),
],
'rss' => [
*/
public function deleteTaggingRuleAction(TaggingRule $rule)
{
- if ($this->getUser()->getId() != $rule->getConfig()->getUser()->getId()) {
- throw $this->createAccessDeniedException('You can not access this tagging rule.');
- }
+ $this->validateRuleAction($rule);
$em = $this->getDoctrine()->getManager();
$em->remove($rule);
return $this->redirect($this->generateUrl('config').'#set5');
}
+ /**
+ * Edit a tagging rule.
+ *
+ * @param TaggingRule $rule
+ *
+ * @Route("/tagging-rule/edit/{id}", requirements={"id" = "\d+"}, name="edit_tagging_rule")
+ *
+ * @return RedirectResponse
+ */
+ public function editTaggingRuleAction(TaggingRule $rule)
+ {
+ $this->validateRuleAction($rule);
+
+ return $this->redirect($this->generateUrl('config').'?tagging-rule='.$rule->getId().'#set5');
+ }
+
+ /**
+ * Validate that a rule can be edited/deleted by the current user.
+ *
+ * @param TaggingRule $rule
+ */
+ private function validateRuleAction(TaggingRule $rule)
+ {
+ if ($this->getUser()->getId() != $rule->getConfig()->getUser()->getId()) {
+ throw $this->createAccessDeniedException('You can not access this tagging rule.');
+ }
+ }
+
/**
* Retrieve config for the current user.
* If no config were found, create a new one.
->getRepository('WallabagCoreBundle:Config')
->findOneByUser($this->getUser());
+ // should NEVER HAPPEN ...
if (!$config) {
$config = new Config($this->getUser());
}
{
$clients = $this->getDoctrine()->getRepository('WallabagApiBundle:Client')->findAll();
- return $this->render('WallabagCoreBundle:Developer:index.html.twig', [
+ return $this->render('@WallabagCore/themes/common/Developer/index.html.twig', [
'clients' => $clients,
]);
}
$this->get('translator')->trans('flashes.developer.notice.client_created', ['%name%' => $client->getName()])
);
- return $this->render('WallabagCoreBundle:Developer:client_parameters.html.twig', [
+ return $this->render('@WallabagCore/themes/common/Developer/client_parameters.html.twig', [
'client_id' => $client->getPublicId(),
'client_secret' => $client->getSecret(),
'client_name' => $client->getName(),
]);
}
- return $this->render('WallabagCoreBundle:Developer:client.html.twig', [
+ return $this->render('@WallabagCore/themes/common/Developer/client.html.twig', [
'form' => $clientForm->createView(),
]);
}
*/
public function howtoFirstAppAction()
{
- return $this->render('WallabagCoreBundle:Developer:howto_app.html.twig');
+ return $this->render('@WallabagCore/themes/common/Developer/howto_app.html.twig');
}
}
}
return $this->render(
- '@WallabagCore/themes/share.html.twig',
+ '@WallabagCore/themes/common/Entry/share.html.twig',
['entry' => $entry]
);
}
--- /dev/null
+<?php
+
+namespace Wallabag\CoreBundle\Controller;
+
+use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * This controller allow us to customize the error template.
+ * The only modified line from the parent template is for "WallabagCoreBundle".
+ */
+class ExceptionController extends BaseExceptionController
+{
+ protected function findTemplate(Request $request, $format, $code, $showException)
+ {
+ $name = $showException ? 'exception' : 'error';
+ if ($showException && 'html' == $format) {
+ $name = 'exception_full';
+ }
+
+ // For error pages, try to find a template for the specific HTTP status code and format
+ if (!$showException) {
+ $template = sprintf('WallabagCoreBundle:Exception:%s.%s.twig', $name, $format);
+ if ($this->templateExists($template)) {
+ return $template;
+ }
+ }
+
+ // try to find a template for the given format
+ $template = sprintf('@Twig/Exception/%s.%s.twig', $name, $format);
+ if ($this->templateExists($template)) {
+ return $template;
+ }
+
+ // default to a generic HTML exception
+ $request->setRequestFormat('html');
+
+ return sprintf('@Twig/Exception/%s.html.twig', $showException ? 'exception_full' : $name);
+ }
+}
$perPage = $user->getConfig()->getRssLimit() ?: $this->getParameter('wallabag_core.rss_limit');
$entries->setMaxPerPage($perPage);
- return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', [
+ return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [
'type' => $type,
'entries' => $entries,
]);
$addonsUrl = $this->container->getParameter('addons_url');
return $this->render(
- 'WallabagCoreBundle:Static:howto.html.twig',
+ '@WallabagCore/themes/common/Static/howto.html.twig',
['addonsUrl' => $addonsUrl]
);
}
public function aboutAction()
{
return $this->render(
- 'WallabagCoreBundle:Static:about.html.twig',
+ '@WallabagCore/themes/common/Static/about.html.twig',
[
'version' => $this->getParameter('wallabag_core.version'),
'paypal_url' => $this->getParameter('wallabag_core.paypal_url'),
public function quickstartAction()
{
return $this->render(
- 'WallabagCoreBundle:Static:quickstart.html.twig',
+ '@WallabagCore/themes/common/Static/quickstart.html.twig',
[]
);
}
private $footerTemplate = '<div style="text-align:center;">
<p>Produced by wallabag with %EXPORT_METHOD%</p>
<p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p>
- </div';
+ </div>';
/**
* @param Config $craueConfig CraueConfig instance to get wallabag instance url from database
$em = $this->registry->getManagerForClass($configuration->getClass());
// Check, if class name is what we need
- if ('Wallabag\UserBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) {
+ if (null !== $em && 'Wallabag\UserBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) {
return false;
}
$username = $request->attributes->get('username');
$rssToken = $request->attributes->get('token');
- // Check, if route attributes exists
- if (null === $username || null === $rssToken) {
- throw new \InvalidArgumentException('Route attribute is missing');
+ if (!$request->attributes->has('username') || !$request->attributes->has('token')) {
+ return false;
}
// Get actual entity manager for class
$qb->andWhere('e.isStarred =:isStarred')->setParameter('isStarred', (bool) $isStarred);
}
- if ($since >= 0) {
+ if ($since > 0) {
$qb->andWhere('e.updatedAt > :since')->setParameter('since', new \DateTime(date('Y-m-d H:i:s', $since)));
}
public function findByUrlAndUserId($url, $userId)
{
$res = $this->createQueryBuilder('e')
- ->where('e.url = :url')->setParameter('url', $url)
+ ->where('e.url = :url')->setParameter('url', urldecode($url))
->andWhere('e.user = :user_id')->setParameter('user_id', $userId)
->getQuery()
->getResult();
arguments:
- WallabagCoreBundle:Tag
- wallabag_core.registration_confirmed:
- class: Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener
- arguments:
- - "@doctrine.orm.entity_manager"
- - "%wallabag_core.theme%"
- - "%wallabag_core.items_on_page%"
- - "%wallabag_core.rss_limit%"
- - "%wallabag_core.language%"
- tags:
- - { name: kernel.event_subscriber }
-
wallabag_core.helper.entries_export:
class: Wallabag\CoreBundle\Helper\EntriesExport
arguments:
host: '%redis_host%'
port: '%redis_port%'
schema: tcp
+
+ wallabag_core.exception_controller:
+ class: Wallabag\CoreBundle\Controller\ExceptionController
+ arguments:
+ - '@twig'
+ - '%kernel.debug%'
search: 'Søg'
# save_link: 'Save a link'
back_to_unread: 'Tilbage til de ulæste artikler'
+ # users_management: 'Users management'
top:
add_new_entry: 'Tilføj ny artikel'
search: 'Søg'
# social: 'Social'
# powered_by: 'powered by'
about: 'Om'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Opsætning'
# if_label: 'if'
# then_tag_as_label: 'then tag as'
# delete_rule_label: 'delete'
+ # edit_rule_label: 'edit'
# rule_label: 'Rule'
# tags_label: 'Tags'
# faq:
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
- form_new_user:
- username_label: 'Brugernavn'
- password_label: 'Adgangskode'
- repeat_new_password_label: 'Gentag adgangskode'
- plain_password_label: '????'
- email_label: 'Emailadresse'
entry:
page_titles:
quickstart:
# page_title: 'Quickstart'
+ # more: 'More…'
# intro:
# title: 'Welcome to wallabag!'
# paragraph_1: "We'll accompany you to visit wallabag and show you some features which can interest you."
# paragraph_2: 'Follow us!'
# configure:
# title: 'Configure the application'
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
# language: 'Change language and design'
# rss: 'Enable RSS feeds'
# tagging_rules: 'Write rules to automatically tag your articles'
# import: 'Configure import'
# first_steps:
# title: 'First steps'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
# new_article: 'Save your first article'
# unread_articles: 'And classify it!'
# migrate:
# wallabag_v1: 'Migrate from wallabag v1'
# wallabag_v2: 'Migrate from wallabag v2'
# readability: 'Migrate from Readability'
+ # instapaper: 'Migrate from Instapaper'
# developer:
# title: 'Developers'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
# create_application: 'Create your third application'
+ # use_docker: 'Use Docker to install wallabag'
# docs:
# title: 'Full documentation'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
# annotate: 'Annotate your article'
# export: 'Convert your articles into ePUB or PDF'
# search_filters: 'See how you can look for an article by using search engine and filters'
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
# firefox:
# page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
# how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
#chrome:
# page_title: 'Import > Chrome'
# description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
# how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ # instapaper:
+ # page_title: 'Import > Instapaper'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
# page_title: 'Developer'
# page_title: 'Developer > New client'
# page_description: 'You are about to create a new client. Please fill the field below for the redirect URI of your application.'
# form:
+ # name_label: 'Name of the client'
# redirect_uris_label: 'Redirect URIs'
# save_label: 'Create a new client'
# action_back: 'Back'
# client_parameter:
# page_title: 'Developer > Client parameters'
# page_description: 'Here are your client parameters.'
+ # field_name: 'Client name'
# field_id: 'Client ID'
# field_secret: 'Client secret'
# back: 'Back'
# paragraph_8: 'If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.'
# back: 'Back'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Brugernavn'
+ # name_label: 'Name'
+ password_label: 'Adgangskode'
+ repeat_new_password_label: 'Gentag adgangskode'
+ plain_password_label: '????'
+ email_label: 'Emailadresse'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
search: 'Suche'
save_link: 'Link speichern'
back_to_unread: 'Zurück zu ungelesenen Artikeln'
+ # users_management: 'Users management'
top:
add_new_entry: 'Neuen Artikel hinzufügen'
search: 'Suche'
social: 'Soziales'
powered_by: 'angetrieben von'
about: 'Über'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Einstellungen'
if_label: 'Wenn'
then_tag_as_label: 'dann tagge als'
delete_rule_label: 'löschen'
+ # edit_rule_label: 'edit'
rule_label: 'Regel'
tags_label: 'Tags'
faq:
or: 'Eine Regel ODER die andere'
and: 'Eine Regel UND eine andere'
matches: 'Tests, ob eine <i>Variable</i> auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title matches "Fußball"</code>'
- form_new_user:
- username_label: 'Benutzername'
- password_label: 'Kennwort'
- repeat_new_password_label: 'Neues Kennwort wiederholen'
- plain_password_label: '????'
- email_label: 'E-Mail-Adresse'
entry:
page_titles:
quickstart:
page_title: 'Schnelleinstieg'
+ # more: 'More…'
intro:
title: 'Willkommen zu wallabag!'
paragraph_1: "Wir werden dich bei der Benutzung von wallabag begleiten und dir einige Funktionen zeigen, die dich interessieren könnten."
paragraph_2: 'Folge uns!'
configure:
title: 'Anwendung konfigurieren'
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: 'Sprache und Design ändern'
rss: 'RSS-Feeds aktivieren'
tagging_rules: 'Schreibe Regeln, um deine Beiträge automatisch zu taggen (verschlagworten)'
import: 'Import-Einstellungen ändern'
first_steps:
title: 'Erste Schritte'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link"
new_article: 'Speichere deinen ersten Artikel'
unread_articles: 'Und klassifiziere ihn!'
migrate:
wallabag_v1: 'von wallabag v1 migrieren'
wallabag_v2: 'von wallabag v2 migrieren'
readability: 'von Readability migrieren'
+ instapaper: 'von Instapaper migrieren'
developer:
title: 'Entwickler'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'Erstelle eine Anwendung und nutze die wallabag API'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'Komplette Dokumentation'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'Anmerkungen zu Artikeln hinzufügen'
export: 'Artikel nach ePUB oder PDF konvertieren'
search_filters: 'Schau nach, wie du nach einem Artikel über die Such- und Filterfunktion suchen kannst'
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.'
readability:
page_title: 'Aus Readability importieren'
- # 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).'
- # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
+ # 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).'
+ # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
worker:
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
- # firefox:
- # page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
- # chrome:
- # page_title: 'Import > Chrome'
- # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ firefox:
+ page_title: 'Aus Firefox importieren'
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ chrome:
+ page_title: 'Aus Chrome importieren'
+ # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ instapaper:
+ page_title: 'Aus Instapaper importieren'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
page_title: 'Entwickler'
page_title: 'Entwickler > Neuer Client'
page_description: 'Du bist dabei, einen neuen Client zu erstellen. Fülle das nachfolgende Feld für die Weiterleitungs-URIs deiner Anwendung aus.'
form:
+ # name_label: 'Name of the client'
redirect_uris_label: 'Weiterleitungs-URIs'
save_label: 'Neuen Client erstellen'
action_back: 'Zurück'
client_parameter:
page_title: 'Entwickler > Client-Parameter'
page_description: 'Dies sind deine Client-Parameter.'
+ # field_name: 'Client name'
field_id: 'Client-ID'
field_secret: 'Client-Secret'
back: 'Zurück'
paragraph_8: 'Wenn du alle API-Endpunkte sehen willst, werfe einen Blick auf die <a href="%link%">API-Dokumentation</a>.'
back: 'Zurück'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Benutzername'
+ # name_label: 'Name'
+ password_label: 'Kennwort'
+ repeat_new_password_label: 'Neues Kennwort wiederholen'
+ plain_password_label: '????'
+ email_label: 'E-Mail-Adresse'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
search: 'Search'
save_link: 'Save a link'
back_to_unread: 'Back to unread articles'
+ users_management: 'Users management'
top:
add_new_entry: 'Add a new entry'
search: 'Search'
social: 'Social'
powered_by: 'powered by'
about: 'About'
+ stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Config'
if_label: 'if'
then_tag_as_label: 'then tag as'
delete_rule_label: 'delete'
+ edit_rule_label: 'edit'
rule_label: 'Rule'
tags_label: 'Tags'
faq:
or: 'One rule OR another'
and: 'One rule AND another'
matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
- form_new_user:
- username_label: 'Username'
- password_label: 'Password'
- repeat_new_password_label: 'Repeat new password'
- plain_password_label: '????'
- email_label: 'Email'
entry:
page_titles:
quickstart:
page_title: 'Quickstart'
+ more: 'More…'
intro:
title: 'Welcome to wallabag!'
paragraph_1: "We'll accompany you on your visit to wallabag and show you some features that might interest you."
paragraph_2: 'Follow us!'
configure:
title: 'Configure the application'
+ description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: 'Change language and design'
rss: 'Enable RSS feeds'
tagging_rules: 'Write rules to automatically tag your articles'
import: 'Configure import'
first_steps:
title: 'First steps'
+ description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
new_article: 'Save your first article'
unread_articles: 'And classify it!'
migrate:
wallabag_v1: 'Migrate from wallabag v1'
wallabag_v2: 'Migrate from wallabag v2'
readability: 'Migrate from Readability'
+ instapaper: 'Migrate from Instapaper'
developer:
title: 'Developers'
+ description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'Create your third application'
+ use_docker: 'Use Docker to install wallabag'
docs:
title: 'Full documentation'
+ description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'Annotate your article'
export: 'Convert your articles into ePUB or PDF'
search_filters: 'See how you can look for an article by using the search engine and filters'
enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
firefox:
page_title: 'Import > Firefox'
- description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
chrome:
page_title: 'Import > Chrome'
description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ instapaper:
+ page_title: 'Import > Instapaper'
+ description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
page_title: 'Developer'
paragraph_8: 'If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.'
back: 'Back'
+user:
+ page_title: Users management
+ new_user: Create a new user
+ edit_user: Edit an existing user
+ description: "Here you can manage all users (create, edit and delete)"
+ list:
+ actions: Actions
+ edit_action: Edit
+ yes: Yes
+ no: No
+ create_new_one: Create a new user
+ form:
+ username_label: 'Username'
+ name_label: 'Name'
+ password_label: 'Password'
+ repeat_new_password_label: 'Repeat new password'
+ plain_password_label: '????'
+ email_label: 'Email'
+ enabled_label: 'Enabled'
+ locked_label: 'Locked'
+ last_login_label: 'Last login'
+ twofactor_label: Two factor authentication
+ save: Save
+ delete: Delete
+ delete_confirm: Are you sure?
+ back_to_list: Back to list
+
flashes:
config:
notice:
rss_updated: 'RSS information updated'
tagging_rules_updated: 'Tagging rules updated'
tagging_rules_deleted: 'Tagging rule deleted'
- user_added: 'User "%username%" added'
rss_token_updated: 'RSS token updated'
entry:
notice:
notice:
client_created: 'New client %name% created.'
client_deleted: 'Client %name% deleted'
+ user:
+ notice:
+ added: 'User "%username%" added'
+ updated: 'User "%username%" updated'
+ deleted: 'User "%username%" deleted'
search: 'Buscar'
save_link: 'Archivar un enlace'
back_to_unread: 'Volver a los artículos sin leer'
+ # users_management: 'Users management'
top:
add_new_entry: 'Añadir un nuevo artículo'
search: 'Buscar'
social: 'Social'
powered_by: 'funciona por'
about: 'Acerca de'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Configuración'
if_label: 'si'
then_tag_as_label: 'Etiquete como'
delete_rule_label: 'Borre'
+ # edit_rule_label: 'edit'
rule_label: 'Regla'
tags_label: 'Etiquetas'
faq:
or: 'Una regla U otra'
and: 'Una regla Y la otra'
matches: 'Pruebe si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>título coincide "football"</code>'
- form_new_user:
- username_label: 'Nombre de usuario'
- password_label: 'Contraseña'
- repeat_new_password_label: 'Confirmar la nueva contraseña'
- plain_password_label: '????'
- email_label: 'Email'
entry:
page_titles:
quickstart:
page_title: 'Comienzo rápido'
+ # more: 'More…'
intro:
title: 'Bienvenido a wallabag !'
paragraph_1: "Le acompañaremos a su visita de wallabag y le mostraremos algunas características que le pueden interesar."
paragraph_2: '¡Síganos!'
configure:
title: 'Configure la aplicación'
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: 'Cambie el idioma y el diseño de la aplicación'
rss: 'Activar los feeds RSS'
tagging_rules: 'Escribir reglas para etiquetear automaticamente sus artículos'
import: 'Configure importación'
first_steps:
title: 'Primeros pasos'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
new_article: 'Guarde su primer artículo'
unread_articles: '¡Y clasifíquelo!'
migrate:
wallabag_v1: 'Migrar desde wallabag v1'
wallabag_v2: 'Migrar desde wallabag v2'
readability: 'Migrar desde Readability'
+ instapaper: 'Migrar desde Instapaper'
developer:
title: 'Promotores'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'Cree su tercera aplicación'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'Documentación completa'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'Anote su artículo'
export: 'Convierta sus artículos a ePub o a PDF'
search_filters: 'Aprenda a utilizar el buscador y los filtros para encontrar el artículo que le interese'
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"'
readability:
page_title: 'Importar > Readability'
- # 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).'
- # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
+ # 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).'
+ # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
worker:
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
- # firefox:
- # page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
- # chrome:
- # page_title: 'Import > Chrome'
- # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ firefox:
+ page_title: 'Importar > Firefox'
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ chrome:
+ page_title: 'Importar > Chrome'
+ # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ instapaper:
+ page_title: 'Importar > Instapaper'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
page_title: 'Promotor'
page_title: 'Promotor > Nuevo cliente'
page_description: 'Va a crear un nuevo cliente. Por favor, llene el campo abajo para URI redirigido de su aplicación.'
form:
+ # name_label: 'Name of the client'
redirect_uris_label: 'los URI redirigidos'
save_label: 'Crear un nuevo cliente'
action_back: 'Atrás'
client_parameter:
page_title: 'Promotor > Parámetros del cliente'
page_description: 'Aquí hay sus parámetros del cliente.'
+ # field_name: 'Client name'
field_id: 'Identificación del cliente'
field_secret: 'Cliente secreto'
back: 'Atrás'
paragraph_8: 'Si quiere ver todos los fines de API, se puede ver <a href="%link%">a nuestra documentación API</a>.'
back: 'Atrás'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Nombre de usuario'
+ # name_label: 'Name'
+ password_label: 'Contraseña'
+ repeat_new_password_label: 'Confirmar la nueva contraseña'
+ plain_password_label: '????'
+ email_label: 'Email'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
search: 'جستجو'
save_link: 'ذخیرهٔ یک پیوند'
back_to_unread: 'بازگشت به خواندهنشدهها'
+ # users_management: 'Users management'
top:
add_new_entry: 'افزودن مقالهٔ تازه'
search: 'جستجو'
social: 'شبکههای اجتماعی'
powered_by: 'توانمند با'
about: 'درباره'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'پیکربندی'
if_label: 'اگر'
then_tag_as_label: 'این برچسب را بزن'
delete_rule_label: 'پاک کن'
+ # edit_rule_label: 'edit'
rule_label: 'قانون'
tags_label: 'برچسبها'
faq:
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
- form_new_user:
- username_label: 'نام کاربری'
- password_label: 'رمز'
- repeat_new_password_label: 'رمز تازه را دوباره بنویسید'
- plain_password_label: '????'
- email_label: 'نشانی ایمیل'
entry:
page_titles:
quickstart:
page_title: 'Quickstart'
+ # more: 'More…'
intro:
title: 'به wallabag خوش آمدید!!'
paragraph_1: "به شما کمک خواهیم کرد تا wallabag را بشناسید و با برخی از ویژگیهای جالبش آشنا شوید"
import: 'درونریزی را تنظیم کنید'
first_steps:
title: 'گام نخست'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
new_article: 'نخستین مقالهٔ خود را ذخیره کنید'
unread_articles: 'و آن را طبقهبندی کنید!'
migrate:
wallabag_v1: 'مهاجرت از نسخهٔ یکم wallabag'
wallabag_v2: 'مهاجرت از نسخهٔ دوم wallabag'
readability: 'مهاجرت از نسخهٔ دوم Readability'
+ instapaper: 'مهاجرت از نسخهٔ دوم Instapaper'
developer:
title: 'برنامهنویسان'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'برنامهٔ wallabag خود را بسازید'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'راهنمای کامل'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'روی مقالههایتان یادداشت بگذارید'
export: 'مقالههایتان را به قالب ePUB یا PDF دربیاورید'
search_filters: 'به کمک موتور جستجو و فیلترها به دنبال مقالههایتان بگردید'
# how_to: 'Please select your Readability export and click on the below button to upload and import it.'
worker:
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
- # firefox:
- # page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
- # chrome:
- # page_title: 'Import > Chrome'
- # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ firefox:
+ page_title: 'درونریزی > Firefox'
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ chrome:
+ page_title: 'درونریزی > Chrome'
+ # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ instapaper:
+ page_title: 'درونریزی > Instapaper'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
# page_title: 'Developer'
# page_title: 'Developer > New client'
# page_description: 'You are about to create a new client. Please fill the field below for the redirect URI of your application.'
# form:
+ # name_label: 'Name of the client'
# redirect_uris_label: 'Redirect URIs'
# save_label: 'Create a new client'
# action_back: 'بازگشت'
# client_parameter:
# page_title: 'Developer > Client parameters'
# page_description: 'Here are your client parameters.'
+ # field_name: 'Client name'
# field_id: 'Client ID'
# field_secret: 'Client secret'
# back: 'بازگشت'
# paragraph_8: 'If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.'
# back: 'بازگشت'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'نام کاربری'
+ # name_label: 'Name'
+ password_label: 'رمز'
+ repeat_new_password_label: 'رمز تازه را دوباره بنویسید'
+ plain_password_label: '????'
+ email_label: 'نشانی ایمیل'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
search: 'Recherche'
save_link: 'Sauvegarder un nouvel article'
back_to_unread: 'Retour aux articles non lus'
+ users_management: 'Gestion des utilisateurs'
top:
add_new_entry: 'Sauvegarder un nouvel article'
search: 'Rechercher'
social: 'Social'
powered_by: 'propulsé par'
about: 'À propos'
- page_title: 'Configuration'
+ stats: Depuis le %user_creation% vous avez lu %nb_archives% articles. Ce qui fait %per_day% par jour !
config:
+ page_title: 'Configuration'
tab_menu:
settings: 'Paramètres'
rss: 'RSS'
if_label: 'si'
then_tag_as_label: 'alors attribuer les tags'
delete_rule_label: 'supprimer'
+ edit_rule_label: 'éditer'
rule_label: 'Règle'
tags_label: 'Tags'
faq:
or: "Une règle OU l'autre"
and: "Une règle ET l'autre"
matches: 'Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches "football"</code>'
- form_new_user:
- username_label: "Nom d'utilisateur"
- password_label: 'Mot de passe'
- repeat_new_password_label: 'Confirmez votre nouveau mot de passe'
- plain_password_label: 'Mot de passe en clair'
- email_label: 'Adresse e-mail'
entry:
page_titles:
quickstart:
page_title: 'Pour bien débuter'
+ more: 'Et plus encore…'
intro:
title: 'Bienvenue sur wallabag !'
paragraph_1: "Nous allons vous accompagner pour vous faire faire le tour de la maison et vous présenter quelques fonctionnalités qui pourraient vous intéresser pour vous approprier cet outil."
paragraph_2: 'Suivez-nous !'
configure:
title: "Configurez l'application"
+ description: 'Pour voir une application qui vous correspond, allez voir du côté de la configuration de wallabag.'
language: "Changez la langue et le design de l'application"
rss: 'Activez les flux RSS'
tagging_rules: 'Écrivez des règles pour classer automatiquement vos articles'
import: "Configurer l'import"
first_steps:
title: 'Premiers pas'
+ description: "Maintenant que wallabag est bien configuré, il est temps d'archiver le web. Vous pouvez cliquer sur le signe + dans le coin en haut à droite."
new_article: 'Ajoutez votre premier article'
unread_articles: 'Et rangez-le !'
migrate:
wallabag_v1: 'Migrer depuis wallabag v1'
wallabag_v2: 'Migrer depuis wallabag v2'
readability: 'Migrer depuis Readability'
+ instapaper: 'Migrer depuis Instapaper'
developer:
title: 'Pour les développeurs'
+ description: 'Nous avons aussi pensé aux développeurs : Docker, API, traductions, etc.'
create_application: 'Créer votre application tierce'
+ use_docker: 'Utiliser Docker pour installer wallabag'
docs:
title: 'Documentation complète'
+ description: "Il y a tellement de fonctionnalités dans wallabag. N'hésitez pas à lire le manuel pour les connaitre et apprendre comment les utiliser."
annotate: 'Annoter votre article'
export: 'Convertissez vos articles en ePub ou en PDF'
search_filters: "Apprenez à utiliser le moteur de recherche et les filtres pour retrouver l'article qui vous intéresse"
enabled: "Les imports sont asynchrones. Une fois l'import commencé un worker externe traitera les messages un par un. Le service activé est :"
firefox:
page_title: 'Import > Firefox'
- description: "Cet outil va vous permettre d'importer tous vos marques-pages de Firefox. <p>Pour Firefox, ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json. </p>"
+ description: "Cet outil va vous permettre d'importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json. </p>"
how_to: "Choisissez le fichier de sauvegarde de vos marques-page et cliquez sur le bouton pour l'importer. Soyez avertis que le processus peut prendre un temps assez long car tous les articles doivent être récupérés en ligne."
chrome:
page_title: 'Import > Chrome'
description: "Cet outil va vous permettre d'importer tous vos marques-pages de Google Chrome/Chromium. Pour Google Chrome, la situation du fichier dépend de votre système d'exploitation : <ul><li>Sur GNU/Linux, allez dans le répertoire <code>~/.config/google-chrome/Default/</code></li><li>Sous Windows, il devrait se trouver à <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>Sur OS X, il devrait se trouver dans le fichier <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Une fois que vous y êtes, copiez le fichier Bookmarks à un endroit où vous le retrouverez.<em><br>Notez que si vous utilisez Chromium à la place de Chrome, vous devez corriger les chemins en conséquence.</em></p>"
how_to: "Choisissez le fichier de sauvegarde de vos marques-page et cliquez sur le bouton pour l'importer. Soyez avertis que le processus peut prendre un temps assez long car tous les articles doivent être récupérés en ligne."
+ instapaper:
+ page_title: 'Import > Instapaper'
+ description: 'Sur la page des paramètres (`https://www.instapaper.com/user<https://www.instapaper.com/user>`_), cliquez sur "Download .CSV file" dans la section "Export". Un fichier CSV se téléchargera ("instapaper-export.csv").'
+ how_to: "Choisissez le fichier de votre export Instapaper et cliquez sur le bouton ci-dessous pour l'importer."
developer:
page_title: 'Développeur'
paragraph_8: "Si vous voulez toutes les méthodes de l'API, jetez un oeil <a href=\"%link%\">à la documentation de l'API</a>."
back: 'Retour'
+user:
+ page_title: Gestion des utilisateurs
+ new_user: Créer un nouvel utilisateur
+ edit_user: Éditer un utilisateur existant
+ description: Ici vous pouvez gérer vos utilisateurs (création, mise à jour et suppression)
+ list:
+ actions: Actions
+ edit_action: Éditer
+ yes: Oui
+ no: Non
+ create_new_one: Créer un nouvel utilisateur
+ form:
+ username_label: "Nom d'utilisateur"
+ name_label: 'Nom'
+ password_label: 'Mot de passe'
+ repeat_new_password_label: 'Confirmez votre nouveau mot de passe'
+ plain_password_label: 'Mot de passe en clair'
+ email_label: 'Adresse e-mail'
+ enabled_label: 'Activé'
+ locked_label: 'Bloqué'
+ last_login_label: 'Dernière connexion'
+ twofactor_label: Double authentification
+ save: Sauvegarder
+ delete: Supprimer
+ delete_confirm: Êtes-vous sûr?
+ back_to_list: Revenir à la liste
+
flashes:
config:
notice:
search: 'Cerca'
save_link: 'Salva collegamento'
back_to_unread: 'Torna ai contenuti non letti'
+ # users_management: 'Users management'
top:
add_new_entry: 'Aggiungi un nuovo contenuto'
search: 'Cerca'
social: 'Social'
powered_by: 'powered by'
about: 'About'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Configurazione'
if_label: 'se'
then_tag_as_label: 'allora tagga come'
delete_rule_label: 'elimina'
+ # edit_rule_label: 'edit'
rule_label: 'Regola'
tags_label: 'Tag'
faq:
or: "Una regola O un'altra"
and: "Una regola E un'altra"
matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>'
- form_new_user:
- username_label: 'Username'
- password_label: 'Password'
- repeat_new_password_label: 'Ripeti password'
- plain_password_label: '????'
- email_label: 'E-mail'
entry:
page_titles:
status_label: 'Stato'
archived_label: 'Archiviati'
starred_label: 'Preferiti'
+ # unread_label: 'Unread'
preview_picture_label: "Ha un'immagine di anteprima"
preview_picture_help: 'Immagine di anteprima'
language_label: 'Lingua'
quickstart:
page_title: 'Introduzione'
+ # more: 'More…'
intro:
title: 'Benvenuto su wallabag!'
paragraph_1: "Un tour in cui ti guideremo per scoprire e che ti mostrerà delle funzionalità che potrebbero interessarti."
paragraph_2: 'Seguici!'
configure:
title: "Configura l'applicazione"
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: 'Cambia lingua e design'
rss: 'Abilita i feed RSS'
tagging_rules: 'Scrivi delle regole per taggare automaticamente i contenuti'
import: "Configura l'importazione"
first_steps:
title: 'Pimi passi'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
new_article: 'Salva il tuo primo contenuto'
unread_articles: 'E classificalo!'
migrate:
wallabag_v1: 'Trasferisci da wallabag v1'
wallabag_v2: 'Trasferisci da wallabag v2'
readability: 'Trasferisci da Readability'
+ instapaper: 'Trasferisci da Instapaper'
developer:
title: 'Sviluppatori'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'Crea la tua applicazione'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'Documentazione completa'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'Annota il tuo contenuto'
export: 'Converti i tuoi contenuti in EPUB o PDF'
search_filters: 'Impara come puoi recuperare un contenuto tramite la ricerca e i filtri'
# how_to: 'Please select your Readability export and click on the below button to upload and import it.'
worker:
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
- # firefox:
- # page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
- # chrome:
- # page_title: 'Import > Chrome'
- # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ firefox:
+ page_title: 'Importa da > Firefox'
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ chrome:
+ page_title: 'Importa da > Chrome'
+ # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ instapaper:
+ page_title: 'Importa da > Instapaper'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
page_title: 'Sviluppatori'
page_title: 'Sviluppatori > Nuovo client'
page_description: 'Stai per creare un nuovo client. Compila i campi sottostanti per il redirect URI della tua applicazione.'
form:
+ # name_label: 'Name of the client'
redirect_uris_label: 'Redirect URI'
save_label: 'Crea un nuovo client'
action_back: 'Indietro'
client_parameter:
page_title: 'Sviluppatori > parametri Client'
page_description: 'Questi sono i tuoi parametri del client.'
+ # field_name: 'Client name'
field_id: 'Client ID'
field_secret: 'Client secret'
back: 'Indietro'
paragraph_8: 'Se vuoi visualizzare tutti gli API endpoints, dai una occhiata alla <a href="%link%">documentazione delle API</a>.'
back: 'Indietro'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Username'
+ # name_label: 'Name'
+ password_label: 'Password'
+ repeat_new_password_label: 'Ripeti password'
+ plain_password_label: '????'
+ email_label: 'E-mail'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
unread: 'Pas legits'
starred: 'Favorits'
archive: 'Legits'
- all_articles: 'Tots los articles'
+ all_articles: 'Totes los articles'
config: 'Configuracion'
tags: 'Etiquetas'
internal_settings: 'Configuracion interna'
import: 'Importar'
howto: 'Ajuda'
developer: 'Desvolopador'
- logout: 'Déconnexion'
+ logout: 'Desconnexion'
about: 'A prepaus'
search: 'Cercar'
save_link: 'Enregistrar un novèl article'
back_to_unread: 'Tornar als articles pas legits'
+ # users_management: 'Users management'
top:
add_new_entry: 'Enregistrar un novèl article'
search: 'Cercar'
social: 'Social'
powered_by: 'propulsat per'
about: 'A prepaus'
- page_title: 'Configuracion'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
+ page_title: 'Configuracion'
tab_menu:
settings: 'Paramètres'
rss: 'RSS'
form_rss:
description: "Los fluxes RSS fornits per wallabag vos permeton de legir vòstres articles salvagardats dins vòstre lector de fluxes preferit. Per los poder emplegar, vos cal, d'en primièr crear un geton."
token_label: 'Geton RSS'
- no_token: 'Aucun jeton généré'
- token_create: 'Pas cap de geton generat'
+ no_token: 'Pas cap de geton generat'
+ token_create: 'Creatz vòstre geton'
token_reset: 'Reïnicializatz vòstre geton'
rss_links: 'URL de vòstres fluxes RSS'
rss_link:
if_label: 'se'
then_tag_as_label: 'alara atribuir las etiquetas'
delete_rule_label: 'suprimir'
+ # edit_rule_label: 'edit'
rule_label: 'Règla'
tags_label: 'Etiquetas'
faq:
or: "Una règla O l'autra"
and: "Una règla E l'autra"
matches: 'Teste se un <i>subjècte</i> correspond a una <i>recerca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>'
- form_new_user:
- username_label: "Nom d'utilizaire"
- password_label: 'Senhal'
- repeat_new_password_label: 'Confirmatz vòstre novèl senhal'
- plain_password_label: 'Senhal en clar'
- email_label: 'Adreça de corrièl'
entry:
page_titles:
re_fetch_content: 'Tornar cargar lo contengut'
delete: 'Suprimir'
add_a_tag: 'Ajustar una etiqueta'
- share_content: 'Partatjar'
+ share_content: 'Partejar'
share_email_label: 'Corrièl'
public_link: 'ligam public'
delete_public_link: 'suprimir lo ligam public'
developped_by: 'Desvolopat per'
website: 'Site web'
many_contributors: 'E un fum de contributors ♥ <a href="https://github.com/wallabag/wallabag/graphs/contributors">sur Github</a>'
- project_website: 'Site web del projète'
+ project_website: 'Site web del projècte'
license: 'Licéncia'
version: 'Version'
getting_help:
howto:
page_title: 'Ajuda'
- page_description: "I a mai d'un biai d'enregistrar un article :"
+ page_description: "I a mai d'un biais d'enregistrar un article :"
top_menu:
browser_addons: 'Extensions de navigator'
mobile_apps: 'Aplicacions mobil'
quickstart:
page_title: 'Per ben començar'
+ # more: 'More…'
intro:
title: 'Benvenguda sus wallabag !'
paragraph_1: "Anem vos guidar per far lo torn de la proprietat e vos presentar unas fonccionalitats que vos poirián interessar per vos apropriar aquesta aisina."
paragraph_2: 'Seguètz-nos '
configure:
title: "Configuratz l'aplicacio"
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: "Cambiatz la lenga e l'estil de l'aplicacion"
rss: 'Activatz los fluxes RSS'
tagging_rules: 'Escrivètz de règlas per classar automaticament vòstres articles'
import: 'Configurar los impòrt'
first_steps:
title: 'Primièrs passes'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
new_article: 'Ajustatz vòstre primièr article'
unread_articles: 'E racaptatz-lo !'
migrate:
wallabag_v1: 'Migrar dempuèi wallabag v1'
wallabag_v2: 'Migrar dempuèi wallabag v2'
readability: 'Migrar dempuèi Readability'
+ instapaper: 'Migrar dempuèi Instapaper'
developer:
title: 'Pels desvolopadors'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'Crear vòstra aplicacion tèrça'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'Documentacion complèta'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'Anotatar vòstre article'
export: 'Convertissètz vòstres articles en ePub o en PDF'
search_filters: "Aprenètz a utilizar lo motor de recèrca e los filtres per retrobar l'article que vos interèssa"
page_title: 'Importar > Wallabag v2'
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\""
readability:
- page_title: 'Importer > Readability'
+ page_title: 'Importar > Readability'
description: "Aquesta aisina importarà totas vòstres articles de Readability. Sus la pagina de l'aisina (https://www.readability.com/tools/), clicatz sus \"Export your data\" dins la seccion \"Data Export\". Recebretz un corrièl per telecargar un json (qu'acaba pas amb un .json de fach)."
how_to: "Mercés de seleccionar vòstre Readability fichièr e de clicar sul boton dejós per lo telecargar e l'importar."
worker:
- # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
- # firefox:
- # page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
- # chrome:
- # page_title: 'Import > Chrome'
- # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ enabled: "L'importacion se fa de manièra asincròna. Un còp l'importacion lançada, una aisina externa s'ocuparà dels messatges un per un. Lo servici actual es : "
+ firefox:
+ page_title: 'Importar > Firefox'
+ description: "Aquesta aisina importarà totas vòstres favorits de Firefox. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ how_to: "Mercés de causir lo fichièr de salvagarda e de clicar sul boton dejós per l'importar. Notatz que lo tractament pòt durar un moment ja que totes los articles an d'èsser recuperats."
+ chrome:
+ page_title: 'Importar > Chrome'
+ description: "Aquesta aisina importarà totas vòstres favorits de Chrome. L'emplaçament del fichièr depend de vòstre sistèma operatiu : <ul><li>Sus Linux, anatz al dorsièr <code>~/.config/chromium/Default/</code></li><li>Sus Windows, deu èsser dins <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>sus OS X, deu èsser dins <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Un còp enlà, copiatz lo fichièr de favorits dins un endrech que volètz.<em><br>Notatz que s'avètz Chromium al lòc de Chrome, vos cal cambiar lo camin segon aquesta situacion.</em></p>"
+ how_to: "Mercés de causir lo fichièr de salvagarda e de clicar sul boton dejós per l'importar. Notatz que lo tractament pòt durar un moment ja que totes los articles an d'èsser recuperats."
+ instapaper:
+ page_title: 'Importar > Instapaper'
+ description: "Aquesta aisina importarà totas vòstres articles d'Instapaper. Sus la pagina de paramètres (https://www.instapaper.com/user), clicatz sus \"Download .CSV file\" dins la seccion \"Export\". Un fichièr CSV serà telecargat (aital \"instapaper-export.csv\")."
+ how_to: "Mercés de causir vòstre fichièr Instapaper e de clicar sul boton dejós per lo telecargar e l'importar"
developer:
- page_title: 'Desvolopador'
+ page_title: 'Desvolopaire'
welcome_message: "Benvenguda sus l'API de wallabag"
documentation: 'Documentacion'
how_to_first_app: 'Cossí crear vòstra primièra aplicacion'
page_title: 'Desvlopador > Novèl client'
page_description: "Anatz crear un novèl client. Mercés de cumplir l'url de redireccion cap a vòstra aplicacion."
form:
+ name_label: "Nom del client"
redirect_uris_label: 'URLs de redireccion'
save_label: 'Crear un novèl client'
action_back: 'Retorn'
client_parameter:
page_title: 'Desvolopador > Los paramètres de vòstre client'
page_description: 'Vaquí los paramètres de vòstre client'
+ field_name: 'Nom del client'
field_id: 'ID Client'
field_secret: 'Clau secreta'
back: 'Retour'
- read_howto: 'Legir \"cossí crear ma primièra aplicacion\"'
+ read_howto: 'Legir "cossí crear ma primièra aplicacion"'
howto:
page_title: 'Desvolopador > Cossí crear ma primièra aplicacion'
description:
paragraph_8: "Se volètz totas las adreças d'accès de l'API, donatz un còp d’uèlh <a href=\"%link%\">a la documentacion de l'API</a>."
back: 'Retorn'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: "Nom d'utilizaire"
+ # name_label: 'Name'
+ password_label: 'Senhal'
+ repeat_new_password_label: 'Confirmatz vòstre novèl senhal'
+ plain_password_label: 'Senhal en clar'
+ email_label: 'Adreça de corrièl'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
notice:
entry_already_saved: 'Article ja salvargardat lo %date%'
entry_saved: 'Article enregistrat'
- # entry_saved_failed: 'Entry saved but fetching content failed'
+ entry_saved_failed: 'Article salvat mai fracàs de la recuperacion del contengut'
entry_updated: 'Article mes a jorn'
entry_reloaded: 'Article recargat'
- # entry_reload_failed: 'Entry reloaded but fetching content failed'
+ entry_reload_failed: "L'article es estat cargat de nòu mai la recuperacion del contengut a fracassat"
entry_archived: 'Article marcat coma legit'
entry_unarchived: 'Article marcat coma pas legit'
entry_starred: 'Article apondut dins los favorits'
failed: "L'importacion a fracassat, mercés de tornar ensajar"
failed_on_file: "Errorr pendent du tractament de l'import. Mercés de verificar vòstre fichièr."
summary: "Rapòrt d'import: %imported% importats, %skipped% ja presents."
- # summary_with_queue: 'Import summary: %queued% queued.'
+ summary_with_queue: "Rapòrt d'import : %queued% en espèra de tractament."
error:
- # redis_enabled_not_installed: Redis is enabled for handle asynchronous import but it looks like <u>we can't connect to it</u>. Please check Redis configuration.
- # rabbit_enabled_not_installed: RabbitMQ is enabled for handle asynchronous import but it looks like <u>we can't connect to it</u>. Please check RabbitMQ configuration.
+ redis_enabled_not_installed: "Redis es capable d'importar de manièra asincròna mai sembla que <u>podèm pas nos conectar amb el</u>. Mercés de verificar la configuracion de Redis."
+ rabbit_enabled_not_installed: "RabbitMQ es capable d'importar de manièra asincròna mai sembla que <u>podèm pas nos conectar amb el</u>. Mercés de verificar la configuracion de RabbitMQ."
developer:
notice:
client_created: 'Novèl client creat'
search: 'Szukaj'
save_link: 'Zapisz link'
back_to_unread: 'Powrót do nieprzeczytanych artykułów'
+ # users_management: 'Users management'
top:
add_new_entry: 'Dodaj nowy wpis'
search: 'Szukaj'
social: 'Społeczność'
powered_by: 'Kontrolowany przez'
about: 'O nas'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Konfiguracja'
if_label: 'jeżeli'
then_tag_as_label: 'wtedy otaguj jako'
delete_rule_label: 'usuń'
+ # edit_rule_label: 'edit'
rule_label: 'Reguła'
tags_label: 'Tagi'
faq:
or: 'Jedna reguła LUB inna'
and: 'Jedna reguła I inna'
matches: 'Sprawdź czy <i>temat</i> pasuje <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł zawiera "piłka nożna"</code>'
- form_new_user:
- username_label: 'Nazwa użytkownika'
- password_label: 'Hasło'
- repeat_new_password_label: 'Powtórz nowe hasło'
- plain_password_label: 'Jawne hasło'
- email_label: 'Adres email'
entry:
page_titles:
quickstart:
page_title: 'Szybki start'
+ # more: 'More…'
intro:
title: 'Witaj w wallabag!'
paragraph_1: "Będziemy ci towarzyszyli w Twojej poznaniu wallabag i pokażemy możliwości, które mogą cię zainteresować."
paragraph_2: 'Śledź nas!'
configure:
title: 'Konfiguruj aplikację'
+ description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: 'Zmień język i wygląd'
rss: 'Włącz kanały RSS'
tagging_rules: 'Napisz reguły pozwalające na automatyczne otagowanie twoich artykułów'
import: 'Skonfigurować import'
first_steps:
title: 'Pierwsze kroki'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link"
new_article: 'Zapisz swój pierwszy artukuł'
unread_articles: 'I sklasyfikuj go!'
migrate:
wallabag_v1: 'Migruj z wallabag v1'
wallabag_v2: 'Migruj z wallabag v2'
readability: 'Migruj z Readability'
+ instapaper: 'Migruj z Instapaper'
developer:
title: 'Deweloperzy'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
create_application: 'Stwórz swoją aplikację'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'Pełna Dokumentacja'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
annotate: 'Dadaj adnotację do swojego artykułu'
export: 'Konwertuj swoje artykuły do ePUB lub PDF'
search_filters: 'Zabacz jak możesz znaleźć artykuł dzięku użyciu silnika wyszukiwarki i filtrów'
enabled: "Import jest wykonywany asynchronicznie. Od momentu rozpoczęcia importu, zewnętrzna usługa może zajmować się na raz tylko jednym zadaniem. Bieżącą usługą jest:"
firefox:
page_title: 'Import > Firefox'
- description: "Ten importer zaimportuje wszystkie twoje zakładki z Firefoksa. <p>Dla Firefoksa, idź do twoich zakładek (Ctrl+Shift+O), następnie w \"Import i kopie zapasowe\", wybierz \"Utwórz kopię zapasową...\". Uzyskasz plik .json."
+ description: "Ten importer zaimportuje wszystkie twoje zakładki z Firefoksa. Idź do twoich zakładek (Ctrl+Shift+O), następnie w \"Import i kopie zapasowe\", wybierz \"Utwórz kopię zapasową...\". Uzyskasz plik .json."
how_to: "Wybierz swój plik z zakładkami i naciśnij poniższy przycisk, aby je zaimportować. Może to zająć dłuższą chwilę, zanim wszystkie artykuły zostaną przeniesione."
chrome:
page_title: 'Import > Chrome'
description: "Ten importer zaimportuje wszystkie twoje zakładki z Chrome. Lokalizacja pliku jest zależna od twojego systemy operacyjnego : <ul><li>Pod Linuksem, idź do katalogu <code>~/.config/chromium/Default/</code></li><li>Pod Windowsem, powinien się on znajdować w <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>Pod OS X, powinien się on znajdować w <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Po odnalezieniu pliku, skopiuj go w łatwo dostęne miejsce.<em><br>Jeżeli używasz Chromium zamiast Chrome, będziesz musiał odpowiednio poprawić ścieżkę dostępu.</em></p>"
how_to: "Wybierz swój plik z zakładkami i naciśnij poniższy przycisk, aby je zaimportować. Może to zająć dłuższą chwilę, zanim wszystkie artykuły zostaną przeniesione."
+ instapaper:
+ page_title: 'Import > Instapaper'
+ description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Instapaper. W ustawieniach (https://www.instapaper.com/user), kliknij na "Download .CSV file" w sekcji "Export". Otrzymasz plik CSV.'
+ how_to: 'Wybierz swój plik eksportu z Instapaper i kliknij poniższy przycisk, aby go załadować.'
developer:
page_title: 'Deweloper'
full_documentation: 'Pokaż pełne API'
list_methods: 'Lista metod API'
clients:
- title: 'Klienci'
- create_new: 'Utwórz nowego klienta'
+ title: 'Klienci'
+ create_new: 'Utwórz nowego klienta'
existing_clients:
- title: 'Istniejący klienci'
- field_id: 'ID klienta'
- field_secret: 'Client secret'
- field_uris: 'Przekieruj URIs'
- field_grant_types: 'Przyznaj pozwolenie'
- no_client: 'Nie ma jeszcze klienta.'
+ title: 'Istniejący klienci'
+ field_id: 'ID klienta'
+ field_secret: 'Client secret'
+ field_uris: 'Przekieruj URIs'
+ field_grant_types: 'Przyznaj pozwolenie'
+ no_client: 'Nie ma jeszcze klienta.'
remove:
- warn_message_1: 'Masz możliwość usunięcia tego klienta. Ta akcja jest NIEODWRACALNA !'
- warn_message_2: "Jeżeli go usuniesz, aplikacje skonfigurowane z tym klientem nię będa w stanie autoryzować twojego wallabag."
- action: 'Usuń tego klienta'
+ warn_message_1: 'Masz możliwość usunięcia tego klienta. Ta akcja jest NIEODWRACALNA !'
+ warn_message_2: "Jeżeli go usuniesz, aplikacje skonfigurowane z tym klientem nię będa w stanie autoryzować twojego wallabag."
+ action: 'Usuń tego klienta'
client:
- page_title: 'Deweloper > Nowy klient'
- page_description: 'Tworzysz nowego klienta. Wypełnij poniższe pole w celu przekierowania URI twojej aplikacji.'
- form:
- redirect_uris_label: 'Przekieruj adresy URI'
- save_label: 'Stwórz nowego klienta'
- action_back: 'Cofnij'
+ page_title: 'Deweloper > Nowy klient'
+ page_description: 'Tworzysz nowego klienta. Wypełnij poniższe pole w celu przekierowania URI twojej aplikacji.'
+ form:
+ # name_label: 'Name of the client'
+ redirect_uris_label: 'Przekieruj adresy URI'
+ save_label: 'Stwórz nowego klienta'
+ action_back: 'Cofnij'
client_parameter:
- page_title: 'Deweloper > Parametry klienta'
- page_description: 'Tutaj znajdują się parametry klienta.'
- field_id: 'Client ID'
- field_secret: 'Client secret'
- back: 'Cofnij'
- read_howto: 'Przeczytaj jak "Stworzyć moją pierwszą aplikację"'
+ page_title: 'Deweloper > Parametry klienta'
+ page_description: 'Tutaj znajdują się parametry klienta.'
+ # field_name: 'Client name'
+ field_id: 'Client ID'
+ field_secret: 'Client secret'
+ back: 'Cofnij'
+ read_howto: 'Przeczytaj jak "Stworzyć moją pierwszą aplikację"'
howto:
- page_title: 'Deweloper > Jak stworzyć moją pierwszą aplikację'
- description:
+ page_title: 'Deweloper > Jak stworzyć moją pierwszą aplikację'
+ description:
paragraph_1: 'Następujące komendy korzystają <a href="https://github.com/jkbrzt/httpie">Biblioteka HTTPie</a>. Upewnij się, czy zainstalowałeś ją w swoim systemie zanim z niej skorzystasz'
paragraph_2: 'Potrzebujesz tokena w celu nawiązania komunikacji między swoją aplikacją a API wallabag.'
paragraph_3: 'W celu stworzenia tokena musisz <a href="%link%">stwórz nowego klienta</a>.'
paragraph_6: 'access_token jest użyteczny do wywołania API endpoint. Na przykład:'
paragraph_7: 'To wywołanie zwróci wszystkie twoje wpisy.'
paragraph_8: 'Jeżeli chcesz wyświetlić wszystkie punkty końcowe API, zobacz <a href="%link%">Dokumentacja naszego API</a>.'
- back: 'Cofnij'
+ back: 'Cofnij'
+
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Nazwa użytkownika'
+ # name_label: 'Name'
+ password_label: 'Hasło'
+ repeat_new_password_label: 'Powtórz nowe hasło'
+ plain_password_label: 'Jawne hasło'
+ email_label: 'Adres email'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
flashes:
config:
search: 'Căutare'
# save_link: 'Save a link'
back_to_unread: 'Înapoi la articolele necitite'
+ # users_management: 'Users management'
top:
add_new_entry: 'Introdu un nou articol'
search: 'Căutare'
# social: 'Social'
# powered_by: 'powered by'
about: 'Despre'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Configurație'
# if_label: 'if'
# then_tag_as_label: 'then tag as'
# delete_rule_label: 'delete'
+ # edit_rule_label: 'edit'
# rule_label: 'Rule'
# tags_label: 'Tags'
# faq:
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
- form_new_user:
- username_label: 'Nume de utilizator'
- password_label: 'Parolă'
- repeat_new_password_label: 'Repeat new password'
- plain_password_label: '????'
- email_label: 'E-mail'
entry:
page_titles:
quickstart:
# page_title: 'Quickstart'
+ # more: 'More…'
# intro:
# title: 'Welcome to wallabag!'
# paragraph_1: "We'll accompany you to visit wallabag and show you some features which can interest you."
# paragraph_2: 'Follow us!'
# configure:
# title: 'Configure the application'
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
# language: 'Change language and design'
# rss: 'Enable RSS feeds'
# tagging_rules: 'Write rules to automatically tag your articles'
# import: 'Configure import'
# first_steps:
# title: 'First steps'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
# new_article: 'Save your first article'
# unread_articles: 'And classify it!'
# migrate:
# wallabag_v1: 'Migrate from wallabag v1'
# wallabag_v2: 'Migrate from wallabag v2'
# readability: 'Migrate from Readability'
+ # instapaper: 'Migrate from Instapaper'
# developer:
# title: 'Developers'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
# create_application: 'Create your third application'
+ # use_docker: 'Use Docker to install wallabag'
# docs:
# title: 'Full documentation'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
# annotate: 'Annotate your article'
# export: 'Convert your articles into ePUB or PDF'
# search_filters: 'See how you can look for an article by using search engine and filters'
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
# firefox:
# page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
# how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
# chrome:
# page_title: 'Import > Chrome'
# description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
# how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ # instapaper:
+ # page_title: 'Import > Instapaper'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
# page_title: 'Developer'
# page_title: 'Developer > New client'
# page_description: 'You are about to create a new client. Please fill the field below for the redirect URI of your application.'
# form:
+ # name_label: 'Name of the client'
# redirect_uris_label: 'Redirect URIs'
# save_label: 'Create a new client'
# action_back: 'Back'
# client_parameter:
# page_title: 'Developer > Client parameters'
# page_description: 'Here are your client parameters.'
+ # field_name: 'Client name'
# field_id: 'Client ID'
# field_secret: 'Client secret'
# back: 'Back'
# paragraph_8: 'If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.'
# back: 'Back'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Nume de utilizator'
+ # name_label: 'Name'
+ password_label: 'Parolă'
+ repeat_new_password_label: 'Repeat new password'
+ plain_password_label: '????'
+ email_label: 'E-mail'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
search: 'Ara'
# save_link: 'Save a link'
back_to_unread: 'Okunmayan makalelere geri dön'
+ # users_management: 'Users management'
top:
add_new_entry: 'Yeni bir makale ekle'
search: 'Ara'
social: 'Sosyal'
powered_by: 'powered by'
about: 'Hakkımızda'
+ # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
config:
page_title: 'Yapılandırma'
or: 'Bir kural veya birbaşkası'
and: 'Bir kural ve diğeri'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
- form_new_user:
- username_label: 'Kullanıcı adı'
- password_label: 'Şifre'
- repeat_new_password_label: 'Yeni şifrenin tekrarı'
- plain_password_label: '????'
- email_label: 'E-posta'
entry:
page_titles:
quickstart:
page_title: 'Hızlı başlangıç'
+ # more: 'More…'
intro:
title: 'wallabag'
paragraph_1: "wallabag kurduğunuz için teşekkür ederiz. Bu sayfada biz size eşlik edecek ve ilginizi çekecek birkaç özellik göstereceğim."
paragraph_2: 'Bizi takip edin!'
configure:
title: 'Uygulamayı Yapılandırma'
+ # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
language: 'Dili ve tasarımı değiştirme'
rss: 'RSS akışını aktifleştirme'
# tagging_rules: 'Write rules to automatically tag your articles'
# import: 'Configure import'
first_steps:
title: 'İlk adım'
+ # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link."
new_article: 'İlk makalenizi kaydedin'
unread_articles: 'Ve bunu sınıflandırın!'
migrate:
wallabag_v1: "wallabag v1 üzerindeki verilerinizi wallabag'in yeni sürümüne aktarın"
wallabag_v2: "wallabag v2 üzerindeki verilerinizi wallabag'in yeni sürümüne aktarın"
readability: "Readability üzerindeki verilerinizi wallabag'e aktarın'"
+ instapaper: "Instapaper üzerindeki verilerinizi wallabag'e aktarın'"
developer:
# title: 'Developers'
+ # description: 'We also thought to the developers: Docker, API, translations, etc.'
# create_application: 'Create your third application'
+ # use_docker: 'Use Docker to install wallabag'
docs:
title: 'Dokümantasyon'
+ # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them."
# annotate: 'Annotate your article'
export: 'Makalelerinizi ePUB ya da PDF formatına çevirme'
search_filters: 'Makaleleri görüntülemek için arama motorlarını ve filteri kullanma'
# how_to: 'Please select your Readability export and click on the below button to upload and import it.'
worker:
# enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
- # firefox:
- # page_title: 'Import > Firefox'
- # description: "This importer will import all your Firefox bookmarks. <p>For Firefox, just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
- # chrome:
- # page_title: 'Import > Chrome'
- # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
- # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ firefox:
+ page_title: 'İçe Aktar > Firefox'
+ # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ chrome:
+ page_title: 'İçe Aktar > Chrome'
+ # description: "This importer will import all your Chrome bookmarks. The location of the file depends on your operating system : <ul><li>On Linux, go into the <code>~/.config/chromium/Default/</code> directory</li><li>On Windows, it should be at <code>%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default</code></li><li>On OS X, it should be at <code>~/Library/Application Support/Google/Chrome/Default/Bookmarks</code></li></ul>Once you got there, copy the Bookmarks file someplace you'll find.<em><br>Note that if you have Chromium instead of Chrome, you'll have to correct paths accordingly.</em></p>"
+ # how_to: "Please choose the bookmark backup file and click on the button below to import it. Note that the process may take a long time since all articles have to be fetched."
+ instapaper:
+ page_title: 'İçe Aktar > Instapaper'
+ # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
+ # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
developer:
# page_title: 'Developer'
# page_title: 'Developer > New client'
# page_description: 'You are about to create a new client. Please fill the field below for the redirect URI of your application.'
# form:
+ # name_label: 'Name of the client'
# redirect_uris_label: 'Redirect URIs'
# save_label: 'Create a new client'
# action_back: 'Back'
# client_parameter:
# page_title: 'Developer > Client parameters'
# page_description: 'Here are your client parameters.'
+ # field_name: 'Client name'
# field_id: 'Client ID'
# field_secret: 'Client secret'
# back: 'Back'
# paragraph_8: 'If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.'
# back: 'Back'
+user:
+ # page_title: Users management
+ # new_user: Create a new user
+ # edit_user: Edit an existing user
+ # description: "Here you can manage all users (create, edit and delete)"
+ # list:
+ # actions: Actions
+ # edit_action: Edit
+ # yes: Yes
+ # no: No
+ # create_new_one: Create a new user
+ form:
+ username_label: 'Kullanıcı adı'
+ # name_label: 'Name'
+ password_label: 'Şifre'
+ repeat_new_password_label: 'Yeni şifrenin tekrarı'
+ plain_password_label: '????'
+ email_label: 'E-posta'
+ # enabled_label: 'Enabled'
+ # locked_label: 'Locked'
+ # last_login_label: 'Last login'
+ # twofactor_label: Two factor authentication
+ # save: Save
+ # delete: Delete
+ # delete_confirm: Are you sure?
+ # back_to_list: Back to list
+
flashes:
config:
notice:
validator:
password_must_match: 'De indtastede adgangskoder skal være ens'
password_too_short: 'Adgangskoden skal være mindst 8 tegn'
-# password_wrong_value: 'Wrong value for your current password'
-# item_per_page_too_high: 'This will certainly kill the app'
-# rss_limit_too_hight: 'This will certainly kill the app'
+ # password_wrong_value: 'Wrong value for your current password'
+ # item_per_page_too_high: 'This will certainly kill the app'
+ # rss_limit_too_hight: 'This will certainly kill the app'
validator:
-# password_must_match: 'The password fields must match.'
-# password_too_short: 'Password should by at least 8 chars long'
-# password_wrong_value: 'Wrong value for your current password'
-# item_per_page_too_high: 'This will certainly kill the app'
-# rss_limit_too_hight: 'This will certainly kill the app'
+ # password_must_match: 'The password fields must match.'
+ # password_too_short: 'Password should by at least 8 chars long'
+ # password_wrong_value: 'Wrong value for your current password'
+ # item_per_page_too_high: 'This will certainly kill the app'
+ # rss_limit_too_hight: 'This will certainly kill the app'
{% block scripts %}
{% endblock %}
- <title>wallabag - {% block title %}{% endblock %}</title>
+ <title>{% block title %}{% endblock %} – wallabag</title>
{% endblock %}
</head>
« {{ tagging_rule.rule }} »
{{ 'config.form_rules.then_tag_as_label'|trans }}
« {{ tagging_rule.tags|join(', ') }} »
+ <a href="{{ path('edit_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.edit_rule_label'|trans }}" class="tool mode_edit">✎</a>
<a href="{{ path('delete_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.delete_rule_label'|trans }}" class="tool delete icon-trash icon"></a>
</li>
{% endfor %}
</table>
</div>
</div>
-
- {% if is_granted('ROLE_SUPER_ADMIN') %}
- <h2>{{ 'config.tab_menu.new_user'|trans }}</h2>
-
- {{ form_start(form.new_user) }}
- {{ form_errors(form.new_user) }}
-
- <fieldset class="w500p inline">
- <div class="row">
- {{ form_label(form.new_user.username) }}
- {{ form_errors(form.new_user.username) }}
- {{ form_widget(form.new_user.username) }}
- </div>
- </fieldset>
-
- <fieldset class="w500p inline">
- <div class="row">
- {{ form_label(form.new_user.plainPassword.first) }}
- {{ form_errors(form.new_user.plainPassword.first) }}
- {{ form_widget(form.new_user.plainPassword.first) }}
- </div>
- </fieldset>
-
- <fieldset class="w500p inline">
- <div class="row">
- {{ form_label(form.new_user.plainPassword.second) }}
- {{ form_errors(form.new_user.plainPassword.second) }}
- {{ form_widget(form.new_user.plainPassword.second) }}
- </div>
- </fieldset>
-
- <fieldset class="w500p inline">
- <div class="row">
- {{ form_label(form.new_user.email) }}
- {{ form_errors(form.new_user.email) }}
- {{ form_widget(form.new_user.email) }}
- </div>
- </fieldset>
-
- {{ form_rest(form.new_user) }}
- {% endif %}
- </form>
{% endblock %}
{% extends "WallabagCoreBundle::layout.html.twig" %}
{% block title %}
- {% include "@WallabagCore/themes/_title.html.twig" %}
+ {% include "@WallabagCore/themes/common/Entry/_title.html.twig" %}
{% endblock %}
{% block content %}
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'error.page_title'|trans }}{% endblock %}
+
+{% block body_class %}login{% endblock %}
+
+{% block menu %}{% endblock %}
+{% block messages %}{% endblock %}
+{% block header %}{% endblock %}
+
+{% block content %}
+<main class="valign-wrapper">
+ <div class="valign row">
+ <div class="card sw">
+ <div class="center"><img src="{{ asset('bundles/wallabagcore/themes/_global/img/logo-w.png') }}" alt="wallabag logo" /></div>
+ <h2>{{ status_code }}: {{ status_text }}</h2>
+ <p>{{ exception.message }}</p>
+ </div>
+ </div>
+</main>
+{% endblock %}
+
+{% block footer %}
+{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'about.page_title'|trans }}{% endblock %}
-
-{% block content %}
- <h2>{{ 'about.top_menu.who_behind_wallabag'|trans }}</h2>
-
- <dl>
- <dt>{{ 'about.who_behind_wallabag.developped_by'|trans }}</dt>
- <dd><a href="mailto:nicolas@loeuillet.org">Nicolas Lœuillet</a> — <a href="http://www.loeuillet.org">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
- <dd>Thomas Citharel — <a href="https://tcit.fr">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
- <dd>Jérémy Benoist — <a href="http://www.j0k3r.net">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
-
- <dt>{{ 'about.who_behind_wallabag.many_contributors'|trans|raw }}</dt>
-
- <dt>{{ 'about.who_behind_wallabag.project_website'|trans }}</dt>
- <dd><a href="https://www.wallabag.org">https://www.wallabag.org</a></dd>
-
- <dt>{{ 'about.who_behind_wallabag.license'|trans }}: <a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a></dt>
-
- <dt>{{ 'about.who_behind_wallabag.version'|trans }}: {{ version }}</dt>
- </dl>
-
- <h2>{{ 'about.top_menu.getting_help'|trans }}</h2>
-
- <dl>
- <dt>{{ 'about.getting_help.documentation'|trans }}</dt>
- <dd><a href="http://doc.wallabag.org/en/master/">english</a></dd>
- <dd><a href="http://doc.wallabag.org/fr/master/">français</a></dd>
-
- <dt>{{ 'about.getting_help.bug_reports'|trans }}</dt>
- <dd>{{ 'about.getting_help.support'|trans|raw }}</dd>
- </dl>
-
- <h2>{{ 'about.top_menu.helping'|trans }}</h2>
-
- <p>{{ 'about.helping.description'|trans }}</p>
-
- <dl>
- <dd>{{ 'about.helping.by_contributing_2'|trans }} <a href="https://github.com/wallabag/wallabag/issues/1254">{{ 'about.helping.by_contributing'|trans }}</a></dd>
- <dd><a href="{{ paypal_url }}">{{ 'about.helping.by_paypal'|trans }}</a></dd>
- </dl>
-
- <h2>{{ 'about.top_menu.contributors'|trans }}</h2>
- <p><a href="https://github.com/wallabag/wallabag/graphs/contributors">{{ 'about.contributors.description'|trans }}</a></p>
-
- <h2>{{ 'about.top_menu.third_party'|trans }}</h2>
- <p>{{ 'about.third_party.description'|trans }}</p>
- <table class="striped">
- <tr>
- <th>{{ 'about.third_party.package'|trans }}</th>
- <th>{{ 'about.third_party.license'|trans }}</th>
- </tr>
- <tr><td>behat/transliterator</td><td>Artistic 1.0</td></tr>
- <tr><td>CraueConfigBundle</td><td>MIT</td></tr>
- <tr><td>doctrine/annotations</td><td>MIT</td></tr>
- <tr><td>doctrine/cache</td><td>MIT</td></tr>
- <tr><td>doctrine/collections</td><td>MIT</td></tr>
- <tr><td>doctrine/common</td><td>MIT</td></tr>
- <tr><td>doctrine/dbal</td><td>MIT</td></tr>
- <tr><td>doctrine/doctrine-bundle</td><td>MIT</td></tr>
- <tr><td>doctrine/doctrine-cache-bundle</td><td>MIT</td></tr>
- <tr><td>doctrine/doctrine-migrations-bundle</td><td>MIT</td></tr>
- <tr><td>doctrine/inflector</td><td>MIT</td></tr>
- <tr><td>doctrine/instantiator</td><td>MIT</td></tr>
- <tr><td>doctrine/lexer</td><td>MIT</td></tr>
- <tr><td>doctrine/migrations</td><td>LGPL-2.1</td></tr>
- <tr><td>doctrine/orm</td><td>MIT</td></tr>
- <tr><td>friendsofsymfony/oauth-server-bundle</td><td>MIT</td></tr>
- <tr><td>friendsofsymfony/oauth2-php</td><td>MIT</td></tr>
- <tr><td>friendsofsymfony/rest-bundle</td><td>MIT</td></tr>
- <tr><td>friendsofsymfony/user-bundle</td><td>MIT</td></tr>
- <tr><td>gedmo/doctrine-extensions</td><td>MIT</td></tr>
- <tr><td>grandt/binstring</td><td>LGPL-2.1</td></tr>
- <tr><td>grandt/phpepub</td><td>LGPL-2.1</td></tr>
- <tr><td>grandt/phpresizegif</td><td>LGPL-2.1</td></tr>
- <tr><td>grandt/phpzipmerge</td><td>LGPL-2.1</td></tr>
- <tr><td>grandt/relativepath</td><td>LGPL-2.1</td></tr>
- <tr><td>guzzlehttp/guzzle</td><td>MIT</td></tr>
- <tr><td>guzzlehttp/ringphp</td><td>MIT</td></tr>
- <tr><td>guzzlehttp/streams</td><td>MIT</td></tr>
- <tr><td>hoa/compiler</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/consistency</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/event</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/exception</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/file</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/iterator</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/math</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/protocol</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/regex</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/ruler</td><td>BSD-3-Clausev
- <tr><td>hoa/stream</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/ustring</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/visitor</td><td>BSD-3-Clause</td></tr>
- <tr><td>hoa/zformat</td><td>BSD-3-Clause</td></tr>
- <tr><td>htmlawed/htmlawed</td><td>GPL-2.0+ or LGPL-3.0</td></tr>
- <tr><td>incenteev/composer-parameter-handler</td><td>MIT</td></tr>
- <tr><td>j0k3r/graby</td><td>AGPL-3.0</td></tr>
- <tr><td>j0k3r/graby-site-config</td><td>AGPL-3.0</td></tr>
- <tr><td>j0k3r/php-readability</td><td>Apache-2.0</td></tr>
- <tr><td>j0k3r/safecurl</td><td>MIT</td></tr>
- <tr><td>jdorn/sql-formatter</td><td>MIT</td></tr>
- <tr><td>jms/metadata</td><td>Apache</td></tr>
- <tr><td>jms/parser-lib</td><td>Apache2</td></tr>
- <tr><td>jms/serializer</td><td>Apache2</td></tr>
- <tr><td>jms/serializer-bundle</td><td>Apache2</td></tr>
- <tr><td>kphoen/rulerz</td><td>MIT</td></tr>
- <tr><td>kphoen/rulerz-bundle</td><td>MIT</td></tr>
- <tr><td>kriswallsmith/assetic</td><td>MIT</td></tr>
- <tr><td>lexik/form-filter-bundle</td><td>MIT</td></tr>
- <tr><td>liip/theme-bundle</td><td>MIT</td></tr>
- <tr><td>mgargano/simplehtmldom</td><td>MIT</td></tr>
- <tr><td>michelf/php-markdown</td><td>BSD-3-Clause</td></tr>
- <tr><td>monolog/monolog</td><td>MIT</td></tr>
- <tr><td>neitanod/forceutf8</td><td>BSD-3-Clause</td></tr>
- <tr><td>nelmio/api-doc-bundle</td><td>MIT</td></tr>
- <tr><td>nelmio/cors-bundle</td><td>MIT</td></tr>
- <tr><td>ocramius/proxy-manager</td><td>MIT</td></tr>
- <tr><td>pagerfanta/pagerfanta</td><td>MIT</td></tr>
- <tr><td>paragonie/random_compat</td><td>MIT</td></tr>
- <tr><td>phpcollection/phpcollection</td><td>Apache2</td></tr>
- <tr><td>phpoption/phpoption</td><td>Apache2</td></tr>
- <tr><td>phpzip/phpzip</td><td>LGPL-2.1</td></tr>
- <tr><td>psr/log</td><td>MIT</td></tr>
- <tr><td>react/promise</td><td>MIT</td></tr>
- <tr><td>scheb/two-factor-bundle</td><td>MIT</td></tr>
- <tr><td>sensio/distribution-bundle</td><td>MIT</td></tr>
- <tr><td>sensio/framework-extra-bundle</td><td>MIT</td></tr>
- <tr><td>sensiolabs/security-checker</td><td>MIT</td></tr>
- <tr><td>simplepie/simplepie</td><td>BSD-3-Clause</td></tr>
- <tr><td>smalot/pdfparser</td><td>GPL-3.0</td></tr>
- <tr><td>sonata-project/google-authenticator</td><td>MIT</td></tr>
- <tr><td>stof/doctrine-extensions-bundle</td><td>MIT</td></tr>
- <tr><td>swiftmailer/swiftmailer</td><td>MIT</td></tr>
- <tr><td>symfony/assetic-bundle</td><td>MIT</td></tr>
- <tr><td>symfony/monolog-bundle</td><td>MIT</td></tr>
- <tr><td>All of Symfony</td><td>MIT-licenced</td></tr>
- <tr><td>tecnickcom/tcpdf</td><td>LGPLv3</td></tr>
- <tr><td>twig/extensions</td><td>MIT</td></tr>
- <tr><td>twig/twig</td><td>BSD-3-Clause</td></tr>
- <tr><td>wallabag/php-mobi</td><td>Apache-2.0</td></tr>
- <tr><td>willdurand/hateoas</td><td>MIT</td></tr>
- <tr><td>willdurand/hateoas-bundle</td><td>MIT</td></tr>
- <tr><td>willdurand/jsonp-callback-validator</td><td>MIT</td></tr>
- <tr><td>willdurand/negotiation</td><td>MIT</td></tr>
- <tr><td>zendframework/zend-code</td><td>BSD-3-Clause</td></tr>
- <tr><td>zendframework/zend-eventmanager</td><td>BSD-3-Clause</td></tr>
- <tr><td>doctrine/data-fixtures</td><td>MIT</td></tr>
- <tr><td>doctrine/doctrine-fixtures-bundle</td><td>MIT</td></tr>
- <tr><td>phpdocumentor/reflection-docblock</td><td>MIT</td></tr>
- <tr><td>phpspec/prophecy</td><td>MIT</td></tr>
- <tr><td>phpunit/php-code-coverage</td><td>BSD-3-Clause</td></tr>
- <tr><td>phpunit/php-file-iterator</td><td>BSD-3-Clause</td></tr>
- <tr><td>phpunit/php-text-template</td><td>BSD-3-Clause</td></tr>
- <tr><td>phpunit/php-timer</td><td>BSD-3-Clause</td></tr>
- <tr><td>phpunit/php-token-stream</td><td>BSD-3-Clause</td></tr>
- <tr><td>phpunit/phpunit</td><td>BSD-3-Clause</td></tr>
- <tr><td>phpunit/phpunit-mock-objects</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/comparator</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/diff</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/environment</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/exporter</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/global-state</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/recursion-context</td><td>BSD-3-Clause</td></tr>
- <tr><td>sebastian/version</td><td>BSD-3-Clause</td></tr>
- <tr><td>sensio/generator-bundle</td><td>MIT</td></tr>
- <tr><td>symfony/phpunit-bridge</td><td>MIT</td></tr>
- </table>
-{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'howto.page_title'|trans }}{% endblock %}
-
-{% block content %}
- <h2>{{ 'howto.page_title'|trans }}</h2>
-
- <p>{{ 'howto.page_description'|trans }}</p>
- <ul>
- <li><a href="{{ path('new') }}">{{ 'howto.form.description'|trans }}</a></li>
- </ul>
- <h3>{{ 'howto.top_menu.browser_addons'|trans }}</h3>
- <ul>
- <li><a href="{{ addonsUrl.firefox }}" target="_blank">{{ 'howto.browser_addons.firefox'|trans }}</a></li>
- <li><a href="{{ addonsUrl.chrome }}" target="_blank">{{ 'howto.browser_addons.chrome'|trans }}</a></li>
- </ul>
- <h3>{{ 'howto.top_menu.mobile_apps'|trans }}</h3>
- <ul>
- <li>Android: <a href="{{ addonsUrl.f_droid }}" target="_blank">{{ 'howto.mobile_apps.android.via_f_droid'|trans }}</a> / <a href="{{ addonsUrl.google_play }}" target="_blank">{{ 'howto.mobile_apps.android.via_google_play'|trans }}</a></li>
- <li>iOS: <a href="{{ addonsUrl.ios }}" target="_blank">{{ 'howto.mobile_apps.ios'|trans }}</a></li>
- <li>Windows Phone: <a href="{{ addonsUrl.windows }}" target="_blank">{{ 'howto.mobile_apps.windows'|trans }}</a></li>
- </ul>
- <h3>{{ 'howto.top_menu.bookmarklet'|trans }}</h3>
- <p>
- {{ 'howto.bookmarklet.description'|trans }}
- {% include 'WallabagCoreBundle::_bookmarklet.html.twig' %}
-
-{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'quickstart.page_title'|trans }}{% endblock %}
-
-{% block content %}
-
- <h3>{{ 'quickstart.intro.title'|trans }}</h3>
- <p>{{ 'quickstart.intro.paragraph_1'|trans }}</p>
- <p>{{ 'quickstart.intro.paragraph_2'|trans }}</p>
-
- <h4>{{ 'quickstart.configure.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('config') }}">{{ 'quickstart.configure.language'|trans }}</a></li>
- <li><a href="{{ path('config') }}#set2">{{ 'quickstart.configure.rss'|trans }}</a></li>
- <li><a href="{{ path('config') }}#set5">{{ 'quickstart.configure.tagging_rules'|trans }}</a></li>
- </ul>
-
- {% if is_granted('ROLE_SUPER_ADMIN') %}
- <h4>{{ 'quickstart.admin.title'|trans }}</h4>
- <p>{{ 'quickstart.admin.description'|trans }}</p>
- <ul>
- <li><a href="{{ path('config') }}#set6">{{ 'quickstart.admin.new_user'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-analytics">{{ 'quickstart.admin.analytics'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-entry">{{ 'quickstart.admin.sharing'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-export">{{ 'quickstart.admin.export'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-import">{{ 'quickstart.admin.import'|trans }}</a></li>
- </ul>
- {% endif %}
-
- <h4>{{ 'quickstart.first_steps.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('new') }}">{{ 'quickstart.first_steps.new_article'|trans }}</a></li>
- <li><a href="{{ path('unread') }}">{{ 'quickstart.first_steps.unread_articles'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.migrate.title'|trans }}</h4>
- <p>{{ 'quickstart.migrate.description'|trans }}</p>
- <ul>
- <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
- <li><a href="{{ path('import_wallabag_v1') }}">{{ 'quickstart.migrate.wallabag_v1'|trans }}</a></li>
- <li><a href="{{ path('import_wallabag_v2') }}">{{ 'quickstart.migrate.wallabag_v2'|trans }}</a></li>
- <li><a href="{{ path('import_readability') }}">{{ 'quickstart.migrate.readability'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.developer.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('developer') }}">{{ 'quickstart.developer.create_application'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.docs.title'|trans }}</h4>
- <ul>
- <li><a href="http://doc.wallabag.org/en/master/user/annotations.html">{{ 'quickstart.docs.annotate'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/user/download_articles.html">{{ 'quickstart.docs.export'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/user/filters.html">{{ 'quickstart.docs.search_filters'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/user/errors_during_fetching.html">{{ 'quickstart.docs.fetching_errors'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/">{{ 'quickstart.docs.all_docs'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.support.title'|trans }}</h4>
- <p>{{ 'quickstart.support.description'|trans }}</p>
- <ul>
- <li><a href="https://github.com/wallabag/wallabag/issues/">{{ 'quickstart.support.github'|trans }}</a></li>
- <li><a href="mailto:hello@wallabag.org">{{ 'quickstart.support.email'|trans }}</a></li>
- <li><a href="https://gitter.im/wallabag/wallabag">{{ 'quickstart.support.gitter'|trans }}</a></li>
- </ul>
-
-{% endblock %}
</li>-->
<li><a href="{{ path('config') }}">{{ 'menu.left.config'|trans }}</a></li>
{% if is_granted('ROLE_SUPER_ADMIN') %}
+ <li><a href="{{ path('user_index') }}">{{ 'menu.left.users_management'|trans }}</a></li>
<li><a href="{{ path('craue_config_settings_modify') }}">{{ 'menu.left.internal_settings'|trans }}</a></li>
{% endif %}
<li><a href="{{ path('import') }}">{{ 'menu.left.import'|trans }}</a></li>
--- /dev/null
+Hello {{username}}!
+
+To reset your password - please visit {{confirmationUrl}}
+
+Regards,
+Wallabag bot
<div class="col s12">
<h5>{{ 'howto.top_menu.bookmarklet'|trans }}</h5>
{{ 'howto.bookmarklet.description'|trans }}
- {% include 'WallabagCoreBundle::_bookmarklet.html.twig' %}
+ {% include '@WallabagCore/themes/common/Static/_bookmarklet.html.twig' %}
</div>
</div>
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'quickstart.page_title'|trans }}{% endblock %}
+
+{% block content %}
+
+ <div class="row">
+ <div class="col s12">
+ <div class="card-panel settings">
+
+ <div class="row">
+ <h3>{{ 'quickstart.intro.title'|trans }}</h3>
+
+ <ul class="row data">
+ <li class="col l4 m6 s12">
+ <div class="card teal darken-1">
+ <div class="card-content white-text">
+ <span class="card-title">{{ 'quickstart.configure.title'|trans }}</span>
+ <p>{{ 'quickstart.configure.description'|trans }}</p>
+ </div>
+ <div class="card-action">
+ <ul>
+ <li><a href="{{ path('config') }}">{{ 'quickstart.configure.language'|trans }}</a></li>
+ <li><a href="{{ path('config') }}#set2">{{ 'quickstart.configure.rss'|trans }}</a></li>
+ <li><a href="{{ path('config') }}#set5">{{ 'quickstart.more'|trans }}</a></li>
+ </ul>
+ </div>
+ </div>
+ </li>
+
+ <li class="col l4 m6 s12">
+ <div class="card green darken-1">
+ <div class="card-content white-text">
+ <span class="card-title">{{ 'quickstart.first_steps.title'|trans }}</span>
+ <p>{{ 'quickstart.first_steps.description'|trans }}</p>
+ </div>
+ <div class="card-action">
+ <ul>
+ <li><a href="{{ path('new') }}">{{ 'quickstart.first_steps.new_article'|trans }}</a></li>
+ <li><a href="{{ path('unread') }}">{{ 'quickstart.first_steps.unread_articles'|trans }}</a></li>
+ </ul>
+ </div>
+ </div>
+ </li>
+
+ <li class="col l4 m6 s12">
+ <div class="card light-green darken-1">
+ <div class="card-content white-text">
+ <span class="card-title">{{ 'quickstart.migrate.title'|trans }}</span>
+ <p>{{ 'quickstart.migrate.description'|trans }}</p>
+ </div>
+ <div class="card-action">
+ <ul>
+ <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
+ <li><a href="{{ path('import_readability') }}">{{ 'quickstart.migrate.readability'|trans }}</a></li>
+ <li><a href="{{ path('import_instapaper') }}">{{ 'quickstart.migrate.instapaper'|trans }}</a></li>
+ <li><a href="{{ path('import') }}">{{ 'quickstart.more'|trans }}</a></li>
+ </ul>
+ </div>
+ </div>
+ </li>
+
+ <li class="col l4 m6 s12">
+ <div class="card blue darken-1">
+ <div class="card-content white-text">
+ <span class="card-title">{{ 'quickstart.developer.title'|trans }}</span>
+ <p>{{ 'quickstart.developer.description'|trans }}</p>
+ </div>
+ <div class="card-action">
+ <ul>
+ <li><a href="{{ path('developer') }}">{{ 'quickstart.developer.create_application'|trans }}</a></li>
+ <li><a href="http://doc.wallabag.org/en/master/developer/docker.html">{{ 'quickstart.developer.use_docker'|trans }}</a></li>
+ <li><a href="http://doc.wallabag.org/en/master/index.html#dev-docs">{{ 'quickstart.more'|trans }}</a></li>
+ </ul>
+ </div>
+ </div>
+ </li>
+
+ <li class="col l4 m6 s12">
+ <div class="card light-blue darken-1">
+ <div class="card-content white-text">
+ <span class="card-title">{{ 'quickstart.docs.title'|trans }}</span>
+ <p>{{ 'quickstart.docs.description'|trans }}</p>
+ </div>
+ <div class="card-action">
+ <ul>
+ <li><a href="http://doc.wallabag.org/en/master/user/annotations.html">{{ 'quickstart.docs.annotate'|trans }}</a></li>
+ <li><a href="http://doc.wallabag.org/en/master/user/download_articles.html">{{ 'quickstart.docs.export'|trans }}</a></li>
+ <li><a href="http://doc.wallabag.org/">{{ 'quickstart.docs.all_docs'|trans }}</a></li>
+ </ul>
+ </div>
+ </div>
+ </li>
+
+ <li class="col l4 m6 s12">
+ <div class="card cyan darken-1">
+ <div class="card-content white-text">
+ <span class="card-title">{{ 'quickstart.support.title'|trans }}</span>
+ <p>{{ 'quickstart.support.description'|trans }}</p>
+ </div>
+ <div class="card-action">
+ <ul>
+ <li><a href="https://github.com/wallabag/wallabag/issues/">{{ 'quickstart.support.github'|trans }}</a></li>
+ <li><a href="mailto:hello@wallabag.org">{{ 'quickstart.support.email'|trans }}</a></li>
+ <li><a href="https://gitter.im/wallabag/wallabag">{{ 'quickstart.support.gitter'|trans }}</a></li>
+ </ul>
+ </div>
+ </div>
+ </li>
+
+ </ul>
+
+ </div>
+
+ </div>
+ </div>
+ </div>
+
+{% endblock %}
<li class="tab col s3"><a href="#set3">{{ 'config.tab_menu.user_info'|trans }}</a></li>
<li class="tab col s3"><a href="#set4">{{ 'config.tab_menu.password'|trans }}</a></li>
<li class="tab col s3"><a href="#set5">{{ 'config.tab_menu.rules'|trans }}</a></li>
- {% if is_granted('ROLE_SUPER_ADMIN') %}
- <li class="tab col s3"><a href="#set6">{{ 'config.tab_menu.new_user'|trans }}</a></li>
- {% endif %}
</ul>
</div>
<div class="row">
<div class="input-field col s12">
{{ 'config.form_user.two_factor_description'|trans }}
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
+ <br />
+
{{ form_widget(form.user.twoFactorAuthentication) }}
{{ form_label(form.user.twoFactorAuthentication) }}
{{ form_errors(form.user.twoFactorAuthentication) }}
« {{ tagging_rule.rule }} »
{{ 'config.form_rules.then_tag_as_label'|trans }}
« {{ tagging_rule.tags|join(', ') }} »
+ <a href="{{ path('edit_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.edit_rule_label'|trans }}">
+ <i class="tool grey-text mode_edit material-icons">mode_edit</i>
+ </a>
<a href="{{ path('delete_tagging_rule', {id: tagging_rule.id}) }}" title="{{ 'config.form_rules.delete_rule_label'|trans }}">
<i class="tool grey-text delete material-icons">delete</i>
</a>
</div>
</div>
</div>
-
- {% if is_granted('ROLE_SUPER_ADMIN') %}
- <div id="set6" class="col s12">
- {{ form_start(form.new_user) }}
- {{ form_errors(form.new_user) }}
-
- <div class="row">
- <div class="input-field col s12">
- {{ form_label(form.new_user.username) }}
- {{ form_errors(form.new_user.username) }}
- {{ form_widget(form.new_user.username) }}
- </div>
- </div>
-
- <div class="row">
- <div class="input-field col s12">
- {{ form_label(form.new_user.plainPassword.first) }}
- {{ form_errors(form.new_user.plainPassword.first) }}
- {{ form_widget(form.new_user.plainPassword.first) }}
- </div>
- </div>
-
- <div class="row">
- <div class="input-field col s12">
- {{ form_label(form.new_user.plainPassword.second) }}
- {{ form_errors(form.new_user.plainPassword.second) }}
- {{ form_widget(form.new_user.plainPassword.second) }}
- </div>
- </div>
-
- <div class="row">
- <div class="input-field col s12">
- {{ form_label(form.new_user.email) }}
- {{ form_errors(form.new_user.email) }}
- {{ form_widget(form.new_user.email) }}
- </div>
- </div>
-
- {{ form_widget(form.new_user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
- {{ form_rest(form.new_user) }}
- </form>
- </div>
- {% endif %}
</div>
</div>
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'developer.client.page_title'|trans }}{% endblock %}
-
-{% block content %}
-<div class="row">
- <div class="col s12">
- <div class="card-panel settings">
-
- <div class="row">
- <p>{{ 'developer.client.page_description'|trans }}</p>
- {{ form_start(form) }}
- {{ form_errors(form) }}
-
- <div class="input-field col s12">
- {{ form_label(form.name) }}
- {{ form_errors(form.name) }}
- {{ form_widget(form.name) }}
- </div>
-
- <div class="input-field col s12">
- {{ form_label(form.redirect_uris) }}
- {{ form_errors(form.redirect_uris) }}
- {{ form_widget(form.redirect_uris) }}
- </div>
-
- <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{{ 'developer.client.action_back'|trans }}</a>
- {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
-
- {{ form_rest(form) }}
- </div>
-
- </div>
- </div>
-</div>
-
-{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'developer.client_parameter.page_title'|trans }}{% endblock %}
-
-{% block content %}
-<div class="row">
- <div class="col s12">
- <div class="card-panel settings">
- <div class="row">
- <p>{{ 'developer.client_parameter.page_description'|trans }}</p>
- <ul>
- <li>{{ 'developer.client_parameter.field_name'|trans }}: <strong><pre>{{ client_name }}</pre></strong></li>
- <li>{{ 'developer.client_parameter.field_id'|trans }}: <strong><pre>{{ client_id }}</pre></strong></li>
- <li>{{ 'developer.client_parameter.field_secret'|trans }}: <strong><pre>{{ client_secret }}</pre></strong></li>
- </ul>
-
- <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{{ 'developer.client_parameter.back'|trans }}</a>
- <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{{ 'developer.client_parameter.read_howto'|trans }}</a>
- </div>
- </div>
- </div>
-</div>
-{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'developer.howto.page_title'|trans }}{% endblock %}
-
-{% block css %}
- {{ parent() }}
- <link rel="stylesheet" href="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/themes/prism-dark.min.css') }}">
-{% endblock %}
-
-{% block content %}
-<div class="row">
- <div class="col s12">
- <div class="card-panel settings">
-
- <div class="row">
- <p>{{ 'developer.howto.description.paragraph_1'|trans|raw }}</p>
- <p>{{ 'developer.howto.description.paragraph_2'|trans }}</p>
- <p>{{ 'developer.howto.description.paragraph_3'|trans({'%link%': path('developer_create_client')})|raw }}</p>
- <p>{{ 'developer.howto.description.paragraph_4'|trans }}</p>
- <p>
- <pre><code class="language-bash">http POST http://v2.wallabag.org/oauth/v2/token \
- grant_type=password \
- client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \
- client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \
- username=yourUsername \
- password=yourPassw0rd</code></pre>
- </p>
- <p>{{ 'developer.howto.description.paragraph_5'|trans }}</p>
- <p>
- <pre><code class="language-bash">HTTP/1.1 200 OK
-Cache-Control: no-store, private
-Connection: close
-Content-Type: application/json
-Date: Tue, 06 Oct 2015 18:24:03 GMT
-Host: localhost:8000
-Pragma: no-cache
-X-Debug-Token: be00a1
-X-Debug-Token-Link: /profiler/be00a1
-X-Powered-By: PHP/5.5.9-1ubuntu4.13
-{
- "access_token": "ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw",
- "expires_in": 3600,
- "refresh_token": "ODBjODU1NWUwNmUzZTBkNDQ5YWVlZTVlMjQ2Y2I0OWM2NTM1ZGM2M2Y3MDhjMTViM2U2MzYxYzRkMDk5ODRlZg",
- "scope": null,
- "token_type": "bearer"
-}</code></pre>
- </p>
- <p>{{ 'developer.howto.description.paragraph_6'|trans }}</p>
- <p>
- <pre><code class="language-bash">http GET http://v2.wallabag.org/api/entries.json \
- "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre>
- </p>
- <p>{{ 'developer.howto.description.paragraph_7'|trans }}</p>
- <p>{{ 'developer.howto.description.paragraph_8'|trans({'%link%': path('nelmio_api_doc_index')})|raw }}</p>
- <p><a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{{ 'developer.howto.back'|trans }}</a></p>
- </div>
-
- </div>
- </div>
-</div>
-<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/prism.min.js') }}"></script>
-<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/components/prism-bash.min.js') }}"></script>
-{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'developer.page_title'|trans }}{% endblock %}
-
-{% block content %}
-<div class="row">
- <div class="col s12">
- <div class="card-panel settings">
-
- <div class="row">
- <h3>{{ 'developer.welcome_message'|trans }}</h3>
-
- <h4>{{ 'developer.documentation'|trans }}</h4>
-
- <ul>
- <li><a href="{{ path('developer_howto_firstapp') }}">{{ 'developer.how_to_first_app'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/developer/api.html">{{ 'developer.full_documentation'|trans }}</a></li>
- <li><a href="{{ path('nelmio_api_doc_index') }}">{{ 'developer.list_methods'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'developer.clients.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('developer_create_client') }}">{{ 'developer.clients.create_new'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'developer.existing_clients.title'|trans }}</h4>
- {% if clients %}
- <ul class="collapsible" data-collapsible="expandable">
- {% for client in clients %}
- <li>
- <div class="collapsible-header">{{ client.name }} - #{{ client.id }}</div>
- <div class="collapsible-body">
- <table class="striped">
- <tr>
- <td>{{ 'developer.existing_clients.field_id'|trans }}</td>
- <td><strong><code>{{ client.id }}_{{ client.randomId }}</code></strong></td>
- </tr>
- <tr>
- <td>{{ 'developer.existing_clients.field_secret'|trans }}</td>
- <td><strong><code>{{ client.secret }}</code></strong></td>
- </tr>
- <tr>
- <td>{{ 'developer.existing_clients.field_uris'|trans }}</td>
- <td><strong><code>{{ client.redirectUris|json_encode() }}</code></strong></td>
- </tr>
- <tr>
- <td>{{ 'developer.existing_clients.field_grant_types'|trans }}</td>
- <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td>
- </tr>
- </table>
- <p>
- {{ 'developer.remove.warn_message_1'|trans({'%name%': client.name }) }}<br/>
- {{ 'developer.remove.warn_message_2'|trans({'%name%': client.name }) }}<br/>
- <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{{ 'developer.remove.action'|trans({'%name%': client.name }) }}</a>
- </p>
- </div>
- </li>
- {% endfor %}
- </ul>
- {% else %}
- {{ 'developer.existing_clients.no_client'|trans }}
- {% endif %}
- </div>
-
- </div>
- </div>
-</div>
-
-{% endblock %}
{% extends "WallabagCoreBundle::layout.html.twig" %}
{% block title %}
- {% include "@WallabagCore/themes/_title.html.twig" %}
+ {% include "@WallabagCore/themes/common/Entry/_title.html.twig" %}
{% endblock %}
{% block content %}
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
- <channel>
- <title>wallabag — {{type}} feed</title>
- <link>{{ url('unread') }}</link>
- <pubDate>{{ "now"|date('D, d M Y H:i:s') }}</pubDate>
- <generator>wallabag</generator>
- <description>wallabag {{type}} elements</description>
-
- {% for entry in entries %}
-
- <item>
- <title><![CDATA[{{ entry.title }}]]></title>
- <source url="{{ url('view', { 'id': entry.id }) }}">wallabag</source>
- <link>{{ entry.url }}</link>
- <guid>{{ entry.url }}</guid>
- <pubDate>{{ entry.createdAt|date('D, d M Y H:i:s') }}</pubDate>
- <description>
- <![CDATA[{%- if entry.readingTime > 0 -%}{{ 'entry.list.reading_time_minutes'|trans({'%readingTime%': entry.readingTime}) }}{%- else -%}{{ 'entry.list.reading_time_less_one_minute'|trans|raw }}{%- endif %}{{ entry.content|raw -}}]]>
- </description>
- </item>
-
- {% endfor %}
-
- </channel>
-</rss>
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'error.page_title'|trans }}{% endblock %}
+
+{% block body_class %}login{% endblock %}
+
+{% block menu %}{% endblock %}
+{% block messages %}{% endblock %}
+
+{% block content %}
+<main class="valign-wrapper">
+ <div class="valign row">
+ <div class="card sw">
+ <div class="center"><img src="{{ asset('bundles/wallabagcore/themes/_global/img/logo-other_themes.png') }}" alt="wallabag logo" /></div>
+ <div class="card-content">
+ <div class="row">
+ <h5>{{ status_code }}: {{ status_text }}</h5>
+ <p>{{ exception.message }}</p>
+ {# {% for trace in exception.trace %}
+ <p>{{ trace.class }} - {{ trace.type }} - {{ trace.file }} - {{ trace.line }}</p>
+ {% endfor %} #}
+ </div>
+ </div>
+ </div>
+ </div>
+</main>
+{% endblock %}
+
+{% block footer %}
+{% endblock %}
+++ /dev/null
-{% extends "WallabagCoreBundle::layout.html.twig" %}
-
-{% block title %}{{ 'quickstart.page_title'|trans }}{% endblock %}
-
-{% block content %}
-
- <div class="row">
- <div class="col s12">
- <div class="card-panel settings">
-
- <div class="row">
- <h3>{{ 'quickstart.intro.title'|trans }}</h3>
- <p>{{ 'quickstart.intro.paragraph_1'|trans }}</p>
- <p>{{ 'quickstart.intro.paragraph_2'|trans }}</p>
-
- <h4>{{ 'quickstart.configure.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('config') }}">{{ 'quickstart.configure.language'|trans }}</a></li>
- <li><a href="{{ path('config') }}#set2">{{ 'quickstart.configure.rss'|trans }}</a></li>
- <li><a href="{{ path('config') }}#set5">{{ 'quickstart.configure.tagging_rules'|trans }}</a></li>
- </ul>
-
- {% if is_granted('ROLE_SUPER_ADMIN') %}
- <h4>{{ 'quickstart.admin.title'|trans }}</h4>
- <p>{{ 'quickstart.admin.description'|trans }}</p>
- <ul>
- <li><a href="{{ path('config') }}#set6">{{ 'quickstart.admin.new_user'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-analytics">{{ 'quickstart.admin.analytics'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-entry">{{ 'quickstart.admin.sharing'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-export">{{ 'quickstart.admin.export'|trans }}</a></li>
- <li><a href="{{ path('craue_config_settings_modify') }}#set-import">{{ 'quickstart.admin.import'|trans }}</a></li>
- </ul>
- {% endif %}
-
- <h4>{{ 'quickstart.first_steps.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('new') }}">{{ 'quickstart.first_steps.new_article'|trans }}</a></li>
- <li><a href="{{ path('unread') }}">{{ 'quickstart.first_steps.unread_articles'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.migrate.title'|trans }}</h4>
- <p>{{ 'quickstart.migrate.description'|trans }}</p>
- <ul>
- <li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
- <li><a href="{{ path('import_wallabag_v1') }}">{{ 'quickstart.migrate.wallabag_v1'|trans }}</a></li>
- <li><a href="{{ path('import_wallabag_v2') }}">{{ 'quickstart.migrate.wallabag_v2'|trans }}</a></li>
- <li><a href="{{ path('import_readability') }}">{{ 'quickstart.migrate.readability'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.developer.title'|trans }}</h4>
- <ul>
- <li><a href="{{ path('developer') }}">{{ 'quickstart.developer.create_application'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.docs.title'|trans }}</h4>
- <ul>
- <li><a href="http://doc.wallabag.org/en/master/user/annotations.html">{{ 'quickstart.docs.annotate'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/user/download_articles.html">{{ 'quickstart.docs.export'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/user/filters.html">{{ 'quickstart.docs.search_filters'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/en/master/user/errors_during_fetching.html">{{ 'quickstart.docs.fetching_errors'|trans }}</a></li>
- <li><a href="http://doc.wallabag.org/">{{ 'quickstart.docs.all_docs'|trans }}</a></li>
- </ul>
-
- <h4>{{ 'quickstart.support.title'|trans }}</h4>
- <p>{{ 'quickstart.support.description'|trans }}</p>
- <ul>
- <li><a href="https://github.com/wallabag/wallabag/issues/">{{ 'quickstart.support.github'|trans }}</a></li>
- <li><a href="mailto:hello@wallabag.org">{{ 'quickstart.support.email'|trans }}</a></li>
- <li><a href="https://gitter.im/wallabag/wallabag">{{ 'quickstart.support.gitter'|trans }}</a></li>
- </ul>
- </div>
-
- </div>
- </div>
- </div>
-
-{% endblock %}
<li class="bold {% if currentRoute == 'archive' %}active{% endif %}">
<a class="waves-effect" href="{{ path('archive') }}">{{ 'menu.left.archive'|trans }} <span class="numberItems grey-text">{{ count_entries('archive') }}</span></a>
</li>
- <li class="bold border-bottom {% if currentRoute == 'all' %}active{% endif %}">
+ <li class="bold {% if currentRoute == 'all' %}active{% endif %}">
<a class="waves-effect" href="{{ path('all') }}">{{ 'menu.left.all_articles'|trans }} <span class="numberItems grey-text">{{ count_entries('all') }}</span></a>
</li>
<li class="bold border-bottom {% if currentRoute == 'tags' %}active{% endif %}">
<a class="waves-effect" href="{{ path('config') }}">{{ 'menu.left.config'|trans }}</a>
</li>
{% if is_granted('ROLE_SUPER_ADMIN') %}
+ <li class="bold {% if currentRoute starts with 'user_' %}active{% endif %}">
+ <a class="waves-effect" href="{{ path('user_index') }}">{{ 'menu.left.users_management'|trans }}</a>
+ </li>
+
<li class="bold border-bottom {% if currentRoute == 'craue_config_settings_modify' %}active{% endif %}">
<a class="waves-effect" href="{{ path('craue_config_settings_modify') }}">{{ 'menu.left.internal_settings'|trans }}</a>
</li>
<footer class="page-footer cyan darken-2">
<div class="footer-copyright">
<div class="container">
- <p>{{ 'footer.wallabag.powered_by'|trans }} <a target="_blank" href="https://wallabag.org" class="grey-text text-lighten-4">wallabag</a></p>
- <a class="grey-text text-lighten-4 right" href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans }}</a>
+ <div class="row">
+ <div class="col s8">
+ <p>
+ {{ display_stats() }}
+ </p>
+ </div>
+ <div class="col s4">
+ <p>
+ {{ 'footer.wallabag.powered_by'|trans }} <a target="_blank" href="https://wallabag.org" class="grey-text text-lighten-4">wallabag</a> –
+ <a class="grey-text text-lighten-4" href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans|lower }}</a>
+ </p>
+ </div>
+ </div>
</div>
</div>
</footer>
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Wallabag\CoreBundle\Repository\EntryRepository;
use Wallabag\CoreBundle\Repository\TagRepository;
+use Symfony\Component\Translation\TranslatorInterface;
class WallabagExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface
{
private $entryRepository;
private $tagRepository;
private $lifeTime;
+ private $translator;
- public function __construct(EntryRepository $entryRepository = null, TagRepository $tagRepository = null, TokenStorageInterface $tokenStorage = null, $lifeTime = 0)
+ public function __construct(EntryRepository $entryRepository, TagRepository $tagRepository, TokenStorageInterface $tokenStorage, $lifeTime, TranslatorInterface $translator)
{
$this->entryRepository = $entryRepository;
$this->tagRepository = $tagRepository;
$this->tokenStorage = $tokenStorage;
$this->lifeTime = $lifeTime;
+ $this->translator = $translator;
}
public function getFilters()
return array(
new \Twig_SimpleFunction('count_entries', [$this, 'countEntries']),
new \Twig_SimpleFunction('count_tags', [$this, 'countTags']),
+ new \Twig_SimpleFunction('display_stats', [$this, 'displayStats']),
);
}
return $this->tagRepository->countAllTags($user->getId());
}
+ /**
+ * Display a single line about reading stats.
+ *
+ * @return string
+ */
+ public function displayStats()
+ {
+ $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
+
+ if (null === $user || !is_object($user)) {
+ return 0;
+ }
+
+ $query = $this->entryRepository->getBuilderForArchiveByUser($user->getId())
+ ->select('e.id')
+ ->groupBy('e.id')
+ ->getQuery();
+
+ $query->useQueryCache(true);
+ $query->useResultCache(true);
+ $query->setResultCacheLifetime($this->lifeTime);
+
+ $nbArchives = count($query->getArrayResult());
+
+ $interval = $user->getCreatedAt()->diff(new \DateTime('now'));
+ $nbDays = (int) $interval->format('%a') ?: 1;
+
+ return $this->translator->trans('footer.stats', [
+ '%user_creation%' => $user->getCreatedAt()->format('F jS, Y'),
+ '%nb_archives%' => $nbArchives,
+ '%per_day%' => round($nbArchives / $nbDays, 2),
+ ]);
+ }
+
public function getName()
{
return 'wallabag_extension';
$this
->setName('wallabag:import:redis-worker')
->setDescription('Launch Redis worker')
- ->addArgument('serviceName', InputArgument::REQUIRED, 'Service to use: wallabag_v1, wallabag_v2, pocket or readability')
+ ->addArgument('serviceName', InputArgument::REQUIRED, 'Service to use: wallabag_v1, wallabag_v2, pocket, readability, firefox, chrome or instapaper')
->addOption('maxIterations', '', InputOption::VALUE_OPTIONAL, 'Number of iterations before stoping', false)
;
}
$nbRabbitMessages = $this->getTotalMessageInRabbitQueue('pocket')
+ $this->getTotalMessageInRabbitQueue('readability')
+ $this->getTotalMessageInRabbitQueue('wallabag_v1')
- + $this->getTotalMessageInRabbitQueue('wallabag_v2');
+ + $this->getTotalMessageInRabbitQueue('wallabag_v2')
+ + $this->getTotalMessageInRabbitQueue('firefox')
+ + $this->getTotalMessageInRabbitQueue('chrome')
+ + $this->getTotalMessageInRabbitQueue('instapaper')
+ ;
} catch (\Exception $e) {
$rabbitNotInstalled = true;
}
$nbRedisMessages = $redis->llen('wallabag.import.pocket')
+ $redis->llen('wallabag.import.readability')
+ $redis->llen('wallabag.import.wallabag_v1')
- + $redis->llen('wallabag.import.wallabag_v2');
+ + $redis->llen('wallabag.import.wallabag_v2')
+ + $redis->llen('wallabag.import.firefox')
+ + $redis->llen('wallabag.import.chrome')
+ + $redis->llen('wallabag.import.instapaper')
+ ;
} catch (\Exception $e) {
$redisNotInstalled = true;
}
--- /dev/null
+<?php
+
+namespace Wallabag\ImportBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Symfony\Component\HttpFoundation\Request;
+use Wallabag\ImportBundle\Form\Type\UploadImportType;
+
+class InstapaperController extends Controller
+{
+ /**
+ * @Route("/instapaper", name="import_instapaper")
+ */
+ public function indexAction(Request $request)
+ {
+ $form = $this->createForm(UploadImportType::class);
+ $form->handleRequest($request);
+
+ $instapaper = $this->get('wallabag_import.instapaper.import');
+ $instapaper->setUser($this->getUser());
+
+ if ($this->get('craue_config')->get('import_with_rabbitmq')) {
+ $instapaper->setProducer($this->get('old_sound_rabbit_mq.import_instapaper_producer'));
+ } elseif ($this->get('craue_config')->get('import_with_redis')) {
+ $instapaper->setProducer($this->get('wallabag_import.producer.redis.instapaper'));
+ }
+
+ if ($form->isValid()) {
+ $file = $form->get('file')->getData();
+ $markAsRead = $form->get('mark_as_read')->getData();
+ $name = 'instapaper_'.$this->getUser()->getId().'.csv';
+
+ if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+ $res = $instapaper
+ ->setFilepath($this->getParameter('wallabag_import.resource_dir').'/'.$name)
+ ->setMarkAsRead($markAsRead)
+ ->import();
+
+ $message = 'flashes.import.notice.failed';
+
+ if (true === $res) {
+ $summary = $instapaper->getSummary();
+ $message = $this->get('translator')->trans('flashes.import.notice.summary', [
+ '%imported%' => $summary['imported'],
+ '%skipped%' => $summary['skipped'],
+ ]);
+
+ if (0 < $summary['queued']) {
+ $message = $this->get('translator')->trans('flashes.import.notice.summary_with_queue', [
+ '%queued%' => $summary['queued'],
+ ]);
+ }
+
+ unlink($this->getParameter('wallabag_import.resource_dir').'/'.$name);
+ }
+
+ $this->get('session')->getFlashBag()->add(
+ 'notice',
+ $message
+ );
+
+ return $this->redirect($this->generateUrl('homepage'));
+ } else {
+ $this->get('session')->getFlashBag()->add(
+ 'notice',
+ 'flashes.import.notice.failed_on_file'
+ );
+ }
+ }
+
+ return $this->render('WallabagImportBundle:Instapaper:index.html.twig', [
+ 'form' => $form->createView(),
+ 'import' => $instapaper,
+ ]);
+ }
+}
$i = 1;
foreach ($entries as $importedEntry) {
+ if ($this->markAsRead) {
+ $importedEntry = $this->setEntryAsRead($importedEntry);
+ }
+
$entry = $this->parseEntry($importedEntry);
if (null === $entry) {
$data = json_decode(file_get_contents($this->filepath), true);
if (empty($data)) {
+ $this->logger->error('Wallabag Browser: no entries in imported file');
+
return false;
}
--- /dev/null
+<?php
+
+namespace Wallabag\ImportBundle\Import;
+
+use Wallabag\CoreBundle\Entity\Entry;
+
+class InstapaperImport extends AbstractImport
+{
+ private $filepath;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'Instapaper';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUrl()
+ {
+ return 'import_instapaper';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDescription()
+ {
+ return 'import.instapaper.description';
+ }
+
+ /**
+ * Set file path to the json file.
+ *
+ * @param string $filepath
+ */
+ public function setFilepath($filepath)
+ {
+ $this->filepath = $filepath;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function import()
+ {
+ if (!$this->user) {
+ $this->logger->error('InstapaperImport: user is not defined');
+
+ return false;
+ }
+
+ if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
+ $this->logger->error('InstapaperImport: unable to read file', ['filepath' => $this->filepath]);
+
+ return false;
+ }
+
+ $entries = [];
+ $handle = fopen($this->filepath, 'r');
+ while (($data = fgetcsv($handle, 10240)) !== false) {
+ if ('URL' === $data[0]) {
+ continue;
+ }
+
+ $entries[] = [
+ 'url' => $data[0],
+ 'title' => $data[1],
+ 'status' => $data[3],
+ 'is_archived' => $data[3] === 'Archive' || $data[3] === 'Starred',
+ 'is_starred' => $data[3] === 'Starred',
+ 'content_type' => '',
+ 'language' => '',
+ ];
+ }
+ fclose($handle);
+
+ if (empty($entries)) {
+ $this->logger->error('InstapaperImport: no entries in imported file');
+
+ return false;
+ }
+
+ if ($this->producer) {
+ $this->parseEntriesForProducer($entries);
+
+ return true;
+ }
+
+ $this->parseEntries($entries);
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseEntry(array $importedEntry)
+ {
+ $existingEntry = $this->em
+ ->getRepository('WallabagCoreBundle:Entry')
+ ->findByUrlAndUserId($importedEntry['url'], $this->user->getId());
+
+ if (false !== $existingEntry) {
+ ++$this->skippedEntries;
+
+ return;
+ }
+
+ $entry = new Entry($this->user);
+ $entry->setUrl($importedEntry['url']);
+ $entry->setTitle($importedEntry['title']);
+
+ // update entry with content (in case fetching failed, the given entry will be return)
+ $entry = $this->fetchContent($entry, $importedEntry['url'], $importedEntry);
+
+ $entry->setArchived($importedEntry['is_archived']);
+ $entry->setStarred($importedEntry['is_starred']);
+
+ $this->em->persist($entry);
+ ++$this->importedEntries;
+
+ return $entry;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setEntryAsRead(array $importedEntry)
+ {
+ $importedEntry['is_archived'] = 1;
+
+ return $importedEntry;
+ }
+}
$data = json_decode(file_get_contents($this->filepath), true);
if (empty($data) || empty($data['bookmarks'])) {
+ $this->logger->error('ReadabilityImport: no entries in imported file');
+
return false;
}
$data = json_decode(file_get_contents($this->filepath), true);
if (empty($data)) {
+ $this->logger->error('WallabagImport: no entries in imported file');
+
return false;
}
- "@wallabag_user.user_repository"
- "@wallabag_import.readability.import"
- "@logger"
+ wallabag_import.consumer.amqp.instapaper:
+ class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
+ arguments:
+ - "@doctrine.orm.entity_manager"
+ - "@wallabag_user.user_repository"
+ - "@wallabag_import.instapaper.import"
+ - "@logger"
wallabag_import.consumer.amqp.wallabag_v1:
class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
arguments:
- "@wallabag_import.readability.import"
- "@logger"
+ # instapaper
+ wallabag_import.queue.redis.instapaper:
+ class: Simpleue\Queue\RedisQueue
+ arguments:
+ - "@wallabag_core.redis.client"
+ - "wallabag.import.instapaper"
+
+ wallabag_import.producer.redis.instapaper:
+ class: Wallabag\ImportBundle\Redis\Producer
+ arguments:
+ - "@wallabag_import.queue.redis.instapaper"
+
+ wallabag_import.consumer.redis.instapaper:
+ class: Wallabag\ImportBundle\Consumer\RedisEntryConsumer
+ arguments:
+ - "@doctrine.orm.entity_manager"
+ - "@wallabag_user.user_repository"
+ - "@wallabag_import.instapaper.import"
+ - "@logger"
+
# pocket
wallabag_import.queue.redis.pocket:
class: Simpleue\Queue\RedisQueue
tags:
- { name: wallabag_import.import, alias: readability }
+ wallabag_import.instapaper.import:
+ class: Wallabag\ImportBundle\Import\InstapaperImport
+ arguments:
+ - "@doctrine.orm.entity_manager"
+ - "@wallabag_core.content_proxy"
+ calls:
+ - [ setLogger, [ "@logger" ]]
+ tags:
+ - { name: wallabag_import.import, alias: instapaper }
+
wallabag_import.firefox.import:
class: Wallabag\ImportBundle\Import\FirefoxImport
arguments:
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'import.instapaper.page_title'|trans }}{% endblock %}
+
+{% block content %}
+<div class="row">
+ <div class="col s12">
+ <div class="card-panel settings">
+ {% include 'WallabagImportBundle:Import:_workerEnabled.html.twig' %}
+
+ <div class="row">
+ <blockquote>{{ import.description|trans }}</blockquote>
+ <p>{{ 'import.instapaper.how_to'|trans }}</p>
+
+ <div class="col s12">
+ {{ form_start(form, {'method': 'POST'}) }}
+ {{ form_errors(form) }}
+ <div class="row">
+ <div class="file-field input-field col s12">
+ {{ form_errors(form.file) }}
+ <div class="btn">
+ <span>{{ form.file.vars.label|trans }}</span>
+ {{ form_widget(form.file) }}
+ </div>
+ <div class="file-path-wrapper">
+ <input class="file-path validate" type="text">
+ </div>
+ </div>
+ <div class="input-field col s6 with-checkbox">
+ <h6>{{ 'import.form.mark_as_read_title'|trans }}</h6>
+ {{ form_widget(form.mark_as_read) }}
+ {{ form_label(form.mark_as_read) }}
+ </div>
+ </div>
+
+ {{ form_widget(form.save, { 'attr': {'class': 'btn waves-effect waves-light'} }) }}
+
+ {{ form_rest(form) }}
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{% endblock %}
--- /dev/null
+<?php
+
+namespace Wallabag\UserBundle\Controller;
+
+use FOS\UserBundle\Event\UserEvent;
+use FOS\UserBundle\FOSUserEvents;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Wallabag\UserBundle\Entity\User;
+use Wallabag\CoreBundle\Entity\Config;
+
+/**
+ * User controller.
+ */
+class ManageController extends Controller
+{
+ /**
+ * Lists all User entities.
+ *
+ * @Route("/", name="user_index")
+ * @Method("GET")
+ */
+ public function indexAction()
+ {
+ $em = $this->getDoctrine()->getManager();
+
+ $users = $em->getRepository('WallabagUserBundle:User')->findAll();
+
+ return $this->render('WallabagUserBundle:Manage:index.html.twig', array(
+ 'users' => $users,
+ ));
+ }
+
+ /**
+ * Creates a new User entity.
+ *
+ * @Route("/new", name="user_new")
+ * @Method({"GET", "POST"})
+ */
+ public function newAction(Request $request)
+ {
+ $userManager = $this->container->get('fos_user.user_manager');
+
+ $user = $userManager->createUser();
+ // enable created user by default
+ $user->setEnabled(true);
+
+ $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [
+ 'validation_groups' => ['Profile'],
+ ]);
+ $form->handleRequest($request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $userManager->updateUser($user);
+
+ // dispatch a created event so the associated config will be created
+ $event = new UserEvent($user, $request);
+ $this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
+
+ $this->get('session')->getFlashBag()->add(
+ 'notice',
+ $this->get('translator')->trans('flashes.user.notice.added', ['%username%' => $user->getUsername()])
+ );
+
+ return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
+ }
+
+ return $this->render('WallabagUserBundle:Manage:new.html.twig', array(
+ 'user' => $user,
+ 'form' => $form->createView(),
+ ));
+ }
+
+ /**
+ * Displays a form to edit an existing User entity.
+ *
+ * @Route("/{id}/edit", name="user_edit")
+ * @Method({"GET", "POST"})
+ */
+ public function editAction(Request $request, User $user)
+ {
+ $deleteForm = $this->createDeleteForm($user);
+ $editForm = $this->createForm('Wallabag\UserBundle\Form\UserType', $user);
+ $editForm->handleRequest($request);
+
+ if ($editForm->isSubmitted() && $editForm->isValid()) {
+ $em = $this->getDoctrine()->getManager();
+ $em->persist($user);
+ $em->flush();
+
+ $this->get('session')->getFlashBag()->add(
+ 'notice',
+ $this->get('translator')->trans('flashes.user.notice.updated', ['%username%' => $user->getUsername()])
+ );
+
+ return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
+ }
+
+ return $this->render('WallabagUserBundle:Manage:edit.html.twig', array(
+ 'user' => $user,
+ 'edit_form' => $editForm->createView(),
+ 'delete_form' => $deleteForm->createView(),
+ 'twofactor_auth' => $this->getParameter('twofactor_auth'),
+ ));
+ }
+
+ /**
+ * Deletes a User entity.
+ *
+ * @Route("/{id}", name="user_delete")
+ * @Method("DELETE")
+ */
+ public function deleteAction(Request $request, User $user)
+ {
+ $form = $this->createDeleteForm($user);
+ $form->handleRequest($request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $this->get('session')->getFlashBag()->add(
+ 'notice',
+ $this->get('translator')->trans('flashes.user.notice.deleted', ['%username%' => $user->getUsername()])
+ );
+
+ $em = $this->getDoctrine()->getManager();
+ $em->remove($user);
+ $em->flush();
+ }
+
+ return $this->redirectToRoute('user_index');
+ }
+
+ /**
+ * Creates a form to delete a User entity.
+ *
+ * @param User $user The User entity
+ *
+ * @return \Symfony\Component\Form\Form The form
+ */
+ private function createDeleteForm(User $user)
+ {
+ return $this->createFormBuilder()
+ ->setAction($this->generateUrl('user_delete', array('id' => $user->getId())))
+ ->setMethod('DELETE')
+ ->getForm()
+ ;
+ }
+}
protected $entries;
/**
- * @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user")
+ * @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user", cascade={"remove"})
*/
protected $config;
<?php
-namespace Wallabag\CoreBundle\EventListener;
+namespace Wallabag\UserBundle\EventListener;
use Doctrine\ORM\EntityManager;
-use FOS\UserBundle\Event\FilterUserResponseEvent;
+use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Wallabag\CoreBundle\Entity\Config;
-class RegistrationConfirmedListener implements EventSubscriberInterface
+/**
+ * This listener will create the associated configuration when a user register.
+ * This configuration will be created right after the registration (no matter if it needs an email validation).
+ */
+class CreateConfigListener implements EventSubscriberInterface
{
private $em;
private $theme;
private $itemsOnPage;
private $rssLimit;
private $language;
+ private $readingSpeed;
- public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language)
+ public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language, $readingSpeed)
{
$this->em = $em;
$this->theme = $theme;
$this->itemsOnPage = $itemsOnPage;
$this->rssLimit = $rssLimit;
$this->language = $language;
+ $this->readingSpeed = $readingSpeed;
}
public static function getSubscribedEvents()
{
return [
- FOSUserEvents::REGISTRATION_CONFIRMED => 'authenticate',
+ // when a user register using the normal form
+ FOSUserEvents::REGISTRATION_COMPLETED => 'createConfig',
+ // when we manually create a user using the command line
+ // OR when we create it from the config UI
+ FOSUserEvents::USER_CREATED => 'createConfig',
];
}
- public function authenticate(FilterUserResponseEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null)
+ public function createConfig(UserEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null)
{
if (!$event->getUser()->isEnabled()) {
return;
$config->setItemsPerPage($this->itemsOnPage);
$config->setRssLimit($this->rssLimit);
$config->setLanguage($this->language);
+ $config->setReadingSpeed($this->readingSpeed);
+
$this->em->persist($config);
$this->em->flush();
}
<?php
-namespace Wallabag\CoreBundle\Form\Type;
+namespace Wallabag\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
$builder
->add('username', TextType::class, [
'required' => true,
- 'label' => 'config.form_new_user.username_label',
+ 'label' => 'user.form.username_label',
])
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'invalid_message' => 'validator.password_must_match',
- 'first_options' => ['label' => 'config.form_new_user.password_label'],
- 'second_options' => ['label' => 'config.form_new_user.repeat_new_password_label'],
+ 'first_options' => ['label' => 'user.form.password_label'],
+ 'second_options' => ['label' => 'user.form.repeat_new_password_label'],
'constraints' => [
new Constraints\Length([
'min' => 8,
]),
new Constraints\NotBlank(),
],
- 'label' => 'config.form_new_user.plain_password_label',
+ 'label' => 'user.form.plain_password_label',
])
->add('email', EmailType::class, [
- 'label' => 'config.form_new_user.email_label',
+ 'label' => 'user.form.email_label',
])
->add('save', SubmitType::class, [
- 'label' => 'config.form.save',
+ 'label' => 'user.form.save',
])
;
}
--- /dev/null
+<?php
+
+namespace Wallabag\UserBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Form\Extension\Core\Type\EmailType;
+
+class UserType extends AbstractType
+{
+ /**
+ * @param FormBuilderInterface $builder
+ * @param array $options
+ */
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder
+ ->add('name', TextType::class, [
+ 'required' => false,
+ 'label' => 'user.form.name_label',
+ ])
+ ->add('username', TextType::class, [
+ 'required' => true,
+ 'label' => 'user.form.username_label',
+ ])
+ ->add('email', EmailType::class, [
+ 'required' => true,
+ 'label' => 'user.form.email_label',
+ ])
+ ->add('enabled', CheckboxType::class, [
+ 'required' => false,
+ 'label' => 'user.form.enabled_label',
+ ])
+ ->add('locked', CheckboxType::class, [
+ 'required' => false,
+ 'label' => 'user.form.locked_label',
+ ])
+ ->add('twoFactorAuthentication', CheckboxType::class, [
+ 'required' => false,
+ 'label' => 'user.form.twofactor_label',
+ ])
+ ->add('save', SubmitType::class, [
+ 'label' => 'user.form.save',
+ ])
+ ;
+ }
+
+ /**
+ * @param OptionsResolver $resolver
+ */
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults(array(
+ 'data_class' => 'Wallabag\UserBundle\Entity\User',
+ ));
+ }
+}
factory: [ "@doctrine.orm.default_entity_manager", getRepository ]
arguments:
- WallabagUserBundle:User
+
+ wallabag_user.create_config:
+ class: Wallabag\UserBundle\EventListener\CreateConfigListener
+ arguments:
+ - "@doctrine.orm.entity_manager"
+ - "%wallabag_core.theme%"
+ - "%wallabag_core.items_on_page%"
+ - "%wallabag_core.rss_limit%"
+ - "%wallabag_core.language%"
+ - "%wallabag_core.reading_speed%"
+ tags:
+ - { name: kernel.event_subscriber }
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'user.page_title'|trans }}{% endblock %}
+
+{% block content %}
+
+ <div class="row">
+ <div class="col s12">
+ <div class="card-panel">
+ <div class="row">
+ <div class="input-field col s12">
+ <h4>{{ 'user.edit_user'|trans }}</h4>
+
+ <div id="set6" class="col s12">
+ {{ form_start(edit_form) }}
+ {{ form_errors(edit_form) }}
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(edit_form.name) }}
+ {{ form_errors(edit_form.name) }}
+ {{ form_widget(edit_form.name) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(edit_form.username) }}
+ {{ form_errors(edit_form.username) }}
+ {{ form_widget(edit_form.username) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(edit_form.email) }}
+ {{ form_errors(edit_form.email) }}
+ {{ form_widget(edit_form.email) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_widget(edit_form.enabled) }}
+ {{ form_label(edit_form.enabled) }}
+ {{ form_errors(edit_form.enabled) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_widget(edit_form.locked) }}
+ {{ form_label(edit_form.locked) }}
+ {{ form_errors(edit_form.locked) }}
+ </div>
+ </div>
+
+ {% if twofactor_auth %}
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_widget(edit_form.twoFactorAuthentication) }}
+ {{ form_label(edit_form.twoFactorAuthentication) }}
+ {{ form_errors(edit_form.twoFactorAuthentication) }}
+ </div>
+ </div>
+ {% endif %}
+
+ <br/>
+
+ {{ form_widget(edit_form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
+ {{ form_rest(edit_form) }}
+ </form>
+ <p>
+ {{ form_start(delete_form) }}
+ <button {% if app.user.id == user.id %}disabled="disabled"{% endif %} onclick="return confirm('{{ 'user.form.delete_confirm'|trans|escape('js') }}')" type="submit" class="btn waves-effect waves-light red">{{ 'user.form.delete'|trans }}</button>
+ {{ form_end(delete_form) }}
+ </p>
+ <p><a class="waves-effect waves-light btn blue-grey" href="{{ path('user_index') }}">{{ 'user.form.back_to_list'|trans }}</a></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+{% endblock %}
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'user.page_title'|trans }}{% endblock %}
+
+{% block content %}
+
+ <div class="row">
+ <div class="col s12">
+ <div class="card-panel">
+ <div class="row">
+ <div class="input-field col s12">
+ <p class="help">{{ 'user.description'|trans|raw }}</p>
+
+ <table class="bordered">
+ <thead>
+ <tr>
+ <th>{{ 'user.form.username_label'|trans }}</th>
+ <th>{{ 'user.form.email_label'|trans }}</th>
+ <th>{{ 'user.form.last_login_label'|trans }}</th>
+ <th>{{ 'user.form.locked_label'|trans }}</th>
+ <th>{{ 'user.list.actions'|trans }}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for user in users %}
+ <tr>
+ <td>{{ user.username }}</td>
+ <td>{{ user.email }}</td>
+ <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td>
+ <td>{% if user.locked %}{{ 'user.list.yes'|trans }}{% else %}{{ 'user.list.no'|trans }}{% endif %}</td>
+ <td>
+ <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ <br />
+ <p>
+ <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+{% endblock %}
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'user.page_title'|trans }}{% endblock %}
+
+{% block content %}
+
+ <div class="row">
+ <div class="col s12">
+ <div class="card-panel">
+ <div class="row">
+ <div class="input-field col s12">
+ <h4>{{ 'user.new_user'|trans }}</h4>
+
+ <div id="set6" class="col s12">
+ {{ form_start(form) }}
+ {{ form_errors(form) }}
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(form.username) }}
+ {{ form_errors(form.username) }}
+ {{ form_widget(form.username) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(form.plainPassword.first) }}
+ {{ form_errors(form.plainPassword.first) }}
+ {{ form_widget(form.plainPassword.first) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(form.plainPassword.second) }}
+ {{ form_errors(form.plainPassword.second) }}
+ {{ form_widget(form.plainPassword.second) }}
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ {{ form_label(form.email) }}
+ {{ form_errors(form.email) }}
+ {{ form_widget(form.email) }}
+ </div>
+ </div>
+
+ {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
+ {{ form_rest(form) }}
+ </form>
+ <p><a class="waves-effect waves-light btn blue-grey" href="{{ path('user_index') }}">{{ 'user.form.back_to_list'|trans }}</a></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+{% endblock %}
--- /dev/null
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{{ 'user.manage.page_title'|trans }}{% endblock %}
+
+{% block content %}
+
+ <div class="row">
+ <div class="col s12">
+ <div class="card-panel">
+ <div class="row">
+ <div class="input-field col s12">
+ <p class="help">{{ 'user.manage.description'|trans|raw }}</p>
+
+ <table class="bordered">
+ <thead>
+ <tr>
+ <th>{{ 'user.manage.field.username'|trans }}</th>
+ <th>{{ 'user.manage.field.email'|trans }}</th>
+ <th>{{ 'user.manage.field.last_login'|trans }}</th>
+ <th>{{ 'user.manage.field.locked'|trans }}</th>
+ <th>{{ 'user.manage.action'|trans }}</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {% for user in users %}
+ <tr>
+ <td>{{ user.username }}</td>
+ <td>{{ user.email }}</td>
+ <td>{{ user.lastLogin|date('d/m/Y H:i:s') }}</td>
+ <td>{{ user.locked ? 'yes' : 'no' }}</td>
+ <td>edit - delete</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+{% endblock %}
);
}
+ public function testGetEntriesWithFullOptions()
+ {
+ $this->client->request('GET', '/api/entries', [
+ 'archive' => 1,
+ 'starred' => 1,
+ 'sort' => 'updated',
+ 'order' => 'asc',
+ 'page' => 1,
+ 'perPage' => 2,
+ 'tags' => 'foo',
+ 'since' => 1443274283,
+ ]);
+
+ $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
+
+ $content = json_decode($this->client->getResponse()->getContent(), true);
+
+ $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertArrayHasKey('items', $content['_embedded']);
+ $this->assertGreaterThanOrEqual(0, $content['total']);
+ $this->assertEquals(1, $content['page']);
+ $this->assertEquals(2, $content['limit']);
+ $this->assertGreaterThanOrEqual(1, $content['pages']);
+
+ $this->assertArrayHasKey('_links', $content);
+ $this->assertArrayHasKey('self', $content['_links']);
+ $this->assertArrayHasKey('first', $content['_links']);
+ $this->assertArrayHasKey('last', $content['_links']);
+
+ foreach (['self', 'first', 'last'] as $link) {
+ $this->assertArrayHasKey('href', $content['_links'][$link]);
+ $this->assertContains('archive=1', $content['_links'][$link]['href']);
+ $this->assertContains('starred=1', $content['_links'][$link]['href']);
+ $this->assertContains('sort=updated', $content['_links'][$link]['href']);
+ $this->assertContains('order=asc', $content['_links'][$link]['href']);
+ $this->assertContains('tags=foo', $content['_links'][$link]['href']);
+ $this->assertContains('since=1443274283', $content['_links'][$link]['href']);
+ }
+
+ $this->assertTrue(
+ $this->client->getResponse()->headers->contains(
+ 'Content-Type',
+ 'application/json'
+ )
+ );
+ }
+
public function testGetStarredEntries()
{
$this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated']);
$this->assertEquals(1, $content['page']);
$this->assertGreaterThanOrEqual(1, $content['pages']);
+ $this->assertArrayHasKey('_links', $content);
+ $this->assertArrayHasKey('self', $content['_links']);
+ $this->assertArrayHasKey('first', $content['_links']);
+ $this->assertArrayHasKey('last', $content['_links']);
+
+ foreach (['self', 'first', 'last'] as $link) {
+ $this->assertArrayHasKey('href', $content['_links'][$link]);
+ $this->assertContains('starred=1', $content['_links'][$link]['href']);
+ $this->assertContains('sort=updated', $content['_links'][$link]['href']);
+ }
+
$this->assertTrue(
$this->client->getResponse()->headers->contains(
'Content-Type',
$this->assertEquals(1, $content['page']);
$this->assertGreaterThanOrEqual(1, $content['pages']);
+ $this->assertArrayHasKey('_links', $content);
+ $this->assertArrayHasKey('self', $content['_links']);
+ $this->assertArrayHasKey('first', $content['_links']);
+ $this->assertArrayHasKey('last', $content['_links']);
+
+ foreach (['self', 'first', 'last'] as $link) {
+ $this->assertArrayHasKey('href', $content['_links'][$link]);
+ $this->assertContains('archive=1', $content['_links'][$link]['href']);
+ }
+
$this->assertTrue(
$this->client->getResponse()->headers->contains(
'Content-Type',
$this->assertEquals(1, $content['page']);
$this->assertGreaterThanOrEqual(1, $content['pages']);
+ $this->assertArrayHasKey('_links', $content);
+ $this->assertArrayHasKey('self', $content['_links']);
+ $this->assertArrayHasKey('first', $content['_links']);
+ $this->assertArrayHasKey('last', $content['_links']);
+
+ foreach (['self', 'first', 'last'] as $link) {
+ $this->assertArrayHasKey('href', $content['_links'][$link]);
+ $this->assertContains('tags='.urlencode('foo,bar'), $content['_links'][$link]['href']);
+ }
+
$this->assertTrue(
$this->client->getResponse()->headers->contains(
'Content-Type',
public function testGetDatedEntries()
{
- $this->client->request('GET', '/api/entries', ['since' => 1]);
+ $this->client->request('GET', '/api/entries', ['since' => 1443274283]);
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
$this->assertEquals(1, $content['page']);
$this->assertGreaterThanOrEqual(1, $content['pages']);
+ $this->assertArrayHasKey('_links', $content);
+ $this->assertArrayHasKey('self', $content['_links']);
+ $this->assertArrayHasKey('first', $content['_links']);
+ $this->assertArrayHasKey('last', $content['_links']);
+
+ foreach (['self', 'first', 'last'] as $link) {
+ $this->assertArrayHasKey('href', $content['_links'][$link]);
+ $this->assertContains('since=1443274283', $content['_links'][$link]['href']);
+ }
+
$this->assertTrue(
$this->client->getResponse()->headers->contains(
'Content-Type',
$this->assertEquals(1, $content['page']);
$this->assertEquals(1, $content['pages']);
+ $this->assertArrayHasKey('_links', $content);
+ $this->assertArrayHasKey('self', $content['_links']);
+ $this->assertArrayHasKey('first', $content['_links']);
+ $this->assertArrayHasKey('last', $content['_links']);
+
+ foreach (['self', 'first', 'last'] as $link) {
+ $this->assertArrayHasKey('href', $content['_links'][$link]);
+ $this->assertContains('since='.($future->getTimestamp() + 1000), $content['_links'][$link]['href']);
+ }
+
$this->assertTrue(
$this->client->getResponse()->headers->contains(
'Content-Type',
$this->assertEquals(true, $content['is_starred']);
}
+
+ public function testGetEntriesExists()
+ {
+ $this->client->request('GET', '/api/entries/exists?url=http://0.0.0.0/entry2');
+
+ $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
+
+ $content = json_decode($this->client->getResponse()->getContent(), true);
+
+ $this->assertEquals(true, $content['exists']);
+ }
+
+ public function testGetEntriesExistsWhichDoesNotExists()
+ {
+ $this->client->request('GET', '/api/entries/exists?url=http://google.com/entry2');
+
+ $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
+
+ $content = json_decode($this->client->getResponse()->getContent(), true);
+
+ $this->assertEquals(false, $content['exists']);
+ }
}
$this->assertCount(1, $crawler->filter('button[id=config_save]'));
$this->assertCount(1, $crawler->filter('button[id=change_passwd_save]'));
$this->assertCount(1, $crawler->filter('button[id=update_user_save]'));
- $this->assertCount(1, $crawler->filter('button[id=new_user_save]'));
$this->assertCount(1, $crawler->filter('button[id=rss_config_save]'));
}
$crawler = $client->followRedirect();
- $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
- $this->assertContains('flashes.config.notice.config_saved', $alert[0]);
+ $this->assertContains('flashes.config.notice.config_saved', $crawler->filter('body')->extract(['_text'])[0]);
}
public function testChangeReadingSpeed()
$crawler = $client->followRedirect();
- $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
- $this->assertContains('flashes.config.notice.password_updated', $alert[0]);
+ $this->assertContains('flashes.config.notice.password_updated', $crawler->filter('body')->extract(['_text'])[0]);
}
public function dataForUserFailed()
$this->assertContains('flashes.config.notice.user_updated', $alert[0]);
}
- public function dataForNewUserFailed()
- {
- return [
- [
- [
- 'new_user[username]' => '',
- 'new_user[plainPassword][first]' => '',
- 'new_user[plainPassword][second]' => '',
- 'new_user[email]' => '',
- ],
- 'fos_user.username.blank',
- ],
- [
- [
- 'new_user[username]' => 'a',
- 'new_user[plainPassword][first]' => 'mypassword',
- 'new_user[plainPassword][second]' => 'mypassword',
- 'new_user[email]' => '',
- ],
- 'fos_user.username.short',
- ],
- [
- [
- 'new_user[username]' => 'wallace',
- 'new_user[plainPassword][first]' => 'mypassword',
- 'new_user[plainPassword][second]' => 'mypassword',
- 'new_user[email]' => 'test',
- ],
- 'fos_user.email.invalid',
- ],
- [
- [
- 'new_user[username]' => 'admin',
- 'new_user[plainPassword][first]' => 'wallacewallace',
- 'new_user[plainPassword][second]' => 'wallacewallace',
- 'new_user[email]' => 'wallace@wallace.me',
- ],
- 'fos_user.username.already_used',
- ],
- [
- [
- 'new_user[username]' => 'wallace',
- 'new_user[plainPassword][first]' => 'mypassword1',
- 'new_user[plainPassword][second]' => 'mypassword2',
- 'new_user[email]' => 'wallace@wallace.me',
- ],
- 'validator.password_must_match',
- ],
- ];
- }
-
- /**
- * @dataProvider dataForNewUserFailed
- */
- public function testNewUserFailed($data, $expectedMessage)
- {
- $this->logInAs('admin');
- $client = $this->getClient();
-
- $crawler = $client->request('GET', '/config');
-
- $this->assertEquals(200, $client->getResponse()->getStatusCode());
-
- $form = $crawler->filter('button[id=new_user_save]')->form();
-
- $crawler = $client->submit($form, $data);
-
- $this->assertEquals(200, $client->getResponse()->getStatusCode());
-
- $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(['_text']));
- $this->assertContains($expectedMessage, $alert[0]);
- }
-
- public function testNewUserCreated()
- {
- $this->logInAs('admin');
- $client = $this->getClient();
-
- $crawler = $client->request('GET', '/config');
-
- $this->assertEquals(200, $client->getResponse()->getStatusCode());
-
- $form = $crawler->filter('button[id=new_user_save]')->form();
-
- $data = [
- 'new_user[username]' => 'wallace',
- 'new_user[plainPassword][first]' => 'wallace1',
- 'new_user[plainPassword][second]' => 'wallace1',
- 'new_user[email]' => 'wallace@wallace.me',
- ];
-
- $client->submit($form, $data);
-
- $this->assertEquals(302, $client->getResponse()->getStatusCode());
-
- $crawler = $client->followRedirect();
-
- $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
- $this->assertContains('flashes.config.notice.user_added', $alert[0]);
-
- $em = $client->getContainer()->get('doctrine.orm.entity_manager');
- $user = $em
- ->getRepository('WallabagUserBundle:User')
- ->findOneByUsername('wallace');
-
- $this->assertTrue(false !== $user);
- $this->assertTrue($user->isEnabled());
- $this->assertEquals('material', $user->getConfig()->getTheme());
- $this->assertEquals(12, $user->getConfig()->getItemsPerPage());
- $this->assertEquals(50, $user->getConfig()->getRssLimit());
- $this->assertEquals('en', $user->getConfig()->getLanguage());
- $this->assertEquals(1, $user->getConfig()->getReadingSpeed());
- }
-
public function testRssUpdateResetToken()
{
$this->logInAs('admin');
$crawler = $client->followRedirect();
- $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
- $this->assertContains('flashes.config.notice.rss_updated', $alert[0]);
+ $this->assertContains('flashes.config.notice.rss_updated', $crawler->filter('body')->extract(['_text'])[0]);
}
public function dataForRssFailed()
$crawler = $client->followRedirect();
- $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
- $this->assertContains('flashes.config.notice.tagging_rules_updated', $alert[0]);
+ $this->assertContains('flashes.config.notice.tagging_rules_updated', $crawler->filter('body')->extract(['_text'])[0]);
+
+ $editLink = $crawler->filter('.mode_edit')->last()->link();
+
+ $crawler = $client->click($editLink);
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+ $this->assertContains('?tagging-rule=', $client->getResponse()->headers->get('location'));
+
+ $crawler = $client->followRedirect();
+
+ $form = $crawler->filter('button[id=tagging_rule_save]')->form();
+
+ $data = [
+ 'tagging_rule[rule]' => 'readingTime <= 30',
+ 'tagging_rule[tags]' => 'short reading',
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+ $crawler = $client->followRedirect();
+
+ $this->assertContains('flashes.config.notice.tagging_rules_updated', $crawler->filter('body')->extract(['_text'])[0]);
+
+ $this->assertContains('readingTime <= 30', $crawler->filter('body')->extract(['_text'])[0]);
$deleteLink = $crawler->filter('.delete')->last()->link();
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$crawler = $client->followRedirect();
- $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
- $this->assertContains('flashes.config.notice.tagging_rules_deleted', $alert[0]);
+ $this->assertContains('flashes.config.notice.tagging_rules_deleted', $crawler->filter('body')->extract(['_text'])[0]);
}
public function dataForTaggingRuleFailed()
->getRepository('WallabagCoreBundle:TaggingRule')
->findAll()[0];
- $crawler = $client->request('GET', '/tagging-rule/delete/'.$rule->getId());
+ $crawler = $client->request('GET', '/tagging-rule/edit/'.$rule->getId());
+
+ $this->assertEquals(403, $client->getResponse()->getStatusCode());
+ $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
+ $this->assertContains('You can not access this tagging rule', $body[0]);
+ }
+
+ public function testEditingTaggingRuleFromAnOtherUser()
+ {
+ $this->logInAs('bob');
+ $client = $this->getClient();
+
+ $rule = $client->getContainer()->get('doctrine.orm.entity_manager')
+ ->getRepository('WallabagCoreBundle:TaggingRule')
+ ->findAll()[0];
+
+ $crawler = $client->request('GET', '/tagging-rule/edit/'.$rule->getId());
$this->assertEquals(403, $client->getResponse()->getStatusCode());
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
$this->assertEquals(200, $client->getResponse()->getStatusCode());
$this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
- $this->assertContains('quickstart.intro.paragraph_1', $body[0]);
+ $this->assertContains('quickstart.intro.title', $body[0]);
// Test if quickstart is disabled when user has 1 entry
$crawler = $client->request('GET', '/new');
$this->assertContains('/view/', $client->getResponse()->getTargetUrl());
}
+ public function testPostNewOkUrlExistWithAccent()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $url = 'http://www.aritylabs.com/post/106091708292/des-contr%C3%B4leurs-optionnels-gr%C3%A2ce-%C3%A0-constmissing';
+
+ $crawler = $client->request('GET', '/new');
+
+ $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+ $form = $crawler->filter('form[name=entry]')->form();
+
+ $data = [
+ 'entry[url]' => $url,
+ ];
+
+ $client->submit($form, $data);
+
+ $crawler = $client->request('GET', '/new');
+
+ $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+ $form = $crawler->filter('form[name=entry]')->form();
+
+ $data = [
+ 'entry[url]' => $url,
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+ $this->assertContains('/view/', $client->getResponse()->getTargetUrl());
+
+ $em = $client->getContainer()
+ ->get('doctrine.orm.entity_manager');
+ $entry = $em
+ ->getRepository('WallabagCoreBundle:Entry')
+ ->findOneByUrl(urldecode($url));
+
+ $em->remove($entry);
+ $em->flush();
+ }
+
/**
* This test will require an internet connection.
*/
$this->assertEquals(1, count($entry->getTags()));
- # tag already exists and already assigned
+ // tag already exists and already assigned
$client->submit($form, $data);
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertEquals(1, count($newEntry->getTags()));
- # tag already exists but still not assigned to this entry
+ // tag already exists but still not assigned to this entry
$data = [
'tag[label]' => 'foo',
];
$this->assertTrue($converter->supports($params));
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Route attribute is missing
- */
public function testApplyEmptyRequest()
{
$params = new ParamConverter([]);
$converter = new UsernameRssTokenConverter();
- $converter->apply(new Request(), $params);
+ $res = $converter->apply(new Request(), $params);
+
+ $this->assertFalse($res);
}
/**
{
public function testRemoveWww()
{
- $extension = new WallabagExtension();
+ $entryRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $tagRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\TagRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $extension = new WallabagExtension($entryRepository, $tagRepository, $tokenStorage, 0, $translator);
$this->assertEquals('lemonde.fr', $extension->removeWww('www.lemonde.fr'));
$this->assertEquals('lemonde.fr', $extension->removeWww('lemonde.fr'));
/**
* Check if Redis is installed.
- * If not, mark test as skip
+ * If not, mark test as skip.
*/
protected function checkRedis()
{
$crawler = $client->request('GET', '/import/');
$this->assertEquals(200, $client->getResponse()->getStatusCode());
- $this->assertEquals(6, $crawler->filter('blockquote')->count());
+ $this->assertEquals(7, $crawler->filter('blockquote')->count());
}
}
--- /dev/null
+<?php
+
+namespace Tests\Wallabag\ImportBundle\Controller;
+
+use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
+use Symfony\Component\HttpFoundation\File\UploadedFile;
+
+class InstapaperControllerTest extends WallabagCoreTestCase
+{
+ public function testImportInstapaper()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/import/instapaper');
+
+ $this->assertEquals(200, $client->getResponse()->getStatusCode());
+ $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
+ $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
+ }
+
+ public function testImportInstapaperWithRabbitEnabled()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
+
+ $crawler = $client->request('GET', '/import/instapaper');
+
+ $this->assertEquals(200, $client->getResponse()->getStatusCode());
+ $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
+ $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
+
+ $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
+ }
+
+ public function testImportInstapaperBadFile()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/import/instapaper');
+ $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+ $data = [
+ 'upload_import_file[file]' => '',
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(200, $client->getResponse()->getStatusCode());
+ }
+
+ public function testImportInstapaperWithRedisEnabled()
+ {
+ $this->checkRedis();
+ $this->logInAs('admin');
+ $client = $this->getClient();
+ $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
+
+ $crawler = $client->request('GET', '/import/instapaper');
+
+ $this->assertEquals(200, $client->getResponse()->getStatusCode());
+ $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
+ $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
+
+ $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+ $file = new UploadedFile(__DIR__.'/../fixtures/instapaper-export.csv', 'instapaper.csv');
+
+ $data = [
+ 'upload_import_file[file]' => $file,
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+ $crawler = $client->followRedirect();
+
+ $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
+ $this->assertContains('flashes.import.notice.summary', $body[0]);
+
+ $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.instapaper'));
+
+ $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
+ }
+
+ public function testImportInstapaperWithFile()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/import/instapaper');
+ $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+ $file = new UploadedFile(__DIR__.'/../fixtures/instapaper-export.csv', 'instapaper.csv');
+
+ $data = [
+ 'upload_import_file[file]' => $file,
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+ $crawler = $client->followRedirect();
+
+ $content = $client->getContainer()
+ ->get('doctrine.orm.entity_manager')
+ ->getRepository('WallabagCoreBundle:Entry')
+ ->findByUrlAndUserId(
+ 'http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551',
+ $this->getLoggedInUserId()
+ );
+
+ $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
+ $this->assertContains('flashes.import.notice.summary', $body[0]);
+
+ $this->assertNotEmpty($content->getMimetype());
+ $this->assertNotEmpty($content->getPreviewPicture());
+ $this->assertNotEmpty($content->getLanguage());
+ $this->assertEquals(0, count($content->getTags()));
+ $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
+ }
+
+ public function testImportInstapaperWithFileAndMarkAllAsRead()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/import/instapaper');
+ $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+ $file = new UploadedFile(__DIR__.'/../fixtures/instapaper-export.csv', 'instapaper-read.csv');
+
+ $data = [
+ 'upload_import_file[file]' => $file,
+ 'upload_import_file[mark_as_read]' => 1,
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+ $crawler = $client->followRedirect();
+
+ $content1 = $client->getContainer()
+ ->get('doctrine.orm.entity_manager')
+ ->getRepository('WallabagCoreBundle:Entry')
+ ->findByUrlAndUserId(
+ 'https://redditblog.com/2016/09/20/amp-and-reactredux/',
+ $this->getLoggedInUserId()
+ );
+
+ $this->assertTrue($content1->isArchived());
+
+ $content2 = $client->getContainer()
+ ->get('doctrine.orm.entity_manager')
+ ->getRepository('WallabagCoreBundle:Entry')
+ ->findByUrlAndUserId(
+ 'https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c',
+ $this->getLoggedInUserId()
+ );
+
+ $this->assertTrue($content2->isArchived());
+
+ $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
+ $this->assertContains('flashes.import.notice.summary', $body[0]);
+ }
+
+ public function testImportInstapaperWithEmptyFile()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/import/instapaper');
+ $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
+
+ $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
+
+ $data = [
+ 'upload_import_file[file]' => $file,
+ ];
+
+ $client->submit($form, $data);
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+ $crawler = $client->followRedirect();
+
+ $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
+ $this->assertContains('flashes.import.notice.failed', $body[0]);
+ }
+}
--- /dev/null
+<?php
+
+namespace Tests\Wallabag\ImportBundle\Import;
+
+use Wallabag\ImportBundle\Import\InstapaperImport;
+use Wallabag\UserBundle\Entity\User;
+use Wallabag\CoreBundle\Entity\Entry;
+use Wallabag\ImportBundle\Redis\Producer;
+use Monolog\Logger;
+use Monolog\Handler\TestHandler;
+use Simpleue\Queue\RedisQueue;
+use M6Web\Component\RedisMock\RedisMockFactory;
+
+class InstapaperImportTest extends \PHPUnit_Framework_TestCase
+{
+ protected $user;
+ protected $em;
+ protected $logHandler;
+ protected $contentProxy;
+
+ private function getInstapaperImport($unsetUser = false)
+ {
+ $this->user = new User();
+
+ $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $import = new InstapaperImport($this->em, $this->contentProxy);
+
+ $this->logHandler = new TestHandler();
+ $logger = new Logger('test', [$this->logHandler]);
+ $import->setLogger($logger);
+
+ if (false === $unsetUser) {
+ $import->setUser($this->user);
+ }
+
+ return $import;
+ }
+
+ public function testInit()
+ {
+ $instapaperImport = $this->getInstapaperImport();
+
+ $this->assertEquals('Instapaper', $instapaperImport->getName());
+ $this->assertNotEmpty($instapaperImport->getUrl());
+ $this->assertEquals('import.instapaper.description', $instapaperImport->getDescription());
+ }
+
+ public function testImport()
+ {
+ $instapaperImport = $this->getInstapaperImport();
+ $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
+
+ $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $entryRepo->expects($this->exactly(3))
+ ->method('findByUrlAndUserId')
+ ->willReturn(false);
+
+ $this->em
+ ->expects($this->any())
+ ->method('getRepository')
+ ->willReturn($entryRepo);
+
+ $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->contentProxy
+ ->expects($this->exactly(3))
+ ->method('updateEntry')
+ ->willReturn($entry);
+
+ $res = $instapaperImport->import();
+
+ $this->assertTrue($res);
+ $this->assertEquals(['skipped' => 0, 'imported' => 3, 'queued' => 0], $instapaperImport->getSummary());
+ }
+
+ public function testImportAndMarkAllAsRead()
+ {
+ $instapaperImport = $this->getInstapaperImport();
+ $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
+
+ $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $entryRepo->expects($this->exactly(3))
+ ->method('findByUrlAndUserId')
+ ->will($this->onConsecutiveCalls(false, true, true));
+
+ $this->em
+ ->expects($this->any())
+ ->method('getRepository')
+ ->willReturn($entryRepo);
+
+ $this->contentProxy
+ ->expects($this->once())
+ ->method('updateEntry')
+ ->willReturn(new Entry($this->user));
+
+ // check that every entry persisted are archived
+ $this->em
+ ->expects($this->once())
+ ->method('persist')
+ ->with($this->callback(function ($persistedEntry) {
+ return $persistedEntry->isArchived();
+ }));
+
+ $res = $instapaperImport->setMarkAsRead(true)->import();
+
+ $this->assertTrue($res);
+
+ $this->assertEquals(['skipped' => 2, 'imported' => 1, 'queued' => 0], $instapaperImport->getSummary());
+ }
+
+ public function testImportWithRabbit()
+ {
+ $instapaperImport = $this->getInstapaperImport();
+ $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
+
+ $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $entryRepo->expects($this->never())
+ ->method('findByUrlAndUserId');
+
+ $this->em
+ ->expects($this->never())
+ ->method('getRepository');
+
+ $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->contentProxy
+ ->expects($this->never())
+ ->method('updateEntry');
+
+ $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $producer
+ ->expects($this->exactly(3))
+ ->method('publish');
+
+ $instapaperImport->setProducer($producer);
+
+ $res = $instapaperImport->setMarkAsRead(true)->import();
+
+ $this->assertTrue($res);
+ $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 3], $instapaperImport->getSummary());
+ }
+
+ public function testImportWithRedis()
+ {
+ $instapaperImport = $this->getInstapaperImport();
+ $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
+
+ $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $entryRepo->expects($this->never())
+ ->method('findByUrlAndUserId');
+
+ $this->em
+ ->expects($this->never())
+ ->method('getRepository');
+
+ $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->contentProxy
+ ->expects($this->never())
+ ->method('updateEntry');
+
+ $factory = new RedisMockFactory();
+ $redisMock = $factory->getAdapter('Predis\Client', true);
+
+ $queue = new RedisQueue($redisMock, 'instapaper');
+ $producer = new Producer($queue);
+
+ $instapaperImport->setProducer($producer);
+
+ $res = $instapaperImport->setMarkAsRead(true)->import();
+
+ $this->assertTrue($res);
+ $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 3], $instapaperImport->getSummary());
+
+ $this->assertNotEmpty($redisMock->lpop('instapaper'));
+ }
+
+ public function testImportBadFile()
+ {
+ $instapaperImport = $this->getInstapaperImport();
+ $instapaperImport->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx');
+
+ $res = $instapaperImport->import();
+
+ $this->assertFalse($res);
+
+ $records = $this->logHandler->getRecords();
+ $this->assertContains('InstapaperImport: unable to read file', $records[0]['message']);
+ $this->assertEquals('ERROR', $records[0]['level_name']);
+ }
+
+ public function testImportUserNotDefined()
+ {
+ $instapaperImport = $this->getInstapaperImport(true);
+ $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
+
+ $res = $instapaperImport->import();
+
+ $this->assertFalse($res);
+
+ $records = $this->logHandler->getRecords();
+ $this->assertContains('InstapaperImport: user is not defined', $records[0]['message']);
+ $this->assertEquals('ERROR', $records[0]['level_name']);
+ }
+}
--- /dev/null
+URL,Title,Selection,Folder
+http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551,Baumettes : un tour en cellule,,Unread
+https://redditblog.com/2016/09/20/amp-and-reactredux/,AMP and React+Redux: Why Not?,,Archive
+https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c,Why Foursquare / Swarm is still my favourite social network,,Starred
--- /dev/null
+<?php
+
+namespace Wallabag\UserBundle\Tests\Controller;
+
+use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
+
+class ManageControllerTest extends WallabagCoreTestCase
+{
+ public function testLogin()
+ {
+ $client = $this->getClient();
+
+ $client->request('GET', '/users/');
+
+ $this->assertEquals(302, $client->getResponse()->getStatusCode());
+ $this->assertContains('login', $client->getResponse()->headers->get('location'));
+ }
+
+ public function testCompleteScenario()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ // Create a new user in the database
+ $crawler = $client->request('GET', '/users/');
+ $this->assertEquals(200, $client->getResponse()->getStatusCode(), "Unexpected HTTP status code for GET /users/");
+ $crawler = $client->click($crawler->selectLink('user.list.create_new_one')->link());
+
+ // Fill in the form and submit it
+ $form = $crawler->selectButton('user.form.save')->form(array(
+ 'new_user[username]' => 'test_user',
+ 'new_user[email]' => 'test@test.io',
+ 'new_user[plainPassword][first]' => 'test',
+ 'new_user[plainPassword][second]' => 'test',
+ ));
+
+ $client->submit($form);
+ $client->followRedirect();
+ $crawler = $client->request('GET', '/users/');
+
+ // Check data in the show view
+ $this->assertGreaterThan(0, $crawler->filter('td:contains("test_user")')->count(), 'Missing element td:contains("test_user")');
+
+ // Edit the user
+ $crawler = $client->click($crawler->selectLink('user.list.edit_action')->last()->link());
+
+ $form = $crawler->selectButton('user.form.save')->form(array(
+ 'user[name]' => 'Foo User',
+ 'user[username]' => 'test_user',
+ 'user[email]' => 'test@test.io',
+ 'user[enabled]' => true,
+ 'user[locked]' => false,
+ ));
+
+ $client->submit($form);
+ $crawler = $client->followRedirect();
+
+ // Check the element contains an attribute with value equals "Foo User"
+ $this->assertGreaterThan(0, $crawler->filter('[value="Foo User"]')->count(), 'Missing element [value="Foo User"]');
+
+ $crawler = $client->request('GET', '/users/');
+ $crawler = $client->click($crawler->selectLink('user.list.edit_action')->last()->link());
+
+ // Delete the user
+ $client->submit($crawler->selectButton('user.form.delete')->form());
+ $crawler = $client->followRedirect();
+
+ // Check the user has been delete on the list
+ $this->assertNotRegExp('/Foo User/', $client->getResponse()->getContent());
+ }
+
+ public function testDeleteDisabledForLoggedUser()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/users/'.$this->getLoggedInUserId().'/edit');
+ $disabled = $crawler->selectButton('user.form.delete')->extract('disabled');
+
+ $this->assertEquals('disabled', $disabled[0]);
+ }
+}
<?php
-namespace Tests\Wallabag\CoreBundle\EventListener;
+namespace Tests\Wallabag\UserBundle\EventListener;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Wallabag\CoreBundle\Entity\Config;
-use Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener;
+use Wallabag\UserBundle\EventListener\CreateConfigListener;
use Wallabag\UserBundle\Entity\User;
-class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
+class CreateConfigListenerTest extends \PHPUnit_Framework_TestCase
{
private $em;
private $listener;
->disableOriginalConstructor()
->getMock();
- $this->listener = new RegistrationConfirmedListener(
+ $this->listener = new CreateConfigListener(
$this->em,
'baggy',
20,
50,
- 'fr'
+ 'fr',
+ 1
);
$this->dispatcher = new EventDispatcher();
$this->em->expects($this->never())->method('flush');
$this->dispatcher->dispatch(
- FOSUserEvents::REGISTRATION_CONFIRMED,
+ FOSUserEvents::REGISTRATION_COMPLETED,
$event
);
}
$config->setItemsPerPage(20);
$config->setRssLimit(50);
$config->setLanguage('fr');
+ $config->setReadingSpeed(1);
$this->em->expects($this->once())
->method('persist')
->method('flush');
$this->dispatcher->dispatch(
- FOSUserEvents::REGISTRATION_CONFIRMED,
+ FOSUserEvents::REGISTRATION_COMPLETED,
$event
);
}
);
$this->mailer = new \Swift_Mailer($transport);
- $twigTemplate = <<<TWIG
+ $twigTemplate = <<<'TWIG'
{% block subject %}subject{% endblock %}
{% block body_html %}html body {{ code }}{% endblock %}
{% block body_text %}text body {{ support_url }}{% endblock %}