mirror of
https://github.com/wallabag/wallabag.git
synced 2024-12-16 20:56:28 +00:00
commit
73ec68b1ff
206 changed files with 4709 additions and 1879 deletions
|
@ -13,5 +13,5 @@ insert_final_newline = true
|
|||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
[*akefile]
|
||||
indent_style = tab
|
||||
|
|
38
.travis.yml
38
.travis.yml
|
@ -4,12 +4,6 @@ services:
|
|||
- rabbitmq
|
||||
- redis
|
||||
|
||||
# used for HHVM
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- tidy
|
||||
|
||||
# cache vendor dirs
|
||||
cache:
|
||||
apt: true
|
||||
|
@ -21,10 +15,9 @@ cache:
|
|||
- $HOME/.yarn-cache
|
||||
|
||||
php:
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
- nightly
|
||||
|
||||
node_js:
|
||||
|
@ -38,7 +31,7 @@ env:
|
|||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: 7.0
|
||||
- php: 7.2
|
||||
env: CS_FIXER=run VALIDATE_TRANSLATION_FILE=run ASSETS=build DB=sqlite
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
|
@ -58,31 +51,26 @@ install:
|
|||
|
||||
before_script:
|
||||
- PHP=$TRAVIS_PHP_VERSION
|
||||
- if [[ ! $PHP = hhvm* ]]; then echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi;
|
||||
# xdebug isn't enable for PHP 7.1
|
||||
- if [[ ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi
|
||||
- echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
- phpenv config-rm xdebug.ini || echo "xdebug not available"
|
||||
- composer self-update --no-progress
|
||||
- if [[ $DB = pgsql ]]; then psql -c 'create database wallabag_test;' -U postgres; fi;
|
||||
# increase swap to avoid "proc_open(): fork failed - Cannot allocate memory"
|
||||
# this should be removed when no more PHP 5 build will be defined
|
||||
- sudo swapon -s
|
||||
- sudo fallocate -l 4G /swapfile
|
||||
- sudo chmod 600 /swapfile
|
||||
- sudo mkswap /swapfile
|
||||
- sudo swapon /swapfile
|
||||
- sudo swapon -s
|
||||
# install imagick
|
||||
- pear config-set preferred_state beta
|
||||
- pecl channel-update pecl.php.net
|
||||
- yes | pecl install imagick
|
||||
|
||||
script:
|
||||
- travis_wait bash composer install -o --no-interaction --no-progress --prefer-dist
|
||||
|
||||
- echo "travis_fold:start:prepare"
|
||||
- make prepare DB=$DB
|
||||
- echo "travis_fold:end:prepare"
|
||||
|
||||
- echo "travis_fold:start:fixtures"
|
||||
- php bin/console doctrine:fixtures:load --no-interaction --env=test
|
||||
- echo "travis_fold:end:fixtures"
|
||||
- make fixtures
|
||||
|
||||
- if [[ $VALIDATE_TRANSLATION_FILE = '' ]]; then ./bin/simple-phpunit -v ; fi;
|
||||
- if [[ $VALIDATE_TRANSLATION_FILE = '' ]]; then SYMFONY_PHPUNIT_VERSION=6.5 ./bin/simple-phpunit -v ; fi;
|
||||
# PHPStan needs PHPUnit to be installed and cache app to be generated
|
||||
- if [[ $VALIDATE_TRANSLATION_FILE = '' ]]; then php bin/phpstan analyse src tests --no-progress --level 1 ; fi;
|
||||
- if [[ $CS_FIXER = run ]]; then php bin/php-cs-fixer fix --verbose --dry-run ; fi;
|
||||
- if [[ $VALIDATE_TRANSLATION_FILE = run ]]; then php bin/console lint:yaml src/Wallabag/CoreBundle/Resources/translations -v ; fi;
|
||||
- if [[ $VALIDATE_TRANSLATION_FILE = run ]]; then php bin/console lint:yaml app/Resources/CraueConfigBundle/translations -v ; fi;
|
||||
|
|
26
.zappr.yaml
26
.zappr.yaml
|
@ -1,26 +0,0 @@
|
|||
# see https://zappr.opensource.zalan.do/
|
||||
autobranch: false
|
||||
commit: false
|
||||
approvals:
|
||||
minimum: 1
|
||||
ignore: pr_opener
|
||||
pattern: "^(:\\+1:|👍)$"
|
||||
veto:
|
||||
pattern: "^(:\\-1:|👎)$"
|
||||
from:
|
||||
orgs:
|
||||
- wallabag
|
||||
collaborators: true
|
||||
specification:
|
||||
title:
|
||||
minimum-length:
|
||||
enabled: true
|
||||
length: 8
|
||||
body:
|
||||
minimum-length:
|
||||
enabled: true
|
||||
length: 8
|
||||
contains-url: false
|
||||
contains-issue-number: false
|
||||
template:
|
||||
differs-from-body: true
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2013-2017 Nicolas Lœuillet
|
||||
Copyright (c) 2013-current Nicolas Lœuillet
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -19,10 +19,10 @@ Then you can install wallabag by executing the following commands:
|
|||
|
||||
```
|
||||
git clone https://github.com/wallabag/wallabag.git
|
||||
cd wallabag && make install
|
||||
cd wallabag && make install
|
||||
```
|
||||
|
||||
Now, [configure a virtual host](https://doc.wallabag.org/en/admin/installation/virtualhosts.html) to use your wallabag.
|
||||
Now, [configure a virtual host](https://doc.wallabag.org/en/admin/installation/virtualhosts.html) to use your wallabag.
|
||||
|
||||
# Run on YunoHost
|
||||
[![Install Wallabag with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=wallabag2)
|
||||
|
@ -30,6 +30,6 @@ Now, [configure a virtual host](https://doc.wallabag.org/en/admin/installation/v
|
|||
Wallabag app for [YunoHost](https://yunohost.org). See [here](https://github.com/YunoHost-Apps/wallabag2_ynh)
|
||||
|
||||
# License
|
||||
Copyright © 2013-2018 Nicolas Lœuillet <nicolas@loeuillet.org>
|
||||
Copyright © 2013-current Nicolas Lœuillet <nicolas@loeuillet.org>
|
||||
This work is free. You can redistribute it and/or modify it under the
|
||||
terms of the MIT License. See the COPYING file for more details.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
class AppKernel extends Kernel
|
||||
|
@ -32,6 +33,8 @@ class AppKernel extends Kernel
|
|||
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
|
||||
new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
|
||||
new BD\GuzzleSiteAuthenticatorBundle\BDGuzzleSiteAuthenticatorBundle(),
|
||||
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
|
||||
new Http\HttplugBundle\HttplugBundle(),
|
||||
|
||||
// wallabag bundles
|
||||
new Wallabag\CoreBundle\WallabagCoreBundle(),
|
||||
|
@ -39,25 +42,32 @@ class AppKernel extends Kernel
|
|||
new Wallabag\UserBundle\WallabagUserBundle(),
|
||||
new Wallabag\ImportBundle\WallabagImportBundle(),
|
||||
new Wallabag\AnnotationBundle\WallabagAnnotationBundle(),
|
||||
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
|
||||
];
|
||||
|
||||
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
|
||||
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
|
||||
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
|
||||
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
|
||||
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
|
||||
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
|
||||
$bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle();
|
||||
|
||||
if ('test' === $this->getEnvironment()) {
|
||||
$bundles[] = new DAMA\DoctrineTestBundle\DAMADoctrineTestBundle();
|
||||
}
|
||||
|
||||
if ('dev' === $this->getEnvironment()) {
|
||||
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
|
||||
$bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle();
|
||||
}
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
public function getRootDir()
|
||||
{
|
||||
return __DIR__;
|
||||
}
|
||||
|
||||
public function getCacheDir()
|
||||
{
|
||||
return dirname(__DIR__) . '/var/cache/' . $this->getEnvironment();
|
||||
|
@ -70,7 +80,8 @@ class AppKernel extends Kernel
|
|||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader)
|
||||
{
|
||||
$loader->load($this->getProjectDir() . '/app/config/config_' . $this->getEnvironment() . '.yml');
|
||||
$loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml');
|
||||
|
||||
$loader->load(function ($container) {
|
||||
if ($container->getParameter('use_webpack_dev_server')) {
|
||||
$container->loadFromExtension('framework', [
|
||||
|
@ -86,5 +97,11 @@ class AppKernel extends Kernel
|
|||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$loader->load(function (ContainerBuilder $container) {
|
||||
// $container->setParameter('container.autowiring.strict_mode', true);
|
||||
// $container->setParameter('container.dumper.inline_class_loader', true);
|
||||
$container->addObjectResource($this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
51
app/DoctrineMigrations/Version20180405182455.php
Executable file
51
app/DoctrineMigrations/Version20180405182455.php
Executable file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Add archived_at column and set its value to updated_at for is_archived entries.
|
||||
*/
|
||||
class Version20180405182455 extends WallabagMigration
|
||||
{
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
$entryTable = $schema->getTable($this->getTable('entry'));
|
||||
|
||||
$this->skipIf($entryTable->hasColumn('archived_at'), 'It seems that you already played this migration.');
|
||||
|
||||
$entryTable->addColumn('archived_at', 'datetime', [
|
||||
'notnull' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function postUp(Schema $schema)
|
||||
{
|
||||
$entryTable = $schema->getTable($this->getTable('entry'));
|
||||
$this->skipIf(!$entryTable->hasColumn('archived_at'), 'Unable to add archived_at colum');
|
||||
|
||||
$this->connection->executeQuery(
|
||||
'UPDATE ' . $this->getTable('entry') . ' SET archived_at = updated_at WHERE is_archived = :is_archived',
|
||||
[
|
||||
'is_archived' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
$entryTable = $schema->getTable($this->getTable('entry'));
|
||||
|
||||
$this->skipIf(!$entryTable->hasColumn('archived_at'), 'It seems that you already played this migration.');
|
||||
|
||||
$entryTable->dropColumn('archived_at');
|
||||
}
|
||||
}
|
45
app/DoctrineMigrations/Version20181128203230.php
Normal file
45
app/DoctrineMigrations/Version20181128203230.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Fix varchar field from vendor to work with utf8mb4.
|
||||
*/
|
||||
class Version20181128203230 extends WallabagMigration
|
||||
{
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
$this->skipIf('mysql' !== $this->connection->getDatabasePlatform()->getName(), 'This migration can only be applied on \'mysql\'.');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' CHANGE `token` `token` varchar(191) NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' CHANGE `scope` `scope` varchar(191)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' CHANGE `token` `token` varchar(191) NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' CHANGE `scope` `scope` varchar(191)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' CHANGE `token` `token` varchar(191) NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' CHANGE `scope` `scope` varchar(191)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('craue_config_setting') . ' CHANGE `name` `name` varchar(191)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('craue_config_setting') . ' CHANGE `section` `section` varchar(191)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('craue_config_setting') . ' CHANGE `value` `value` varchar(191)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
$this->skipIf('mysql' !== $this->connection->getDatabasePlatform()->getName(), 'This migration can only be applied on \'mysql\'.');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' CHANGE `token` `token` varchar(255) NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' CHANGE `scope` `scope` varchar(255)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' CHANGE `token` `token` varchar(255) NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' CHANGE `scope` `scope` varchar(255)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' CHANGE `token` `token` varchar(255) NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' CHANGE `scope` `scope` varchar(255)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('craue_config_setting') . ' CHANGE `name` `name` varchar(255)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('craue_config_setting') . ' CHANGE `section` `section` varchar(255)');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('craue_config_setting') . ' CHANGE `value` `value` varchar(255)');
|
||||
}
|
||||
}
|
76
app/DoctrineMigrations/Version20181202073750.php
Normal file
76
app/DoctrineMigrations/Version20181202073750.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Add 2fa OTP stuff.
|
||||
*/
|
||||
final class Version20181202073750 extends WallabagMigration
|
||||
{
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
switch ($this->connection->getDatabasePlatform()->getName()) {
|
||||
case 'sqlite':
|
||||
$this->addSql('DROP INDEX UNIQ_1D63E7E5C05FB297');
|
||||
$this->addSql('DROP INDEX UNIQ_1D63E7E5A0D96FBF');
|
||||
$this->addSql('DROP INDEX UNIQ_1D63E7E592FC23A8');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('user', true) . ' AS SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, twoFactorAuthentication FROM ' . $this->getTable('user', true) . '');
|
||||
$this->addSql('DROP TABLE ' . $this->getTable('user', true) . '');
|
||||
$this->addSql('CREATE TABLE ' . $this->getTable('user', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(180) NOT NULL COLLATE BINARY, username_canonical VARCHAR(180) NOT NULL COLLATE BINARY, email VARCHAR(180) NOT NULL COLLATE BINARY, email_canonical VARCHAR(180) NOT NULL COLLATE BINARY, enabled BOOLEAN NOT NULL, password VARCHAR(255) NOT NULL COLLATE BINARY, last_login DATETIME DEFAULT NULL, password_requested_at DATETIME DEFAULT NULL, name CLOB DEFAULT NULL COLLATE BINARY, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, authCode INTEGER DEFAULT NULL, emailTwoFactor BOOLEAN NOT NULL, salt VARCHAR(255) DEFAULT NULL, confirmation_token VARCHAR(180) DEFAULT NULL, roles CLOB NOT NULL --(DC2Type:array)
|
||||
, googleAuthenticatorSecret VARCHAR(255) DEFAULT NULL, backupCodes CLOB DEFAULT NULL --(DC2Type:json_array)
|
||||
)');
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('user', true) . ' (id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, emailTwoFactor) SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, twoFactorAuthentication FROM __temp__' . $this->getTable('user', true) . '');
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('user', true) . '');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5C05FB297 ON ' . $this->getTable('user', true) . ' (confirmation_token)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5A0D96FBF ON ' . $this->getTable('user', true) . ' (email_canonical)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E592FC23A8 ON ' . $this->getTable('user', true) . ' (username_canonical)');
|
||||
break;
|
||||
case 'mysql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' CHANGE twoFactorAuthentication emailTwoFactor BOOLEAN NOT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP trusted');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD backupCodes LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:json_array)\'');
|
||||
break;
|
||||
case 'postgresql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' RENAME COLUMN twofactorauthentication TO emailTwoFactor');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP trusted');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD backupCodes TEXT DEFAULT NULL');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
switch ($this->connection->getDatabasePlatform()->getName()) {
|
||||
case 'sqlite':
|
||||
$this->addSql('DROP INDEX UNIQ_1D63E7E592FC23A8');
|
||||
$this->addSql('DROP INDEX UNIQ_1D63E7E5A0D96FBF');
|
||||
$this->addSql('DROP INDEX UNIQ_1D63E7E5C05FB297');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('user', true) . ' AS SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, emailTwoFactor FROM "' . $this->getTable('user', true) . '"');
|
||||
$this->addSql('DROP TABLE "' . $this->getTable('user', true) . '"');
|
||||
$this->addSql('CREATE TABLE "' . $this->getTable('user', true) . '" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(180) NOT NULL, username_canonical VARCHAR(180) NOT NULL, email VARCHAR(180) NOT NULL, email_canonical VARCHAR(180) NOT NULL, enabled BOOLEAN NOT NULL, password VARCHAR(255) NOT NULL, last_login DATETIME DEFAULT NULL, password_requested_at DATETIME DEFAULT NULL, name CLOB DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, authCode INTEGER DEFAULT NULL, twoFactorAuthentication BOOLEAN NOT NULL, salt VARCHAR(255) NOT NULL COLLATE BINARY, confirmation_token VARCHAR(255) DEFAULT NULL COLLATE BINARY, roles CLOB NOT NULL COLLATE BINARY, trusted CLOB DEFAULT NULL COLLATE BINARY)');
|
||||
$this->addSql('INSERT INTO "' . $this->getTable('user', true) . '" (id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, twoFactorAuthentication) SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, emailTwoFactor FROM __temp__' . $this->getTable('user', true) . '');
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('user', true) . '');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E592FC23A8 ON "' . $this->getTable('user', true) . '" (username_canonical)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5A0D96FBF ON "' . $this->getTable('user', true) . '" (email_canonical)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5C05FB297 ON "' . $this->getTable('user', true) . '" (confirmation_token)');
|
||||
break;
|
||||
case 'mysql':
|
||||
$this->addSql('ALTER TABLE `' . $this->getTable('user') . '` DROP googleAuthenticatorSecret');
|
||||
$this->addSql('ALTER TABLE `' . $this->getTable('user') . '` CHANGE emailtwofactor twoFactorAuthentication BOOLEAN NOT NULL');
|
||||
$this->addSql('ALTER TABLE `' . $this->getTable('user') . '` ADD trusted TEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE `' . $this->getTable('user') . '` DROP backupCodes');
|
||||
break;
|
||||
case 'postgresql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP googleAuthenticatorSecret');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' RENAME COLUMN emailTwoFactor TO twofactorauthentication');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD trusted TEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP backupCodes');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
32
app/DoctrineMigrations/Version20190117131816.php
Normal file
32
app/DoctrineMigrations/Version20190117131816.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Add updated_at fields to site_credential table.
|
||||
*/
|
||||
final class Version20190117131816 extends WallabagMigration
|
||||
{
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$siteCredentialTable = $schema->getTable($this->getTable('site_credential'));
|
||||
|
||||
$this->skipIf($siteCredentialTable->hasColumn('updated_at'), 'It seems that you already played this migration.');
|
||||
|
||||
$siteCredentialTable->addColumn('updated_at', 'datetime', [
|
||||
'notnull' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$siteCredentialTable = $schema->getTable($this->getTable('site_credential'));
|
||||
|
||||
$this->skipIf(!$siteCredentialTable->hasColumn('updated_at'), 'It seems that you already played this migration.');
|
||||
|
||||
$siteCredentialTable->dropColumn('updated_at');
|
||||
}
|
||||
}
|
147
app/DoctrineMigrations/Version20190129120000.php
Normal file
147
app/DoctrineMigrations/Version20190129120000.php
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Add missing entries in craue_config_setting.
|
||||
*/
|
||||
final class Version20190129120000 extends WallabagMigration
|
||||
{
|
||||
private $settings = [
|
||||
[
|
||||
'name' => 'carrot',
|
||||
'value' => '1',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'share_diaspora',
|
||||
'value' => '1',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'diaspora_url',
|
||||
'value' => 'http://diasporapod.com',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'share_shaarli',
|
||||
'value' => '1',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'shaarli_url',
|
||||
'value' => 'http://myshaarli.com',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'share_mail',
|
||||
'value' => '1',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'share_twitter',
|
||||
'value' => '1',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'show_printlink',
|
||||
'value' => '1',
|
||||
'section' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'export_epub',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'export_mobi',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'export_pdf',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'export_csv',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'export_json',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'export_txt',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'export_xml',
|
||||
'value' => '1',
|
||||
'section' => 'export',
|
||||
],
|
||||
[
|
||||
'name' => 'piwik_enabled',
|
||||
'value' => '0',
|
||||
'section' => 'analytics',
|
||||
],
|
||||
[
|
||||
'name' => 'piwik_host',
|
||||
'value' => 'v2.wallabag.org',
|
||||
'section' => 'analytics',
|
||||
],
|
||||
[
|
||||
'name' => 'piwik_site_id',
|
||||
'value' => '1',
|
||||
'section' => 'analytics',
|
||||
],
|
||||
[
|
||||
'name' => 'demo_mode_enabled',
|
||||
'value' => '0',
|
||||
'section' => 'misc',
|
||||
],
|
||||
[
|
||||
'name' => 'demo_mode_username',
|
||||
'value' => 'wallabag',
|
||||
'section' => 'misc',
|
||||
],
|
||||
[
|
||||
'name' => 'wallabag_support_url',
|
||||
'value' => 'https://www.wallabag.org/pages/support.html',
|
||||
'section' => 'misc',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
foreach ($this->settings as $setting) {
|
||||
$settingEnabled = $this->container
|
||||
->get('doctrine.orm.default_entity_manager')
|
||||
->getConnection()
|
||||
->fetchArray('SELECT * FROM ' . $this->getTable('craue_config_setting') . " WHERE name = '" . $setting['name'] . "'");
|
||||
|
||||
if (false !== $settingEnabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('craue_config_setting') . " (name, value, section) VALUES ('" . $setting['name'] . "', '" . $setting['value'] . "', '" . $setting['section'] . "');");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
$this->skipIf(true, 'These settings are required and should not be removed.');
|
||||
}
|
||||
}
|
42
app/DoctrineMigrations/Version20190401105353.php
Normal file
42
app/DoctrineMigrations/Version20190401105353.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Add hashed_url in entry.
|
||||
*/
|
||||
class Version20190401105353 extends WallabagMigration
|
||||
{
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
$entryTable = $schema->getTable($this->getTable('entry'));
|
||||
|
||||
$this->skipIf($entryTable->hasColumn('hashed_url'), 'It seems that you already played this migration.');
|
||||
|
||||
$entryTable->addColumn('hashed_url', 'text', [
|
||||
'length' => 40,
|
||||
'notnull' => false,
|
||||
]);
|
||||
|
||||
$entryTable->addIndex(['user_id', 'hashed_url'], 'hashed_url_user_id', [], ['lengths' => [null, 40]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
$entryTable = $schema->getTable($this->getTable('entry'));
|
||||
|
||||
$this->skipIf(!$entryTable->hasColumn('hashed_url'), 'It seems that you already played this migration.');
|
||||
|
||||
$entryTable->dropIndex('hashed_url_user_id');
|
||||
$entryTable->dropColumn('hashed_url');
|
||||
}
|
||||
}
|
58
app/DoctrineMigrations/Version20190425115043.php
Normal file
58
app/DoctrineMigrations/Version20190425115043.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Rename rss_token & rss_limit to feed_token & feed_limit.
|
||||
*/
|
||||
final class Version20190425115043 extends WallabagMigration
|
||||
{
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
switch ($this->connection->getDatabasePlatform()->getName()) {
|
||||
case 'sqlite':
|
||||
$this->addSql('DROP INDEX UNIQ_87E64C53A76ED395');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('config', true) . ' AS SELECT id, user_id, theme, items_per_page, language, rss_token, rss_limit, reading_speed, pocket_consumer_key, action_mark_as_read, list_mode FROM ' . $this->getTable('config', true));
|
||||
$this->addSql('DROP TABLE ' . $this->getTable('config', true));
|
||||
$this->addSql('CREATE TABLE ' . $this->getTable('config', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, theme VARCHAR(255) NOT NULL COLLATE BINARY, items_per_page INTEGER NOT NULL, language VARCHAR(255) NOT NULL COLLATE BINARY, reading_speed DOUBLE PRECISION DEFAULT NULL, pocket_consumer_key VARCHAR(255) DEFAULT NULL COLLATE BINARY, action_mark_as_read INTEGER DEFAULT 0, list_mode INTEGER DEFAULT NULL, feed_token VARCHAR(255) DEFAULT NULL, feed_limit INTEGER DEFAULT NULL, CONSTRAINT FK_87E64C53A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('config', true) . ' (id, user_id, theme, items_per_page, language, feed_token, feed_limit, reading_speed, pocket_consumer_key, action_mark_as_read, list_mode) SELECT id, user_id, theme, items_per_page, language, rss_token, rss_limit, reading_speed, pocket_consumer_key, action_mark_as_read, list_mode FROM __temp__' . $this->getTable('config', true));
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('config', true));
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_87E64C53A76ED395 ON ' . $this->getTable('config', true) . ' (user_id)');
|
||||
break;
|
||||
case 'mysql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' CHANGE rss_token feed_token VARCHAR(255) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' CHANGE rss_limit feed_limit INT DEFAULT NULL');
|
||||
break;
|
||||
case 'postgresql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' RENAME COLUMN rss_token TO feed_token');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' RENAME COLUMN rss_limit TO feed_limit');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
switch ($this->connection->getDatabasePlatform()->getName()) {
|
||||
case 'sqlite':
|
||||
$this->addSql('DROP INDEX UNIQ_87E64C53A76ED395');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('config', true) . ' AS SELECT id, user_id, theme, items_per_page, language, feed_token, feed_limit, reading_speed, pocket_consumer_key, action_mark_as_read, list_mode FROM "' . $this->getTable('config', true) . '"');
|
||||
$this->addSql('DROP TABLE "' . $this->getTable('config', true) . '"');
|
||||
$this->addSql('CREATE TABLE "' . $this->getTable('config', true) . '" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, theme VARCHAR(255) NOT NULL, items_per_page INTEGER NOT NULL, language VARCHAR(255) NOT NULL, reading_speed DOUBLE PRECISION DEFAULT NULL, pocket_consumer_key VARCHAR(255) DEFAULT NULL, action_mark_as_read INTEGER DEFAULT 0, list_mode INTEGER DEFAULT NULL, rss_token VARCHAR(255) DEFAULT NULL COLLATE BINARY, rss_limit INTEGER DEFAULT NULL)');
|
||||
$this->addSql('INSERT INTO "' . $this->getTable('config', true) . '" (id, user_id, theme, items_per_page, language, rss_token, rss_limit, reading_speed, pocket_consumer_key, action_mark_as_read, list_mode) SELECT id, user_id, theme, items_per_page, language, feed_token, feed_limit, reading_speed, pocket_consumer_key, action_mark_as_read, list_mode FROM __temp__' . $this->getTable('config', true));
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('config', true));
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_87E64C53A76ED395 ON "' . $this->getTable('config', true) . '" (user_id)');
|
||||
break;
|
||||
case 'mysql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' CHANGE feed_token rss_token');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' CHANGE feed_limit rss_limit');
|
||||
break;
|
||||
case 'postgresql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' RENAME COLUMN feed_token TO rss_token');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('config') . ' RENAME COLUMN feed_limit TO rss_limit');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
96
app/DoctrineMigrations/Version20190510141130.php
Normal file
96
app/DoctrineMigrations/Version20190510141130.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Migrations\SkipMigrationException;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Wallabag\CoreBundle\Doctrine\WallabagMigration;
|
||||
|
||||
/**
|
||||
* Enable cascade delete when deleting a user on:
|
||||
* - oauth2_access_tokens
|
||||
* - oauth2_clients
|
||||
* - oauth2_refresh_tokens
|
||||
* - oauth2_auth_codes.
|
||||
*/
|
||||
final class Version20190510141130 extends WallabagMigration
|
||||
{
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
switch ($this->connection->getDatabasePlatform()->getName()) {
|
||||
case 'sqlite':
|
||||
$this->addSql('DROP INDEX IDX_368A4209A76ED395');
|
||||
$this->addSql('DROP INDEX IDX_368A420919EB6921');
|
||||
$this->addSql('DROP INDEX UNIQ_368A42095F37A13B');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('oauth2_access_tokens', true) . ' AS SELECT id, client_id, user_id, token, expires_at, scope FROM ' . $this->getTable('oauth2_access_tokens', true));
|
||||
$this->addSql('DROP TABLE ' . $this->getTable('oauth2_access_tokens', true));
|
||||
$this->addSql('CREATE TABLE ' . $this->getTable('oauth2_access_tokens', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, client_id INTEGER NOT NULL, user_id INTEGER DEFAULT NULL, expires_at INTEGER DEFAULT NULL, token VARCHAR(191) NOT NULL, scope VARCHAR(191) NULL, CONSTRAINT FK_368A420919EB6921 FOREIGN KEY (client_id) REFERENCES ' . $this->getTable('oauth2_clients', true) . ' (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_368A4209A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('oauth2_access_tokens', true) . ' (id, client_id, user_id, token, expires_at, scope) SELECT id, client_id, user_id, token, expires_at, scope FROM __temp__' . $this->getTable('oauth2_access_tokens', true));
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('oauth2_access_tokens', true));
|
||||
$this->addSql('CREATE INDEX IDX_368A4209A76ED395 ON ' . $this->getTable('oauth2_access_tokens', true) . ' (user_id)');
|
||||
$this->addSql('CREATE INDEX IDX_368A420919EB6921 ON ' . $this->getTable('oauth2_access_tokens', true) . ' (client_id)');
|
||||
|
||||
$this->addSql('DROP INDEX IDX_635D765EA76ED395');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('oauth2_clients', true) . ' AS SELECT id, user_id, random_id, secret, redirect_uris, allowed_grant_types, name FROM ' . $this->getTable('oauth2_clients', true));
|
||||
$this->addSql('DROP TABLE ' . $this->getTable('oauth2_clients', true));
|
||||
$this->addSql('CREATE TABLE ' . $this->getTable('oauth2_clients', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, random_id VARCHAR(255) NOT NULL COLLATE BINARY, secret VARCHAR(255) NOT NULL COLLATE BINARY, name CLOB NOT NULL COLLATE BINARY, redirect_uris CLOB NOT NULL, allowed_grant_types CLOB NOT NULL, CONSTRAINT FK_635D765EA76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('oauth2_clients', true) . ' (id, user_id, random_id, secret, redirect_uris, allowed_grant_types, name) SELECT id, user_id, random_id, secret, redirect_uris, allowed_grant_types, name FROM __temp__' . $this->getTable('oauth2_clients', true));
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('oauth2_clients', true));
|
||||
$this->addSql('CREATE INDEX IDX_635D765EA76ED395 ON ' . $this->getTable('oauth2_clients', true) . ' (user_id)');
|
||||
|
||||
$this->addSql('DROP INDEX IDX_20C9FB24A76ED395');
|
||||
$this->addSql('DROP INDEX IDX_20C9FB2419EB6921');
|
||||
$this->addSql('DROP INDEX UNIQ_20C9FB245F37A13B');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('oauth2_refresh_tokens', true) . ' AS SELECT id, client_id, user_id, token, expires_at, scope FROM ' . $this->getTable('oauth2_refresh_tokens', true));
|
||||
$this->addSql('DROP TABLE ' . $this->getTable('oauth2_refresh_tokens', true));
|
||||
$this->addSql('CREATE TABLE ' . $this->getTable('oauth2_refresh_tokens', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, client_id INTEGER NOT NULL, user_id INTEGER DEFAULT NULL, expires_at INTEGER DEFAULT NULL, token VARCHAR(191) NOT NULL, scope VARCHAR(191) NULL, CONSTRAINT FK_20C9FB2419EB6921 FOREIGN KEY (client_id) REFERENCES ' . $this->getTable('oauth2_clients', true) . ' (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_20C9FB24A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('oauth2_refresh_tokens', true) . ' (id, client_id, user_id, token, expires_at, scope) SELECT id, client_id, user_id, token, expires_at, scope FROM __temp__' . $this->getTable('oauth2_refresh_tokens', true));
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('oauth2_refresh_tokens', true));
|
||||
$this->addSql('CREATE INDEX IDX_20C9FB24A76ED395 ON ' . $this->getTable('oauth2_refresh_tokens', true) . ' (user_id)');
|
||||
$this->addSql('CREATE INDEX IDX_20C9FB2419EB6921 ON ' . $this->getTable('oauth2_refresh_tokens', true) . ' (client_id)');
|
||||
|
||||
$this->addSql('DROP INDEX IDX_EE52E3FAA76ED395');
|
||||
$this->addSql('DROP INDEX IDX_EE52E3FA19EB6921');
|
||||
$this->addSql('DROP INDEX UNIQ_EE52E3FA5F37A13B');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('oauth2_auth_codes', true) . ' AS SELECT id, client_id, user_id, token, redirect_uri, expires_at, scope FROM ' . $this->getTable('oauth2_auth_codes', true));
|
||||
$this->addSql('DROP TABLE ' . $this->getTable('oauth2_auth_codes', true));
|
||||
$this->addSql('CREATE TABLE ' . $this->getTable('oauth2_auth_codes', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, client_id INTEGER NOT NULL, user_id INTEGER DEFAULT NULL, redirect_uri CLOB NOT NULL COLLATE BINARY, expires_at INTEGER DEFAULT NULL, token VARCHAR(191) NOT NULL, scope VARCHAR(191) NULL, CONSTRAINT FK_EE52E3FA19EB6921 FOREIGN KEY (client_id) REFERENCES ' . $this->getTable('oauth2_clients', true) . ' (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EE52E3FAA76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO ' . $this->getTable('oauth2_auth_codes', true) . ' (id, client_id, user_id, token, redirect_uri, expires_at, scope) SELECT id, client_id, user_id, token, redirect_uri, expires_at, scope FROM __temp__' . $this->getTable('oauth2_auth_codes', true));
|
||||
$this->addSql('DROP TABLE __temp__' . $this->getTable('oauth2_auth_codes', true));
|
||||
$this->addSql('CREATE INDEX IDX_EE52E3FAA76ED395 ON ' . $this->getTable('oauth2_auth_codes', true) . ' (user_id)');
|
||||
$this->addSql('CREATE INDEX IDX_EE52E3FA19EB6921 ON ' . $this->getTable('oauth2_auth_codes', true) . ' (client_id)');
|
||||
break;
|
||||
case 'mysql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' DROP FOREIGN KEY FK_368A4209A76ED395');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' ADD CONSTRAINT FK_368A4209A76ED395 FOREIGN KEY (user_id) REFERENCES `wallabag_user` (id) ON DELETE CASCADE');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_clients') . ' DROP FOREIGN KEY IDX_user_oauth_client');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_clients') . ' ADD CONSTRAINT FK_635D765EA76ED395 FOREIGN KEY (user_id) REFERENCES `wallabag_user` (id)');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' DROP FOREIGN KEY FK_20C9FB24A76ED395');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' ADD CONSTRAINT FK_20C9FB24A76ED395 FOREIGN KEY (user_id) REFERENCES `wallabag_user` (id) ON DELETE CASCADE');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' DROP FOREIGN KEY FK_EE52E3FAA76ED395');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' ADD CONSTRAINT FK_EE52E3FAA76ED395 FOREIGN KEY (user_id) REFERENCES `wallabag_user` (id) ON DELETE CASCADE');
|
||||
break;
|
||||
case 'postgresql':
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' DROP CONSTRAINT FK_368A4209A76ED395');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_access_tokens') . ' ADD CONSTRAINT FK_368A4209A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_clients') . ' DROP CONSTRAINT idx_user_oauth_client');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_clients') . ' ADD CONSTRAINT FK_635D765EA76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' DROP CONSTRAINT FK_20C9FB24A76ED395');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_refresh_tokens') . ' ADD CONSTRAINT FK_20C9FB24A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' DROP CONSTRAINT FK_EE52E3FAA76ED395');
|
||||
$this->addSql('ALTER TABLE ' . $this->getTable('oauth2_auth_codes') . ' ADD CONSTRAINT FK_EE52E3FAA76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
throw new SkipMigrationException('Too complex ...');
|
||||
}
|
||||
}
|
|
@ -70,4 +70,41 @@ $(document).ready(() => {
|
|||
retrievePercent(x.entryId, true);
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-handler=tag-rename]').forEach((item) => {
|
||||
const current = item;
|
||||
current.wallabag_edit_mode = false;
|
||||
current.onclick = (event) => {
|
||||
const target = event.currentTarget;
|
||||
|
||||
if (target.wallabag_edit_mode === false) {
|
||||
$(target.parentNode.querySelector('[data-handle=tag-link]')).addClass('hidden');
|
||||
$(target.parentNode.querySelector('[data-handle=tag-rename-form]')).removeClass('hidden');
|
||||
target.parentNode.querySelector('[data-handle=tag-rename-form] input').focus();
|
||||
target.querySelector('.material-icons').innerHTML = 'done';
|
||||
|
||||
target.wallabag_edit_mode = true;
|
||||
} else {
|
||||
target.parentNode.querySelector('[data-handle=tag-rename-form]').submit();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// mimic radio button because emailTwoFactor is a boolean
|
||||
$('#update_user_googleTwoFactor').on('change', () => {
|
||||
$('#update_user_emailTwoFactor').prop('checked', false);
|
||||
});
|
||||
|
||||
$('#update_user_emailTwoFactor').on('change', () => {
|
||||
$('#update_user_googleTwoFactor').prop('checked', false);
|
||||
});
|
||||
|
||||
// same mimic for super admin
|
||||
$('#user_googleTwoFactor').on('change', () => {
|
||||
$('#user_emailTwoFactor').prop('checked', false);
|
||||
});
|
||||
|
||||
$('#user_emailTwoFactor').on('change', () => {
|
||||
$('#user_googleTwoFactor').prop('checked', false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -85,7 +85,7 @@ blockquote {
|
|||
color: #999;
|
||||
}
|
||||
|
||||
.icon-rss {
|
||||
.icon-feed {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
padding: 0.2em 0.5em;
|
||||
|
@ -101,8 +101,8 @@ blockquote {
|
|||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.icon-rss:hover,
|
||||
.icon-rss:focus {
|
||||
.icon-feed:hover,
|
||||
.icon-feed:focus {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
|
|
|
@ -295,6 +295,15 @@ div.pagination ul {
|
|||
}
|
||||
}
|
||||
|
||||
.hide {
|
||||
.card-tag-form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.card-tag-form input[type="text"] {
|
||||
min-width: 20em;
|
||||
}
|
||||
|
||||
.hide,
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
content: "\ea3a";
|
||||
}
|
||||
|
||||
.icon-rss::before {
|
||||
.icon-feed::before {
|
||||
content: "\e808";
|
||||
}
|
||||
|
||||
|
|
|
@ -197,6 +197,17 @@ a.original:not(.waves-effect) {
|
|||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.card-tag-form {
|
||||
display: flex;
|
||||
min-width: 100px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.card-tag-form input {
|
||||
margin-bottom: 0;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.card-tag-rss {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'materialize-css/dist/js/materialize';
|
|||
import '../_global/index';
|
||||
|
||||
/* Tools */
|
||||
import { initExport, initFilters } from './js/tools';
|
||||
import { initExport, initFilters, initRandom } from './js/tools';
|
||||
|
||||
/* Import shortcuts */
|
||||
import './js/shortcuts/main';
|
||||
|
@ -32,8 +32,10 @@ $(document).ready(() => {
|
|||
format: 'dd/mm/yyyy',
|
||||
container: 'body',
|
||||
});
|
||||
|
||||
initFilters();
|
||||
initExport();
|
||||
initRandom();
|
||||
|
||||
const toggleNav = (toShow, toFocus) => {
|
||||
$('.nav-panel-actions').hide(100);
|
||||
|
@ -48,25 +50,30 @@ $(document).ready(() => {
|
|||
$('#tag_label').focus();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#nav-btn-add').on('click', () => {
|
||||
toggleNav('.nav-panel-add', '#entry_url');
|
||||
return false;
|
||||
});
|
||||
|
||||
const materialAddForm = $('.nav-panel-add');
|
||||
materialAddForm.on('submit', () => {
|
||||
materialAddForm.addClass('disabled');
|
||||
$('input#entry_url', materialAddForm).prop('readonly', true).trigger('blur');
|
||||
});
|
||||
|
||||
$('#nav-btn-search').on('click', () => {
|
||||
toggleNav('.nav-panel-search', '#search_entry_term');
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.close').on('click', (e) => {
|
||||
$(e.target).parent('.nav-panel-item').hide(100);
|
||||
$('.nav-panel-actions').show(100);
|
||||
$('.nav-panels').css('background', 'transparent');
|
||||
return false;
|
||||
});
|
||||
|
||||
$(window).scroll(() => {
|
||||
const s = $(window).scrollTop();
|
||||
const d = $(document).height();
|
||||
|
|
|
@ -8,6 +8,7 @@ function initFilters() {
|
|||
$('#clear_form_filters').on('click', () => {
|
||||
$('#filters input').val('');
|
||||
$('#filters :checked').removeAttr('checked');
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
@ -21,4 +22,15 @@ function initExport() {
|
|||
}
|
||||
}
|
||||
|
||||
export { initExport, initFilters };
|
||||
function initRandom() {
|
||||
// no display if export (ie: entries) not available
|
||||
if ($('div').is('#export')) {
|
||||
$('#button_random').show();
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
initExport,
|
||||
initFilters,
|
||||
initRandom,
|
||||
};
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
||||
/**
|
||||
* @var ClassLoader
|
||||
*/
|
||||
$loader = require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
|
||||
|
||||
return $loader;
|
|
@ -46,7 +46,6 @@ twig:
|
|||
doctrine:
|
||||
dbal:
|
||||
driver: "%database_driver%"
|
||||
driver_class: "%database_driver_class%"
|
||||
host: "%database_host%"
|
||||
port: "%database_port%"
|
||||
dbname: "%database_name%"
|
||||
|
@ -55,7 +54,6 @@ doctrine:
|
|||
charset: "%database_charset%"
|
||||
path: "%database_path%"
|
||||
unix_socket: "%database_socket%"
|
||||
server_version: 5.6
|
||||
|
||||
orm:
|
||||
auto_generate_proxy_classes: "%kernel.debug%"
|
||||
|
@ -79,10 +77,13 @@ doctrine_migrations:
|
|||
|
||||
# Swiftmailer Configuration
|
||||
swiftmailer:
|
||||
transport: "%mailer_transport%"
|
||||
host: "%mailer_host%"
|
||||
username: "%mailer_user%"
|
||||
password: "%mailer_password%"
|
||||
transport: "%mailer_transport%"
|
||||
username: "%mailer_user%"
|
||||
password: "%mailer_password%"
|
||||
host: "%mailer_host%"
|
||||
port: "%mailer_port%"
|
||||
encryption: "%mailer_encryption%"
|
||||
auth_mode: "%mailer_auth_mode%"
|
||||
spool:
|
||||
type: memory
|
||||
|
||||
|
@ -197,10 +198,17 @@ fos_oauth_server:
|
|||
refresh_token_lifetime: 1209600
|
||||
|
||||
scheb_two_factor:
|
||||
trusted_computer:
|
||||
trusted_device:
|
||||
enabled: true
|
||||
cookie_name: wllbg_trusted_computer
|
||||
cookie_lifetime: 2592000
|
||||
lifetime: 2592000
|
||||
|
||||
backup_codes:
|
||||
enabled: "%twofactor_auth%"
|
||||
|
||||
google:
|
||||
enabled: "%twofactor_auth%"
|
||||
template: WallabagUserBundle:Authentication:form.html.twig
|
||||
|
||||
email:
|
||||
enabled: "%twofactor_auth%"
|
||||
|
@ -357,3 +365,30 @@ jms_serializer:
|
|||
# see: https://github.com/schmittjoh/JMSSerializerBundle/pull/494
|
||||
datetime:
|
||||
default_format: "Y-m-d\\TH:i:sO" # ATOM
|
||||
|
||||
# see https://github.com/symfony/symfony-standard/pull/1133
|
||||
sensio_framework_extra:
|
||||
router:
|
||||
annotations: false
|
||||
|
||||
httplug:
|
||||
clients:
|
||||
wallabag_core:
|
||||
factory: 'wallabag_core.http_client_factory'
|
||||
config:
|
||||
defaults:
|
||||
timeout: 10
|
||||
plugins: ['httplug.plugin.logger']
|
||||
wallabag_core.entry.download_images:
|
||||
factory: 'httplug.factory.auto'
|
||||
plugins: ['httplug.plugin.logger']
|
||||
wallabag_import.pocket.client:
|
||||
factory: 'httplug.factory.auto'
|
||||
plugins:
|
||||
- 'httplug.plugin.logger'
|
||||
- header_defaults:
|
||||
headers:
|
||||
'content-type': 'application/json'
|
||||
'X-Accept': 'application/json'
|
||||
discovery:
|
||||
client: false
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
imports:
|
||||
- { resource: config_dev.yml }
|
||||
- { resource: parameters_test.yml }
|
||||
- { resource: services_test.yml }
|
||||
|
||||
framework:
|
||||
test: ~
|
||||
|
@ -23,7 +24,6 @@ swiftmailer:
|
|||
doctrine:
|
||||
dbal:
|
||||
driver: "%test_database_driver%"
|
||||
driver_class: "%test_database_driver_class%"
|
||||
host: "%test_database_host%"
|
||||
port: "%test_database_port%"
|
||||
dbname: "%test_database_name%"
|
||||
|
|
|
@ -11,8 +11,6 @@ parameters:
|
|||
# database_password: %env.database_password%
|
||||
|
||||
database_driver: pdo_mysql
|
||||
database_driver_class: ~
|
||||
# database_driver_class: Wallabag\CoreBundle\Doctrine\DBAL\Driver\CustomPostgreSQLDriver
|
||||
database_host: 127.0.0.1
|
||||
database_port: ~
|
||||
database_name: wallabag
|
||||
|
@ -27,10 +25,13 @@ parameters:
|
|||
|
||||
domain_name: https://your-wallabag-url-instance.com
|
||||
|
||||
mailer_transport: smtp
|
||||
mailer_host: 127.0.0.1
|
||||
mailer_user: ~
|
||||
mailer_password: ~
|
||||
mailer_transport: smtp
|
||||
mailer_user: ~
|
||||
mailer_password: ~
|
||||
mailer_host: 127.0.0.1
|
||||
mailer_port: false
|
||||
mailer_encryption: ~
|
||||
mailer_auth_mode: ~
|
||||
|
||||
locale: en
|
||||
|
||||
|
|
|
@ -8,4 +8,3 @@ parameters:
|
|||
test_database_path: "%env(TEST_DATABASE_PATH)%"
|
||||
env(TEST_DATABASE_PATH): "%kernel.project_dir%/data/db/wallabag_test.sqlite"
|
||||
test_database_charset: utf8
|
||||
test_database_driver_class: ~
|
||||
|
|
|
@ -51,3 +51,47 @@ craue_config_settings_modify:
|
|||
|
||||
fos_js_routing:
|
||||
resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml"
|
||||
|
||||
2fa_login:
|
||||
path: /2fa
|
||||
defaults:
|
||||
_controller: "scheb_two_factor.form_controller:form"
|
||||
|
||||
2fa_login_check:
|
||||
path: /2fa_check
|
||||
|
||||
# redirect RSS feed to Atom
|
||||
rss_to_atom_unread:
|
||||
path: /{username}/{token}/unread.xml
|
||||
defaults:
|
||||
_controller: FrameworkBundle:Redirect:redirect
|
||||
route: unread_feed
|
||||
permanent: true
|
||||
|
||||
rss_to_atom_archive:
|
||||
path: /{username}/{token}/archive.xml
|
||||
defaults:
|
||||
_controller: FrameworkBundle:Redirect:redirect
|
||||
route: archive_feed
|
||||
permanent: true
|
||||
|
||||
rss_to_atom_starred:
|
||||
path: /{username}/{token}/starred.xml
|
||||
defaults:
|
||||
_controller: FrameworkBundle:Redirect:redirect
|
||||
route: starred_feed
|
||||
permanent: true
|
||||
|
||||
rss_to_atom_all:
|
||||
path: /{username}/{token}/all.xml
|
||||
defaults:
|
||||
_controller: FrameworkBundle:Redirect:redirect
|
||||
route: all_feed
|
||||
permanent: true
|
||||
|
||||
rss_to_atom_tags:
|
||||
path: /{username}/{token}/tags/{slug}.xml
|
||||
defaults:
|
||||
_controller: FrameworkBundle:Redirect:redirect
|
||||
route: tag_feed
|
||||
permanent: true
|
||||
|
|
|
@ -31,12 +31,15 @@ security:
|
|||
fos_oauth: true
|
||||
stateless: true
|
||||
anonymous: true
|
||||
provider: fos_userbundle
|
||||
|
||||
login_firewall:
|
||||
logout_on_user_change: true
|
||||
pattern: ^/login$
|
||||
anonymous: ~
|
||||
|
||||
secured_area:
|
||||
logout_on_user_change: true
|
||||
pattern: ^/
|
||||
form_login:
|
||||
provider: fos_userbundle
|
||||
|
@ -53,17 +56,27 @@ security:
|
|||
path: /logout
|
||||
target: /
|
||||
|
||||
two_factor:
|
||||
provider: fos_userbundle
|
||||
auth_form_path: 2fa_login
|
||||
check_path: 2fa_login_check
|
||||
|
||||
access_control:
|
||||
- { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/api/version, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/api/user, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/api/(doc|version|info|user), roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
# force role for logout otherwise when 2fa enable, you won't be able to logout
|
||||
# https://github.com/scheb/two-factor-bundle/issues/168#issuecomment-430822478
|
||||
- { path: ^/logout, roles: [IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_2FA_IN_PROGRESS] }
|
||||
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: /(unread|starred|archive|all).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/locale, role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: /tags/(.*).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/feed, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } # For backwards compatibility
|
||||
- { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/settings, roles: ROLE_SUPER_ADMIN }
|
||||
- { path: ^/annotations, roles: ROLE_USER }
|
||||
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
|
||||
- { path: ^/users, roles: ROLE_SUPER_ADMIN }
|
||||
- { path: ^/, roles: ROLE_USER }
|
||||
|
|
|
@ -2,12 +2,6 @@ parameters:
|
|||
lexik_form_filter.get_filter.doctrine_orm.class: Wallabag\CoreBundle\Event\Subscriber\CustomDoctrineORMSubscriber
|
||||
|
||||
services:
|
||||
# used for tests
|
||||
filesystem_cache:
|
||||
class: Doctrine\Common\Cache\FilesystemCache
|
||||
arguments:
|
||||
- "%kernel.cache_dir%/doctrine/metadata"
|
||||
|
||||
twig.extension.text:
|
||||
class: Twig_Extensions_Extension_Text
|
||||
tags:
|
||||
|
|
38
app/config/services_test.yml
Normal file
38
app/config/services_test.yml
Normal file
|
@ -0,0 +1,38 @@
|
|||
services:
|
||||
# see https://github.com/symfony/symfony/issues/24543
|
||||
fos_user.user_manager.test:
|
||||
alias: fos_user.user_manager
|
||||
public: true
|
||||
|
||||
fos_user.security.login_manager.test:
|
||||
alias: fos_user.security.login_manager
|
||||
public: true
|
||||
|
||||
wallabag_core.entry_repository.test:
|
||||
alias: wallabag_core.entry_repository
|
||||
public: true
|
||||
|
||||
wallabag_user.user_repository.test:
|
||||
alias: wallabag_user.user_repository
|
||||
public: true
|
||||
|
||||
filesystem_cache:
|
||||
class: Doctrine\Common\Cache\FilesystemCache
|
||||
arguments:
|
||||
- "%kernel.cache_dir%/doctrine/metadata"
|
||||
|
||||
# fixtures
|
||||
Wallabag\UserBundle\DataFixtures\:
|
||||
resource: '../../src/Wallabag/UserBundle/DataFixtures/*'
|
||||
tags: ['doctrine.fixture.orm']
|
||||
autowire: true
|
||||
|
||||
Wallabag\CoreBundle\DataFixtures\:
|
||||
resource: '../../src/Wallabag/CoreBundle/DataFixtures/*'
|
||||
tags: ['doctrine.fixture.orm']
|
||||
autowire: true
|
||||
|
||||
Wallabag\AnnotationBundle\DataFixtures\:
|
||||
resource: '../../src/Wallabag/AnnotationBundle/DataFixtures/*'
|
||||
tags: ['doctrine.fixture.orm']
|
||||
autowire: true
|
|
@ -1,6 +1,5 @@
|
|||
parameters:
|
||||
test_database_driver: pdo_mysql
|
||||
test_database_driver_class: ~
|
||||
test_database_host: localhost
|
||||
test_database_port: 3306
|
||||
test_database_name: wallabag_test
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
parameters:
|
||||
test_database_driver: pdo_pgsql
|
||||
test_database_driver_class: Wallabag\CoreBundle\Doctrine\DBAL\Driver\CustomPostgreSQLDriver
|
||||
test_database_host: localhost
|
||||
test_database_port:
|
||||
test_database_name: wallabag_test
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
parameters:
|
||||
test_database_driver: pdo_sqlite
|
||||
test_database_driver_class: ~
|
||||
test_database_host: localhost
|
||||
test_database_port:
|
||||
test_database_name: ~
|
||||
|
|
12
bin/console
12
bin/console
|
@ -6,19 +6,17 @@ use Symfony\Component\Console\Input\ArgvInput;
|
|||
use Symfony\Component\Debug\Debug;
|
||||
|
||||
// if you don't want to setup permissions the proper way, just uncomment the following PHP line
|
||||
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
|
||||
// read https://symfony.com/doc/current/setup.html#checking-symfony-application-configuration-and-setup
|
||||
// for more information
|
||||
//umask(0000);
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
/**
|
||||
* @var Composer\Autoload\ClassLoader $loader
|
||||
*/
|
||||
$loader = require __DIR__.'/../app/autoload.php';
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$input = new ArgvInput();
|
||||
$env = $input->getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev');
|
||||
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod';
|
||||
$env = $input->getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev', true);
|
||||
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption('--no-debug', true) && $env !== 'prod';
|
||||
|
||||
if ($debug) {
|
||||
Debug::enable();
|
||||
|
|
108
composer.json
108
composer.json
|
@ -2,7 +2,10 @@
|
|||
"name": "wallabag/wallabag",
|
||||
"type": "project",
|
||||
"description": "open source self hostable read-it-later web application",
|
||||
"keywords": ["read-it-later","read it later"],
|
||||
"keywords": [
|
||||
"read-it-later",
|
||||
"read it later"
|
||||
],
|
||||
"homepage": "https://github.com/wallabag/wallabag",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
|
@ -28,7 +31,7 @@
|
|||
"issues": "https://github.com/wallabag/wallabag/issues"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"php": ">=7.1.3",
|
||||
"ext-pcre": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-curl": "*",
|
||||
|
@ -44,59 +47,68 @@
|
|||
"ext-tokenizer": "*",
|
||||
"ext-pdo": "*",
|
||||
"ext-tidy": "*",
|
||||
"symfony/symfony": "~3.3.13",
|
||||
"doctrine/orm": "^2.5.12",
|
||||
"doctrine/doctrine-bundle": "^1.8.0",
|
||||
"doctrine/doctrine-cache-bundle": "^1.3.2",
|
||||
"twig/extensions": "^1.5.1",
|
||||
"symfony/swiftmailer-bundle": "^2.6.7",
|
||||
"symfony/monolog-bundle": "^3.1.2",
|
||||
"sensio/distribution-bundle": "^5.0.21",
|
||||
"sensio/framework-extra-bundle": "^3.0.28",
|
||||
"incenteev/composer-parameter-handler": "^2.1.2",
|
||||
"symfony/symfony": "3.4.*",
|
||||
"doctrine/orm": "^2.6",
|
||||
"doctrine/doctrine-bundle": "^1.9",
|
||||
"doctrine/doctrine-cache-bundle": "^1.3",
|
||||
"twig/extensions": "^1.5",
|
||||
"symfony/swiftmailer-bundle": "^3.2",
|
||||
"symfony/monolog-bundle": "^3.1",
|
||||
"sensio/distribution-bundle": "^5.0",
|
||||
"sensio/framework-extra-bundle": "^5.2",
|
||||
"incenteev/composer-parameter-handler": "^2.1",
|
||||
"nelmio/cors-bundle": "~1.5",
|
||||
"friendsofsymfony/rest-bundle": "~2.1",
|
||||
"jms/serializer-bundle": "~2.2",
|
||||
"nelmio/api-doc-bundle": "^2.13.2",
|
||||
"mgargano/simplehtmldom": "~1.5",
|
||||
"wallabag/tcpdf": "^6.2.15",
|
||||
"wallabag/tcpdf": "^6.2.26",
|
||||
"simplepie/simplepie": "~1.5",
|
||||
"willdurand/hateoas-bundle": "~1.3",
|
||||
"liip/theme-bundle": "^1.4.6",
|
||||
"lexik/form-filter-bundle": "^5.0.4",
|
||||
"j0k3r/graby": "^1.0",
|
||||
"j0k3r/graby": "^2.0",
|
||||
"php-http/guzzle5-adapter": "^2.0",
|
||||
"friendsofsymfony/user-bundle": "2.0.*",
|
||||
"friendsofsymfony/oauth-server-bundle": "^1.5.2",
|
||||
"friendsofsymfony/oauth-server-bundle": "^1.5",
|
||||
"stof/doctrine-extensions-bundle": "^1.2",
|
||||
"scheb/two-factor-bundle": "^2.14.0",
|
||||
"grandt/phpepub": "^4.0.7",
|
||||
"wallabag/php-mobi": "~1.0.0",
|
||||
"scheb/two-factor-bundle": "^3.0",
|
||||
"grandt/phpepub": "dev-master",
|
||||
"wallabag/php-mobi": "~1.0",
|
||||
"kphoen/rulerz-bundle": "~0.13",
|
||||
"guzzlehttp/guzzle": "^5.3.1",
|
||||
"doctrine/doctrine-migrations-bundle": "^1.3",
|
||||
"paragonie/random_compat": "^2.0.11",
|
||||
"craue/config-bundle": "~2.0",
|
||||
"craue/config-bundle": "dev-utf8mb4",
|
||||
"mnapoli/piwik-twig-extension": "^1.0",
|
||||
"ocramius/proxy-manager": "^1.0.2",
|
||||
"white-october/pagerfanta-bundle": "^1.1.0",
|
||||
"ocramius/proxy-manager": "^2.1.1",
|
||||
"white-october/pagerfanta-bundle": "^1.1",
|
||||
"php-amqplib/rabbitmq-bundle": "^1.14",
|
||||
"predis/predis": "^1.1.1",
|
||||
"predis/predis": "v1.1.x-dev",
|
||||
"javibravo/simpleue": "^2.0",
|
||||
"symfony/dom-crawler": "^3.3.13",
|
||||
"friendsofsymfony/jsrouting-bundle": "^1.6.3",
|
||||
"symfony/dom-crawler": "^3.4",
|
||||
"friendsofsymfony/jsrouting-bundle": "^2.2",
|
||||
"bdunogier/guzzle-site-authenticator": "^1.0.0",
|
||||
"defuse/php-encryption": "^2.1",
|
||||
"html2text/html2text": "^4.1",
|
||||
"sulu/symfony-intl-fix": "^1.0"
|
||||
"pragmarx/recovery": "^0.1.0",
|
||||
"php-http/httplug-bundle": "^1.14"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-fixtures-bundle": "~2.2",
|
||||
"doctrine/data-fixtures": "~1.1",
|
||||
"doctrine/doctrine-fixtures-bundle": "~3.0",
|
||||
"sensio/generator-bundle": "^3.0",
|
||||
"symfony/phpunit-bridge": "^4.2",
|
||||
"friendsofphp/php-cs-fixer": "~2.0",
|
||||
"m6web/redis-mock": "^2.0",
|
||||
"dama/doctrine-test-bundle": "^4.0"
|
||||
"friendsofphp/php-cs-fixer": "~2.13",
|
||||
"m6web/redis-mock": "^4.1",
|
||||
"dama/doctrine-test-bundle": "^5.0",
|
||||
"phpstan/phpstan": "^0.11.0",
|
||||
"phpstan/phpstan-phpunit": "^0.11.0",
|
||||
"phpstan/phpstan-symfony": "^0.11.0",
|
||||
"phpstan/phpstan-doctrine": "^0.11.0",
|
||||
"php-http/mock-client": "^1.0",
|
||||
"guzzlehttp/psr7": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-imagick": "To keep GIF animation when downloading image is enabled"
|
||||
},
|
||||
"scripts": {
|
||||
"post-cmd": [
|
||||
|
@ -125,22 +137,40 @@
|
|||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Wallabag\\": "src/Wallabag/" },
|
||||
"classmap": [ "app/AppKernel.php", "app/AppCache.php" ],
|
||||
"exclude-from-classmap": [
|
||||
"vendor/symfony/intl/Locale.php",
|
||||
"vendor/symfony/symfony/src/Symfony/Component/Intl/Locale.php"
|
||||
"psr-4": {
|
||||
"Wallabag\\": "src/Wallabag/"
|
||||
},
|
||||
"classmap": [
|
||||
"app/AppKernel.php",
|
||||
"app/AppCache.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "Tests\\": "tests/" }
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
},
|
||||
"files": [
|
||||
"vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"bin-dir": "bin",
|
||||
"platform": {
|
||||
"php": "5.6.0"
|
||||
"php": "7.1.3"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
"prefer-stable": true,
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/Daniel-KM/PHPePub",
|
||||
"comment": "The most up-to-date PHPePub as of now"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/wallabag/CraueConfigBundle",
|
||||
"comment": "To handle utf8mb4 field size"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM php:fpm
|
||||
FROM php:7.2-fpm
|
||||
|
||||
# Default timezone. To change it, use the argument in the docker-compose.yml file
|
||||
ARG timezone='Europe/Paris'
|
||||
|
|
13
phpstan.neon
Normal file
13
phpstan.neon
Normal file
|
@ -0,0 +1,13 @@
|
|||
includes:
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- vendor/phpstan/phpstan-symfony/extension.neon
|
||||
- vendor/phpstan/phpstan-doctrine/extension.neon
|
||||
- vendor/phpstan/phpstan-phpunit/rules.neon
|
||||
|
||||
parameters:
|
||||
symfony:
|
||||
container_xml_path: %rootDir%/../../../var/cache/test/appTestDebugProjectContainer.xml
|
||||
|
||||
# https://github.com/phpstan/phpstan/issues/694#issuecomment-350724288
|
||||
autoload_files:
|
||||
- vendor/bin/.phpunit/phpunit-6.5/vendor/autoload.php
|
|
@ -4,7 +4,7 @@
|
|||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="app/autoload.php"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
|
||||
<testsuites>
|
||||
|
@ -15,7 +15,7 @@
|
|||
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<server name="KERNEL_DIR" value="app/" />
|
||||
<server name="KERNEL_CLASS" value="AppKernel" />
|
||||
<env name="SYMFONY_DEPRECATIONS_HELPER" value="weak" />
|
||||
</php>
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\AnnotationBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\AnnotationBundle\DataFixtures;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\AnnotationBundle\Entity\Annotation;
|
||||
use Wallabag\CoreBundle\DataFixtures\EntryFixtures;
|
||||
use Wallabag\UserBundle\DataFixtures\UserFixtures;
|
||||
|
||||
class LoadAnnotationData extends AbstractFixture implements OrderedFixtureInterface
|
||||
class AnnotationFixtures extends Fixture implements DependentFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -38,8 +40,11 @@ class LoadAnnotationData extends AbstractFixture implements OrderedFixtureInterf
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
public function getDependencies()
|
||||
{
|
||||
return 35;
|
||||
return [
|
||||
EntryFixtures::class,
|
||||
UserFixtures::class,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace Wallabag\ApiBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\ApiBundle\Entity\Client;
|
||||
use Wallabag\ApiBundle\Form\Type\ClientType;
|
||||
|
||||
|
|
|
@ -4,18 +4,17 @@ namespace Wallabag\ApiBundle\Controller;
|
|||
|
||||
use Hateoas\Configuration\Route;
|
||||
use Hateoas\Representation\Factory\PagerfantaFactory;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
use Wallabag\CoreBundle\Event\EntryDeletedEvent;
|
||||
use Wallabag\CoreBundle\Event\EntrySavedEvent;
|
||||
use Wallabag\CoreBundle\Helper\UrlHasher;
|
||||
|
||||
class EntryRestController extends WallabagRestController
|
||||
{
|
||||
|
@ -29,8 +28,10 @@ class EntryRestController extends WallabagRestController
|
|||
* @ApiDoc(
|
||||
* parameters={
|
||||
* {"name"="return_id", "dataType"="string", "required"=false, "format"="1 or 0", "description"="Set 1 if you want to retrieve ID in case entry(ies) exists, 0 by default"},
|
||||
* {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"},
|
||||
* {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="Urls (as an array) to check if it exists"}
|
||||
* {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="DEPRECATED, use hashed_url instead"},
|
||||
* {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="DEPRECATED, use hashed_urls instead"},
|
||||
* {"name"="hashed_url", "dataType"="string", "required"=false, "format"="A hashed url", "description"="Hashed url using SHA1 to check if it exists"},
|
||||
* {"name"="hashed_urls", "dataType"="string", "required"=false, "format"="An array of hashed urls (?hashed_urls[]=xxx...&hashed_urls[]=xxx...)", "description"="An array of hashed urls using SHA1 to check if they exist"}
|
||||
* }
|
||||
* )
|
||||
*
|
||||
|
@ -39,38 +40,49 @@ class EntryRestController extends WallabagRestController
|
|||
public function getEntriesExistsAction(Request $request)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
$repo = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
|
||||
$returnId = (null === $request->query->get('return_id')) ? false : (bool) $request->query->get('return_id');
|
||||
$urls = $request->query->get('urls', []);
|
||||
|
||||
// handle multiple urls first
|
||||
if (!empty($urls)) {
|
||||
$results = [];
|
||||
foreach ($urls as $url) {
|
||||
$res = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findByUrlAndUserId($url, $this->getUser()->getId());
|
||||
|
||||
$results[$url] = $this->returnExistInformation($res, $returnId);
|
||||
}
|
||||
|
||||
return $this->sendResponse($results);
|
||||
$hashedUrls = $request->query->get('hashed_urls', []);
|
||||
$hashedUrl = $request->query->get('hashed_url', '');
|
||||
if (!empty($hashedUrl)) {
|
||||
$hashedUrls[] = $hashedUrl;
|
||||
}
|
||||
|
||||
// let's see if it is a simple url?
|
||||
$urls = $request->query->get('urls', []);
|
||||
$url = $request->query->get('url', '');
|
||||
if (!empty($url)) {
|
||||
$urls[] = $url;
|
||||
}
|
||||
|
||||
if (empty($url)) {
|
||||
$urlHashMap = [];
|
||||
foreach ($urls as $urlToHash) {
|
||||
$urlHash = UrlHasher::hashUrl($urlToHash);
|
||||
$hashedUrls[] = $urlHash;
|
||||
$urlHashMap[$urlHash] = $urlToHash;
|
||||
}
|
||||
|
||||
if (empty($hashedUrls)) {
|
||||
throw $this->createAccessDeniedException('URL is empty?, logged user id: ' . $this->getUser()->getId());
|
||||
}
|
||||
|
||||
$res = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findByUrlAndUserId($url, $this->getUser()->getId());
|
||||
$results = [];
|
||||
foreach ($hashedUrls as $hashedUrlToSearch) {
|
||||
$res = $repo->findByHashedUrlAndUserId($hashedUrlToSearch, $this->getUser()->getId());
|
||||
|
||||
$exists = $this->returnExistInformation($res, $returnId);
|
||||
$results[$hashedUrlToSearch] = $this->returnExistInformation($res, $returnId);
|
||||
}
|
||||
|
||||
return $this->sendResponse(['exists' => $exists]);
|
||||
$results = $this->replaceUrlHashes($results, $urlHashMap);
|
||||
|
||||
if (!empty($url) || !empty($hashedUrl)) {
|
||||
$hu = array_keys($results)[0];
|
||||
|
||||
return $this->sendResponse(['exists' => $results[$hu]]);
|
||||
}
|
||||
|
||||
return $this->sendResponse($results);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,13 +92,14 @@ class EntryRestController extends WallabagRestController
|
|||
* parameters={
|
||||
* {"name"="archive", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by archived status."},
|
||||
* {"name"="starred", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by starred status."},
|
||||
* {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated', default 'created'", "description"="sort entries by date."},
|
||||
* {"name"="sort", "dataType"="string", "required"=false, "format"="'created' or 'updated' or 'archived', default 'created'", "description"="sort entries by date."},
|
||||
* {"name"="order", "dataType"="string", "required"=false, "format"="'asc' or 'desc', default 'desc'", "description"="order of sort."},
|
||||
* {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
|
||||
* {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."},
|
||||
* {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."},
|
||||
* {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."},
|
||||
* {"name"="public", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by entries with a public link"},
|
||||
* {"name"="detail", "dataType"="string", "required"=false, "format"="metadata or full, metadata by default", "description"="include content field if 'full'. 'full' by default for backward compatibility."},
|
||||
* }
|
||||
* )
|
||||
*
|
||||
|
@ -105,6 +118,7 @@ class EntryRestController extends WallabagRestController
|
|||
$perPage = (int) $request->query->get('perPage', 30);
|
||||
$tags = \is_array($request->query->get('tags')) ? '' : (string) $request->query->get('tags', '');
|
||||
$since = $request->query->get('since', 0);
|
||||
$detail = strtolower($request->query->get('detail', 'full'));
|
||||
|
||||
try {
|
||||
/** @var \Pagerfanta\Pagerfanta $pager */
|
||||
|
@ -116,7 +130,8 @@ class EntryRestController extends WallabagRestController
|
|||
$sort,
|
||||
$order,
|
||||
$since,
|
||||
$tags
|
||||
$tags,
|
||||
$detail
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
throw new BadRequestHttpException($e->getMessage());
|
||||
|
@ -140,8 +155,9 @@ class EntryRestController extends WallabagRestController
|
|||
'perPage' => $perPage,
|
||||
'tags' => $tags,
|
||||
'since' => $since,
|
||||
'detail' => $detail,
|
||||
],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -349,9 +365,7 @@ class EntryRestController extends WallabagRestController
|
|||
'language' => !empty($data['language']) ? $data['language'] : $entry->getLanguage(),
|
||||
'date' => !empty($data['publishedAt']) ? $data['publishedAt'] : $entry->getPublishedAt(),
|
||||
// faking the open graph preview picture
|
||||
'open_graph' => [
|
||||
'og_image' => !empty($data['picture']) ? $data['picture'] : $entry->getPreviewPicture(),
|
||||
],
|
||||
'image' => !empty($data['picture']) ? $data['picture'] : $entry->getPreviewPicture(),
|
||||
'authors' => \is_string($data['authors']) ? explode(',', $data['authors']) : $entry->getPublishedBy(),
|
||||
]
|
||||
);
|
||||
|
@ -363,7 +377,7 @@ class EntryRestController extends WallabagRestController
|
|||
}
|
||||
|
||||
if (null !== $data['isArchived']) {
|
||||
$entry->setArchived((bool) $data['isArchived']);
|
||||
$entry->updateArchived((bool) $data['isArchived']);
|
||||
}
|
||||
|
||||
if (null !== $data['isStarred']) {
|
||||
|
@ -479,7 +493,7 @@ class EntryRestController extends WallabagRestController
|
|||
}
|
||||
|
||||
if (null !== $data['isArchived']) {
|
||||
$entry->setArchived((bool) $data['isArchived']);
|
||||
$entry->updateArchived((bool) $data['isArchived']);
|
||||
}
|
||||
|
||||
if (null !== $data['isStarred']) {
|
||||
|
@ -787,21 +801,21 @@ class EntryRestController extends WallabagRestController
|
|||
}
|
||||
|
||||
/**
|
||||
* Shortcut to send data serialized in json.
|
||||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return JsonResponse
|
||||
* Replace the hashedUrl keys in $results with the unhashed URL from the
|
||||
* request, as recorded in $urlHashMap.
|
||||
*/
|
||||
private function sendResponse($data)
|
||||
private function replaceUrlHashes(array $results, array $urlHashMap)
|
||||
{
|
||||
// https://github.com/schmittjoh/JMSSerializerBundle/issues/293
|
||||
$context = new SerializationContext();
|
||||
$context->setSerializeNull(true);
|
||||
$newResults = [];
|
||||
foreach ($results as $hash => $res) {
|
||||
if (isset($urlHashMap[$hash])) {
|
||||
$newResults[$urlHashMap[$hash]] = $res;
|
||||
} else {
|
||||
$newResults[$hash] = $res;
|
||||
}
|
||||
}
|
||||
|
||||
$json = $this->get('jms_serializer')->serialize($data, 'json', $context);
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
return $newResults;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -832,8 +846,8 @@ class EntryRestController extends WallabagRestController
|
|||
/**
|
||||
* Return information about the entry if it exist and depending on the id or not.
|
||||
*
|
||||
* @param Entry|null $entry
|
||||
* @param bool $returnId
|
||||
* @param Entry|bool|null $entry
|
||||
* @param bool $returnId
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
|
|
65
src/Wallabag/ApiBundle/Controller/SearchRestController.php
Normal file
65
src/Wallabag/ApiBundle/Controller/SearchRestController.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Controller;
|
||||
|
||||
use Hateoas\Configuration\Route;
|
||||
use Hateoas\Representation\Factory\PagerfantaFactory;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class SearchRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Search all entries by term.
|
||||
*
|
||||
* @ApiDoc(
|
||||
* parameters={
|
||||
* {"name"="term", "dataType"="string", "required"=false, "format"="any", "description"="Any query term"},
|
||||
* {"name"="page", "dataType"="integer", "required"=false, "format"="default '1'", "description"="what page you want."},
|
||||
* {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."}
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getSearchAction(Request $request)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$term = $request->query->get('term');
|
||||
$page = (int) $request->query->get('page', 1);
|
||||
$perPage = (int) $request->query->get('perPage', 30);
|
||||
|
||||
$qb = $this->get('wallabag_core.entry_repository')
|
||||
->getBuilderForSearchByUser(
|
||||
$this->getUser()->getId(),
|
||||
$term,
|
||||
null
|
||||
);
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
|
||||
$pager = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$pager->setMaxPerPage($perPage);
|
||||
$pager->setCurrentPage($page);
|
||||
|
||||
$pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
|
||||
$paginatedCollection = $pagerfantaFactory->createRepresentation(
|
||||
$pager,
|
||||
new Route(
|
||||
'api_get_search',
|
||||
[
|
||||
'term' => $term,
|
||||
'page' => $page,
|
||||
'perPage' => $perPage,
|
||||
],
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
return $this->sendResponse($paginatedCollection);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace Wallabag\ApiBundle\Controller;
|
||||
|
||||
use FOS\RestBundle\Controller\FOSRestController;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
|
@ -14,6 +15,8 @@ class WallabagRestController extends FOSRestController
|
|||
*
|
||||
* @ApiDoc()
|
||||
*
|
||||
* @deprecated Should use info endpoint instead
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getVersionAction()
|
||||
|
@ -24,6 +27,24 @@ class WallabagRestController extends FOSRestController
|
|||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve information about the wallabag instance.
|
||||
*
|
||||
* @ApiDoc()
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getInfoAction()
|
||||
{
|
||||
$info = [
|
||||
'appname' => 'wallabag',
|
||||
'version' => $this->container->getParameter('wallabag_core.version'),
|
||||
'allowed_registration' => $this->container->getParameter('wallabag_user.registration_enabled'),
|
||||
];
|
||||
|
||||
return (new JsonResponse())->setJson($this->get('jms_serializer')->serialize($info, 'json'));
|
||||
}
|
||||
|
||||
protected function validateAuthentication()
|
||||
{
|
||||
if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
|
||||
|
@ -44,4 +65,22 @@ class WallabagRestController extends FOSRestController
|
|||
throw $this->createAccessDeniedException('Access forbidden. Entry user id: ' . $requestUserId . ', logged user id: ' . $user->getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to send data serialized in json.
|
||||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
protected function sendResponse($data)
|
||||
{
|
||||
// https://github.com/schmittjoh/JMSSerializerBundle/issues/293
|
||||
$context = new SerializationContext();
|
||||
$context->setSerializeNull(true);
|
||||
|
||||
$json = $this->get('jms_serializer')->serialize($data, 'json', $context);
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,22 @@ use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken;
|
|||
/**
|
||||
* @ORM\Table("oauth2_access_tokens")
|
||||
* @ORM\Entity
|
||||
* @ORM\AttributeOverrides({
|
||||
* @ORM\AttributeOverride(name="token",
|
||||
* column=@ORM\Column(
|
||||
* name = "token",
|
||||
* type = "string",
|
||||
* length = 191
|
||||
* )
|
||||
* ),
|
||||
* @ORM\AttributeOverride(name="scope",
|
||||
* column=@ORM\Column(
|
||||
* name = "scope",
|
||||
* type = "string",
|
||||
* length = 191
|
||||
* )
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class AccessToken extends BaseAccessToken
|
||||
{
|
||||
|
@ -26,6 +42,7 @@ class AccessToken extends BaseAccessToken
|
|||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,22 @@ use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode;
|
|||
/**
|
||||
* @ORM\Table("oauth2_auth_codes")
|
||||
* @ORM\Entity
|
||||
* @ORM\AttributeOverrides({
|
||||
* @ORM\AttributeOverride(name="token",
|
||||
* column=@ORM\Column(
|
||||
* name = "token",
|
||||
* type = "string",
|
||||
* length = 191
|
||||
* )
|
||||
* ),
|
||||
* @ORM\AttributeOverride(name="scope",
|
||||
* column=@ORM\Column(
|
||||
* name = "scope",
|
||||
* type = "string",
|
||||
* length = 191
|
||||
* )
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class AuthCode extends BaseAuthCode
|
||||
{
|
||||
|
@ -26,6 +42,7 @@ class AuthCode extends BaseAuthCode
|
|||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,22 @@ use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken;
|
|||
/**
|
||||
* @ORM\Table("oauth2_refresh_tokens")
|
||||
* @ORM\Entity
|
||||
* @ORM\AttributeOverrides({
|
||||
* @ORM\AttributeOverride(name="token",
|
||||
* column=@ORM\Column(
|
||||
* name = "token",
|
||||
* type = "string",
|
||||
* length = 191
|
||||
* )
|
||||
* ),
|
||||
* @ORM\AttributeOverride(name="scope",
|
||||
* column=@ORM\Column(
|
||||
* name = "scope",
|
||||
* type = "string",
|
||||
* length = 191
|
||||
* )
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class RefreshToken extends BaseRefreshToken
|
||||
{
|
||||
|
@ -26,6 +42,7 @@ class RefreshToken extends BaseRefreshToken
|
|||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ class ClientType extends AbstractType
|
|||
'required' => false,
|
||||
'label' => 'developer.client.form.redirect_uris_label',
|
||||
'property_path' => 'redirectUris',
|
||||
'default_protocol' => null,
|
||||
])
|
||||
->add('save', SubmitType::class, ['label' => 'developer.client.form.save_label'])
|
||||
;
|
||||
|
|
|
@ -3,6 +3,11 @@ entry:
|
|||
resource: "WallabagApiBundle:EntryRest"
|
||||
name_prefix: api_
|
||||
|
||||
search:
|
||||
type: rest
|
||||
resource: "WallabagApiBundle:SearchRest"
|
||||
name_prefix: api_
|
||||
|
||||
tag:
|
||||
type: rest
|
||||
resource: "WallabagApiBundle:TagRest"
|
||||
|
|
99
src/Wallabag/CoreBundle/Command/GenerateUrlHashesCommand.php
Normal file
99
src/Wallabag/CoreBundle/Command/GenerateUrlHashesCommand.php
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Command;
|
||||
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Wallabag\CoreBundle\Helper\UrlHasher;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
class GenerateUrlHashesCommand extends ContainerAwareCommand
|
||||
{
|
||||
/** @var OutputInterface */
|
||||
protected $output;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('wallabag:generate-hashed-urls')
|
||||
->setDescription('Generates hashed urls for each entry')
|
||||
->setHelp('This command helps you to generates hashes of the url of each entry, to check through API if an URL is already saved')
|
||||
->addArgument('username', InputArgument::OPTIONAL, 'User to process entries');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
$username = (string) $input->getArgument('username');
|
||||
|
||||
if ($username) {
|
||||
try {
|
||||
$user = $this->getUser($username);
|
||||
$this->generateHashedUrls($user);
|
||||
} catch (NoResultException $e) {
|
||||
$output->writeln(sprintf('<error>User "%s" not found.</error>', $username));
|
||||
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
$users = $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findAll();
|
||||
|
||||
$output->writeln(sprintf('Generating hashed urls for "%d" users', \count($users)));
|
||||
|
||||
foreach ($users as $user) {
|
||||
$output->writeln(sprintf('Processing user: %s', $user->getUsername()));
|
||||
$this->generateHashedUrls($user);
|
||||
}
|
||||
$output->writeln('Finished generated hashed urls');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
private function generateHashedUrls(User $user)
|
||||
{
|
||||
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$repo = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
|
||||
$entries = $repo->findByUser($user->getId());
|
||||
|
||||
$i = 1;
|
||||
foreach ($entries as $entry) {
|
||||
$entry->setHashedUrl(UrlHasher::hashUrl($entry->getUrl()));
|
||||
$em->persist($entry);
|
||||
|
||||
if (0 === ($i % 20)) {
|
||||
$em->flush();
|
||||
}
|
||||
++$i;
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
|
||||
$this->output->writeln(sprintf('Generated hashed urls for user: %s', $user->getUserName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a user from its username.
|
||||
*
|
||||
* @param string $username
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
private function getUser($username)
|
||||
{
|
||||
return $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findOneByUserName($username);
|
||||
}
|
||||
|
||||
private function getDoctrine()
|
||||
{
|
||||
return $this->getContainer()->get('doctrine');
|
||||
}
|
||||
}
|
|
@ -94,8 +94,9 @@ class InstallCommand extends ContainerAwareCommand
|
|||
$status = '<info>OK!</info>';
|
||||
$help = '';
|
||||
|
||||
$conn = $this->getContainer()->get('doctrine')->getManager()->getConnection();
|
||||
|
||||
try {
|
||||
$conn = $this->getContainer()->get('doctrine')->getManager()->getConnection();
|
||||
$conn->connect();
|
||||
} catch (\Exception $e) {
|
||||
if (false === strpos($e->getMessage(), 'Unknown database')
|
||||
|
@ -253,7 +254,7 @@ class InstallCommand extends ContainerAwareCommand
|
|||
$question->setHidden(true);
|
||||
$user->setPlainPassword($this->io->askQuestion($question));
|
||||
|
||||
$user->setEmail($this->io->ask('Email', ''));
|
||||
$user->setEmail($this->io->ask('Email', 'wallabag@wallabag.io'));
|
||||
|
||||
$user->setEnabled(true);
|
||||
$user->addRole('ROLE_SUPER_ADMIN');
|
||||
|
|
|
@ -57,7 +57,8 @@ class ShowUserCommand extends ContainerAwareCommand
|
|||
sprintf('Display name: %s', $user->getName()),
|
||||
sprintf('Creation date: %s', $user->getCreatedAt()->format('Y-m-d H:i:s')),
|
||||
sprintf('Last login: %s', null !== $user->getLastLogin() ? $user->getLastLogin()->format('Y-m-d H:i:s') : 'never'),
|
||||
sprintf('2FA activated: %s', $user->isTwoFactorAuthentication() ? 'yes' : 'no'),
|
||||
sprintf('2FA (email) activated: %s', $user->isEmailTwoFactor() ? 'yes' : 'no'),
|
||||
sprintf('2FA (OTP) activated: %s', $user->isGoogleAuthenticatorEnabled() ? 'yes' : 'no'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,19 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use PragmaRX\Recovery\Recovery as BackupCodes;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
use Wallabag\CoreBundle\Entity\TaggingRule;
|
||||
use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
|
||||
use Wallabag\CoreBundle\Form\Type\ConfigType;
|
||||
use Wallabag\CoreBundle\Form\Type\RssType;
|
||||
use Wallabag\CoreBundle\Form\Type\FeedType;
|
||||
use Wallabag\CoreBundle\Form\Type\TaggingRuleType;
|
||||
use Wallabag\CoreBundle\Form\Type\UserInformationType;
|
||||
use Wallabag\CoreBundle\Tools\Utils;
|
||||
|
@ -45,7 +47,7 @@ class ConfigController extends Controller
|
|||
$activeTheme = $this->get('liip_theme.active_theme');
|
||||
$activeTheme->setName($config->getTheme());
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.config_saved'
|
||||
);
|
||||
|
@ -67,7 +69,7 @@ class ConfigController extends Controller
|
|||
$userManager->updateUser($user, true);
|
||||
}
|
||||
|
||||
$this->get('session')->getFlashBag()->add('notice', $message);
|
||||
$this->addFlash('notice', $message);
|
||||
|
||||
return $this->redirect($this->generateUrl('config') . '#set4');
|
||||
}
|
||||
|
@ -82,7 +84,7 @@ class ConfigController extends Controller
|
|||
if ($userForm->isSubmitted() && $userForm->isValid()) {
|
||||
$userManager->updateUser($user, true);
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.user_updated'
|
||||
);
|
||||
|
@ -90,17 +92,17 @@ class ConfigController extends Controller
|
|||
return $this->redirect($this->generateUrl('config') . '#set3');
|
||||
}
|
||||
|
||||
// handle rss information
|
||||
$rssForm = $this->createForm(RssType::class, $config, ['action' => $this->generateUrl('config') . '#set2']);
|
||||
$rssForm->handleRequest($request);
|
||||
// handle feed information
|
||||
$feedForm = $this->createForm(FeedType::class, $config, ['action' => $this->generateUrl('config') . '#set2']);
|
||||
$feedForm->handleRequest($request);
|
||||
|
||||
if ($rssForm->isSubmitted() && $rssForm->isValid()) {
|
||||
if ($feedForm->isSubmitted() && $feedForm->isValid()) {
|
||||
$em->persist($config);
|
||||
$em->flush();
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.rss_updated'
|
||||
'flashes.config.notice.feed_updated'
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('config') . '#set2');
|
||||
|
@ -130,7 +132,7 @@ class ConfigController extends Controller
|
|||
$em->persist($taggingRule);
|
||||
$em->flush();
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.tagging_rules_updated'
|
||||
);
|
||||
|
@ -141,22 +143,134 @@ class ConfigController extends Controller
|
|||
return $this->render('WallabagCoreBundle:Config:index.html.twig', [
|
||||
'form' => [
|
||||
'config' => $configForm->createView(),
|
||||
'rss' => $rssForm->createView(),
|
||||
'feed' => $feedForm->createView(),
|
||||
'pwd' => $pwdForm->createView(),
|
||||
'user' => $userForm->createView(),
|
||||
'new_tagging_rule' => $newTaggingRule->createView(),
|
||||
],
|
||||
'rss' => [
|
||||
'feed' => [
|
||||
'username' => $user->getUsername(),
|
||||
'token' => $config->getRssToken(),
|
||||
'token' => $config->getFeedToken(),
|
||||
],
|
||||
'twofactor_auth' => $this->getParameter('twofactor_auth'),
|
||||
'wallabag_url' => $this->getParameter('domain_name'),
|
||||
'enabled_users' => $this->get('wallabag_user.user_repository')
|
||||
->getSumEnabledUsers(),
|
||||
'enabled_users' => $this->get('wallabag_user.user_repository')->getSumEnabledUsers(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable 2FA using email.
|
||||
*
|
||||
* @Route("/config/otp/email", name="config_otp_email")
|
||||
*/
|
||||
public function otpEmailAction()
|
||||
{
|
||||
if (!$this->getParameter('twofactor_auth')) {
|
||||
return $this->createNotFoundException('two_factor not enabled');
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
|
||||
$user->setGoogleAuthenticatorSecret(null);
|
||||
$user->setBackupCodes(null);
|
||||
$user->setEmailTwoFactor(true);
|
||||
|
||||
$this->container->get('fos_user.user_manager')->updateUser($user, true);
|
||||
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.otp_enabled'
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('config') . '#set3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable 2FA using OTP app, user will need to confirm the generated code from the app.
|
||||
*
|
||||
* @Route("/config/otp/app", name="config_otp_app")
|
||||
*/
|
||||
public function otpAppAction()
|
||||
{
|
||||
if (!$this->getParameter('twofactor_auth')) {
|
||||
return $this->createNotFoundException('two_factor not enabled');
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
$secret = $this->get('scheb_two_factor.security.google_authenticator')->generateSecret();
|
||||
|
||||
$user->setGoogleAuthenticatorSecret($secret);
|
||||
$user->setEmailTwoFactor(false);
|
||||
|
||||
$backupCodes = (new BackupCodes())->toArray();
|
||||
$backupCodesHashed = array_map(
|
||||
function ($backupCode) {
|
||||
return password_hash($backupCode, PASSWORD_DEFAULT);
|
||||
},
|
||||
$backupCodes
|
||||
);
|
||||
|
||||
$user->setBackupCodes($backupCodesHashed);
|
||||
|
||||
$this->container->get('fos_user.user_manager')->updateUser($user, true);
|
||||
|
||||
return $this->render('WallabagCoreBundle:Config:otp_app.html.twig', [
|
||||
'backupCodes' => $backupCodes,
|
||||
'qr_code' => $this->get('scheb_two_factor.security.google_authenticator')->getQRContent($user),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancelling 2FA using OTP app.
|
||||
*
|
||||
* @Route("/config/otp/app/cancel", name="config_otp_app_cancel")
|
||||
*/
|
||||
public function otpAppCancelAction()
|
||||
{
|
||||
if (!$this->getParameter('twofactor_auth')) {
|
||||
return $this->createNotFoundException('two_factor not enabled');
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
$user->setGoogleAuthenticatorSecret(null);
|
||||
$user->setBackupCodes(null);
|
||||
|
||||
$this->container->get('fos_user.user_manager')->updateUser($user, true);
|
||||
|
||||
return $this->redirect($this->generateUrl('config') . '#set3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate OTP code.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @Route("/config/otp/app/check", name="config_otp_app_check")
|
||||
*/
|
||||
public function otpAppCheckAction(Request $request)
|
||||
{
|
||||
$isValid = $this->get('scheb_two_factor.security.google_authenticator')->checkCode(
|
||||
$this->getUser(),
|
||||
$request->get('_auth_code')
|
||||
);
|
||||
|
||||
if (true === $isValid) {
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.otp_enabled'
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('config') . '#set3');
|
||||
}
|
||||
|
||||
$this->addFlash(
|
||||
'two_factor',
|
||||
'scheb_two_factor.code_invalid'
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('config_otp_app'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
|
@ -167,19 +281,19 @@ class ConfigController extends Controller
|
|||
public function generateTokenAction(Request $request)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$config->setRssToken(Utils::generateToken());
|
||||
$config->setFeedToken(Utils::generateToken());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->persist($config);
|
||||
$em->flush();
|
||||
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
return new JsonResponse(['token' => $config->getRssToken()]);
|
||||
return new JsonResponse(['token' => $config->getFeedToken()]);
|
||||
}
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.rss_token_updated'
|
||||
'flashes.config.notice.feed_token_updated'
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('config') . '#set2');
|
||||
|
@ -202,7 +316,7 @@ class ConfigController extends Controller
|
|||
$em->remove($rule);
|
||||
$em->flush();
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.tagging_rules_deleted'
|
||||
);
|
||||
|
@ -268,7 +382,7 @@ class ConfigController extends Controller
|
|||
break;
|
||||
}
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
'flashes.config.notice.' . $type . '_reset'
|
||||
);
|
||||
|
@ -329,6 +443,27 @@ class ConfigController extends Controller
|
|||
return $this->redirect($request->headers->get('referer'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the locale for the current user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $language
|
||||
*
|
||||
* @Route("/locale/{language}", name="changeLocale")
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function setLocaleAction(Request $request, $language = null)
|
||||
{
|
||||
$errors = $this->get('validator')->validate($language, (new LocaleConstraint()));
|
||||
|
||||
if (0 === \count($errors)) {
|
||||
$request->getSession()->set('_locale', $language);
|
||||
}
|
||||
|
||||
return $this->redirect($request->headers->get('referer', $this->generateUrl('homepage')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all tags for given tags and a given user and cleanup orphan tags.
|
||||
*
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Controller;
|
||||
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||
use Pagerfanta\Exception\OutOfRangeCurrentPageException;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Event\EntryDeletedEvent;
|
||||
|
@ -232,6 +233,46 @@ class EntryController extends Controller
|
|||
return $this->showEntries('starred', $request, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows untagged articles for current user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $page
|
||||
*
|
||||
* @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"})
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showUntaggedEntriesAction(Request $request, $page)
|
||||
{
|
||||
return $this->showEntries('untagged', $request, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows random entry depending on the given type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|all"})
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function redirectRandomEntryAction($type = 'all')
|
||||
{
|
||||
try {
|
||||
$entry = $this->get('wallabag_core.entry_repository')
|
||||
->getRandomEntry($this->getUser()->getId(), $type);
|
||||
} catch (NoResultException $e) {
|
||||
$bag = $this->get('session')->getFlashBag();
|
||||
$bag->clear();
|
||||
$bag->add('notice', 'flashes.entry.notice.no_random_entry');
|
||||
|
||||
return $this->redirect($this->generateUrl($type));
|
||||
}
|
||||
|
||||
return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows entry content.
|
||||
*
|
||||
|
@ -465,54 +506,6 @@ class EntryController extends Controller
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows untagged articles for current user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $page
|
||||
*
|
||||
* @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"})
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showUntaggedEntriesAction(Request $request, $page)
|
||||
{
|
||||
return $this->showEntries('untagged', $request, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch content and update entry.
|
||||
* In case it fails, $entry->getContent will return an error message.
|
||||
*
|
||||
* @param Entry $entry
|
||||
* @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded
|
||||
*/
|
||||
private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved')
|
||||
{
|
||||
$message = 'flashes.entry.notice.' . $prefixMessage;
|
||||
|
||||
try {
|
||||
$this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
|
||||
} catch (\Exception $e) {
|
||||
$this->get('logger')->error('Error while saving an entry', [
|
||||
'exception' => $e,
|
||||
'entry' => $entry,
|
||||
]);
|
||||
|
||||
$message = 'flashes.entry.notice.' . $prefixMessage . '_failed';
|
||||
}
|
||||
|
||||
if (empty($entry->getDomainName())) {
|
||||
$this->get('wallabag_core.content_proxy')->setEntryDomainName($entry);
|
||||
}
|
||||
|
||||
if (empty($entry->getTitle())) {
|
||||
$this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry);
|
||||
}
|
||||
|
||||
$this->get('session')->getFlashBag()->add('notice', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global method to retrieve entries depending on the given type
|
||||
* It returns the response to be send.
|
||||
|
@ -532,11 +525,9 @@ class EntryController extends Controller
|
|||
switch ($type) {
|
||||
case 'search':
|
||||
$qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute);
|
||||
|
||||
break;
|
||||
case 'untagged':
|
||||
$qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId());
|
||||
|
||||
break;
|
||||
case 'starred':
|
||||
$qb = $repository->getBuilderForStarredByUser($this->getUser()->getId());
|
||||
|
@ -587,6 +578,39 @@ class EntryController extends Controller
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch content and update entry.
|
||||
* In case it fails, $entry->getContent will return an error message.
|
||||
*
|
||||
* @param Entry $entry
|
||||
* @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded
|
||||
*/
|
||||
private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved')
|
||||
{
|
||||
$message = 'flashes.entry.notice.' . $prefixMessage;
|
||||
|
||||
try {
|
||||
$this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
|
||||
} catch (\Exception $e) {
|
||||
$this->get('logger')->error('Error while saving an entry', [
|
||||
'exception' => $e,
|
||||
'entry' => $entry,
|
||||
]);
|
||||
|
||||
$message = 'flashes.entry.notice.' . $prefixMessage . '_failed';
|
||||
}
|
||||
|
||||
if (empty($entry->getDomainName())) {
|
||||
$this->get('wallabag_core.content_proxy')->setEntryDomainName($entry);
|
||||
}
|
||||
|
||||
if (empty($entry->getTitle())) {
|
||||
$this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry);
|
||||
}
|
||||
|
||||
$this->get('session')->getFlashBag()->add('notice', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the logged user can manage the given entry.
|
||||
*
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,86 +7,97 @@ use Pagerfanta\Adapter\DoctrineORMAdapter;
|
|||
use Pagerfanta\Exception\OutOfRangeCurrentPageException;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
class RssController extends Controller
|
||||
class FeedController extends Controller
|
||||
{
|
||||
/**
|
||||
* Shows unread entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"})
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
* @Route("/feed/{username}/{token}/unread/{page}", name="unread_feed", defaults={"page"=1, "_format"="xml"})
|
||||
*
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter")
|
||||
*
|
||||
* @param User $user
|
||||
* @param $page
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showUnreadRSSAction(Request $request, User $user)
|
||||
public function showUnreadFeedAction(User $user, $page)
|
||||
{
|
||||
return $this->showEntries('unread', $user, $request->query->get('page', 1));
|
||||
return $this->showEntries('unread', $user, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows read entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/archive.xml", name="archive_rss", defaults={"_format"="xml"})
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
* @Route("/feed/{username}/{token}/archive/{page}", name="archive_feed", defaults={"page"=1, "_format"="xml"})
|
||||
*
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter")
|
||||
*
|
||||
* @param User $user
|
||||
* @param $page
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showArchiveRSSAction(Request $request, User $user)
|
||||
public function showArchiveFeedAction(User $user, $page)
|
||||
{
|
||||
return $this->showEntries('archive', $user, $request->query->get('page', 1));
|
||||
return $this->showEntries('archive', $user, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows starred entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/starred.xml", name="starred_rss", defaults={"_format"="xml"})
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
* @Route("/feed/{username}/{token}/starred/{page}", name="starred_feed", defaults={"page"=1, "_format"="xml"})
|
||||
*
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter")
|
||||
*
|
||||
* @param User $user
|
||||
* @param $page
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showStarredRSSAction(Request $request, User $user)
|
||||
public function showStarredFeedAction(User $user, $page)
|
||||
{
|
||||
return $this->showEntries('starred', $user, $request->query->get('page', 1));
|
||||
return $this->showEntries('starred', $user, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows all entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/all.xml", name="all_rss", defaults={"_format"="xml"})
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
* @Route("/feed/{username}/{token}/all/{page}", name="all_feed", defaults={"page"=1, "_format"="xml"})
|
||||
*
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter")
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showAllRSSAction(Request $request, User $user)
|
||||
public function showAllFeedAction(User $user, $page)
|
||||
{
|
||||
return $this->showEntries('all', $user, $request->query->get('page', 1));
|
||||
return $this->showEntries('all', $user, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows entries associated to a tag for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/tags/{slug}.xml", name="tag_rss", defaults={"_format"="xml"})
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
* @Route("/feed/{username}/{token}/tags/{slug}/{page}", name="tag_feed", defaults={"page"=1, "_format"="xml"})
|
||||
*
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter")
|
||||
* @ParamConverter("tag", options={"mapping": {"slug": "slug"}})
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function showTagsAction(Request $request, User $user, Tag $tag)
|
||||
public function showTagsFeedAction(User $user, Tag $tag, $page)
|
||||
{
|
||||
$page = $request->query->get('page', 1);
|
||||
|
||||
$url = $this->generateUrl(
|
||||
'tag_rss',
|
||||
'tag_feed',
|
||||
[
|
||||
'username' => $user->getUsername(),
|
||||
'token' => $user->getConfig()->getRssToken(),
|
||||
'token' => $user->getConfig()->getFeedToken(),
|
||||
'slug' => $tag->getSlug(),
|
||||
],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
|
@ -119,12 +130,15 @@ class RssController extends Controller
|
|||
return $this->render(
|
||||
'@WallabagCore/themes/common/Entry/entries.xml.twig',
|
||||
[
|
||||
'url_html' => $this->generateUrl('tag_entries', ['slug' => $tag->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
'type' => 'tag (' . $tag->getLabel() . ')',
|
||||
'type' => 'tag',
|
||||
'url' => $url,
|
||||
'entries' => $entries,
|
||||
'user' => $user->getUsername(),
|
||||
'domainName' => $this->getParameter('domain_name'),
|
||||
'version' => $this->getParameter('wallabag_core.version'),
|
||||
'tag' => $tag->getSlug(),
|
||||
],
|
||||
new Response('', 200, ['Content-Type' => 'application/rss+xml'])
|
||||
new Response('', 200, ['Content-Type' => 'application/atom+xml'])
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -162,14 +176,14 @@ class RssController extends Controller
|
|||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$perPage = $user->getConfig()->getRssLimit() ?: $this->getParameter('wallabag_core.rss_limit');
|
||||
$perPage = $user->getConfig()->getFeedLimit() ?: $this->getParameter('wallabag_core.Feed_limit');
|
||||
$entries->setMaxPerPage($perPage);
|
||||
|
||||
$url = $this->generateUrl(
|
||||
$type . '_rss',
|
||||
$type . '_feed',
|
||||
[
|
||||
'username' => $user->getUsername(),
|
||||
'token' => $user->getConfig()->getRssToken(),
|
||||
'token' => $user->getConfig()->getFeedToken(),
|
||||
],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
);
|
||||
|
@ -178,19 +192,19 @@ class RssController extends Controller
|
|||
$entries->setCurrentPage((int) $page);
|
||||
} catch (OutOfRangeCurrentPageException $e) {
|
||||
if ($page > 1) {
|
||||
return $this->redirect($url . '?page=' . $entries->getNbPages(), 302);
|
||||
return $this->redirect($url . '/' . $entries->getNbPages());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'@WallabagCore/themes/common/Entry/entries.xml.twig',
|
||||
[
|
||||
'url_html' => $this->generateUrl($type, [], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
'type' => $type,
|
||||
'url' => $url,
|
||||
'entries' => $entries,
|
||||
],
|
||||
new Response('', 200, ['Content-Type' => 'application/rss+xml'])
|
||||
return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [
|
||||
'type' => $type,
|
||||
'url' => $url,
|
||||
'entries' => $entries,
|
||||
'user' => $user->getUsername(),
|
||||
'domainName' => $this->getParameter('domain_name'),
|
||||
'version' => $this->getParameter('wallabag_core.version'),
|
||||
],
|
||||
new Response('', 200, ['Content-Type' => 'application/atom+xml'])
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Entity\SiteCredential;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
|
@ -19,8 +18,7 @@ class SiteCredentialController extends Controller
|
|||
/**
|
||||
* Lists all User entities.
|
||||
*
|
||||
* @Route("/", name="site_credentials_index")
|
||||
* @Method("GET")
|
||||
* @Route("/", name="site_credentials_index", methods={"GET"})
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
|
@ -36,8 +34,7 @@ class SiteCredentialController extends Controller
|
|||
/**
|
||||
* Creates a new site credential entity.
|
||||
*
|
||||
* @Route("/new", name="site_credentials_new")
|
||||
* @Method({"GET", "POST"})
|
||||
* @Route("/new", name="site_credentials_new", methods={"GET", "POST"})
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
|
@ -77,8 +74,7 @@ class SiteCredentialController extends Controller
|
|||
/**
|
||||
* Displays a form to edit an existing site credential entity.
|
||||
*
|
||||
* @Route("/{id}/edit", name="site_credentials_edit")
|
||||
* @Method({"GET", "POST"})
|
||||
* @Route("/{id}/edit", name="site_credentials_edit", methods={"GET", "POST"})
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SiteCredential $siteCredential
|
||||
|
@ -121,8 +117,7 @@ class SiteCredentialController extends Controller
|
|||
/**
|
||||
* Deletes a site credential entity.
|
||||
*
|
||||
* @Route("/{id}", name="site_credentials_delete")
|
||||
* @Method("DELETE")
|
||||
* @Route("/{id}", name="site_credentials_delete", methods={"DELETE"})
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SiteCredential $siteCredential
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class StaticController extends Controller
|
||||
{
|
||||
|
|
|
@ -5,12 +5,13 @@ namespace Wallabag\CoreBundle\Controller;
|
|||
use Pagerfanta\Adapter\ArrayAdapter;
|
||||
use Pagerfanta\Exception\OutOfRangeCurrentPageException;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
use Wallabag\CoreBundle\Form\Type\NewTagType;
|
||||
use Wallabag\CoreBundle\Form\Type\RenameTagType;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
|
@ -87,8 +88,14 @@ class TagController extends Controller
|
|||
$tags = $this->get('wallabag_core.tag_repository')
|
||||
->findAllFlatTagsWithNbEntries($this->getUser()->getId());
|
||||
|
||||
$renameForms = [];
|
||||
foreach ($tags as $tag) {
|
||||
$renameForms[$tag['id']] = $this->createForm(RenameTagType::class, new Tag())->createView();
|
||||
}
|
||||
|
||||
return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [
|
||||
'tags' => $tags,
|
||||
'renameForms' => $renameForms,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -130,4 +137,48 @@ class TagController extends Controller
|
|||
'tag' => $tag,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a given tag with a new label
|
||||
* Create a new tag with the new name and drop the old one.
|
||||
*
|
||||
* @param Tag $tag
|
||||
* @param Request $request
|
||||
*
|
||||
* @Route("/tag/rename/{slug}", name="tag_rename")
|
||||
* @ParamConverter("tag", options={"mapping": {"slug": "slug"}})
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function renameTagAction(Tag $tag, Request $request)
|
||||
{
|
||||
$form = $this->createForm(RenameTagType::class, new Tag());
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$entries = $this->get('wallabag_core.entry_repository')->findAllByTagId(
|
||||
$this->getUser()->getId(),
|
||||
$tag->getId()
|
||||
);
|
||||
foreach ($entries as $entry) {
|
||||
$this->get('wallabag_core.tags_assigner')->assignTagsToEntry(
|
||||
$entry,
|
||||
$form->get('label')->getData()
|
||||
);
|
||||
$entry->removeTag($tag);
|
||||
}
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
'flashes.tag.notice.tag_renamed'
|
||||
);
|
||||
|
||||
$redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'), '', true);
|
||||
|
||||
return $this->redirect($redirectUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\CoreBundle\DataFixtures;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
use Wallabag\UserBundle\DataFixtures\UserFixtures;
|
||||
|
||||
class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
|
||||
class ConfigFixtures extends Fixture implements DependentFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -60,8 +61,10 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
public function getDependencies()
|
||||
{
|
||||
return 20;
|
||||
return [
|
||||
UserFixtures::class,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\CoreBundle\DataFixtures;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\UserBundle\DataFixtures\UserFixtures;
|
||||
|
||||
class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
||||
class EntryFixtures extends Fixture implements DependentFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -127,8 +128,11 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
public function getDependencies()
|
||||
{
|
||||
return 30;
|
||||
return [
|
||||
UserFixtures::class,
|
||||
TagFixtures::class,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,15 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\CoreBundle\DataFixtures;
|
||||
|
||||
use Craue\ConfigBundle\Entity\Setting;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
|
||||
class SettingFixtures extends Fixture implements ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
|
@ -36,12 +35,4 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
|
|||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 29;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\CoreBundle\DataFixtures;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Wallabag\CoreBundle\Entity\SiteCredential;
|
||||
use Wallabag\UserBundle\DataFixtures\UserFixtures;
|
||||
|
||||
class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
|
||||
class SiteCredentialFixtures extends Fixture implements DependentFixtureInterface, ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
|
@ -46,8 +47,10 @@ class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureIn
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
public function getDependencies()
|
||||
{
|
||||
return 50;
|
||||
return [
|
||||
UserFixtures::class,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\CoreBundle\DataFixtures;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
|
||||
class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
|
||||
class TagFixtures extends Fixture
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -33,12 +32,4 @@ class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
|
|||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 25;
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\CoreBundle\DataFixtures;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\TaggingRule;
|
||||
|
||||
class LoadTaggingRuleData extends AbstractFixture implements OrderedFixtureInterface
|
||||
class TaggingRuleFixtures extends Fixture implements DependentFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -49,8 +49,10 @@ class LoadTaggingRuleData extends AbstractFixture implements OrderedFixtureInter
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
public function getDependencies()
|
||||
{
|
||||
return 40;
|
||||
return [
|
||||
ConfigFixtures::class,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ class WallabagCoreExtension extends Extension
|
|||
$container->setParameter('wallabag_core.items_on_page', $config['items_on_page']);
|
||||
$container->setParameter('wallabag_core.theme', $config['theme']);
|
||||
$container->setParameter('wallabag_core.language', $config['language']);
|
||||
$container->setParameter('wallabag_core.rss_limit', $config['rss_limit']);
|
||||
$container->setParameter('wallabag_core.feed_limit', $config['rss_limit']);
|
||||
$container->setParameter('wallabag_core.reading_speed', $config['reading_speed']);
|
||||
$container->setParameter('wallabag_core.version', $config['version']);
|
||||
$container->setParameter('wallabag_core.paypal_url', $config['paypal_url']);
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\PDOPgSql\Driver;
|
||||
use Wallabag\CoreBundle\Doctrine\DBAL\Schema\CustomPostgreSqlSchemaManager;
|
||||
|
||||
/**
|
||||
* This custom driver allow to use a different schema manager
|
||||
* So we can fix the PostgreSQL 10 problem.
|
||||
*
|
||||
* @see https://github.com/wallabag/wallabag/issues/3479
|
||||
* @see https://github.com/doctrine/dbal/issues/2868
|
||||
*/
|
||||
class CustomPostgreSQLDriver extends Driver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSchemaManager(Connection $conn)
|
||||
{
|
||||
return new CustomPostgreSqlSchemaManager($conn);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Doctrine\DBAL\Schema;
|
||||
|
||||
use Doctrine\DBAL\Schema\PostgreSqlSchemaManager;
|
||||
use Doctrine\DBAL\Schema\Sequence;
|
||||
|
||||
/**
|
||||
* This custom schema manager fix the PostgreSQL 10 problem.
|
||||
*
|
||||
* @see https://github.com/wallabag/wallabag/issues/3479
|
||||
* @see https://github.com/doctrine/dbal/issues/2868
|
||||
*/
|
||||
class CustomPostgreSqlSchemaManager extends PostgreSqlSchemaManager
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function _getPortableSequenceDefinition($sequence)
|
||||
{
|
||||
$sequenceName = $sequence['relname'];
|
||||
if ('public' !== $sequence['schemaname']) {
|
||||
$sequenceName = $sequence['schemaname'] . '.' . $sequence['relname'];
|
||||
}
|
||||
|
||||
$query = 'SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName);
|
||||
|
||||
// the `method_exists` is only to avoid test to fail:
|
||||
// DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticConnection doesn't support the `getServerVersion`
|
||||
if (method_exists($this->_conn->getWrappedConnection(), 'getServerVersion') && (float) ($this->_conn->getWrappedConnection()->getServerVersion()) >= 10) {
|
||||
$query = "SELECT min_value, increment_by FROM pg_sequences WHERE schemaname = 'public' AND sequencename = " . $this->_conn->quote($sequenceName);
|
||||
}
|
||||
|
||||
$data = $this->_conn->fetchAll($query);
|
||||
|
||||
return new Sequence($sequenceName, $data[0]['increment_by'], $data[0]['min_value']);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Doctrine;
|
||||
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
|
|
|
@ -60,21 +60,21 @@ class Config
|
|||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="rss_token", type="string", nullable=true)
|
||||
* @ORM\Column(name="feed_token", type="string", nullable=true)
|
||||
*/
|
||||
private $rssToken;
|
||||
private $feedToken;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(name="rss_limit", type="integer", nullable=true)
|
||||
* @ORM\Column(name="feed_limit", type="integer", nullable=true)
|
||||
* @Assert\Range(
|
||||
* min = 1,
|
||||
* max = 100000,
|
||||
* maxMessage = "validator.rss_limit_too_high"
|
||||
* maxMessage = "validator.feed_limit_too_high"
|
||||
* )
|
||||
*/
|
||||
private $rssLimit;
|
||||
private $feedLimit;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
|
@ -231,51 +231,51 @@ class Config
|
|||
}
|
||||
|
||||
/**
|
||||
* Set rssToken.
|
||||
* Set feed Token.
|
||||
*
|
||||
* @param string $rssToken
|
||||
* @param string $feedToken
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function setRssToken($rssToken)
|
||||
public function setFeedToken($feedToken)
|
||||
{
|
||||
$this->rssToken = $rssToken;
|
||||
$this->feedToken = $feedToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rssToken.
|
||||
* Get feedToken.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRssToken()
|
||||
public function getFeedToken()
|
||||
{
|
||||
return $this->rssToken;
|
||||
return $this->feedToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rssLimit.
|
||||
* Set Feed Limit.
|
||||
*
|
||||
* @param int $rssLimit
|
||||
* @param int $feedLimit
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function setRssLimit($rssLimit)
|
||||
public function setFeedLimit($feedLimit)
|
||||
{
|
||||
$this->rssLimit = $rssLimit;
|
||||
$this->feedLimit = $feedLimit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rssLimit.
|
||||
* Get Feed Limit.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRssLimit()
|
||||
public function getFeedLimit()
|
||||
{
|
||||
return $this->rssLimit;
|
||||
return $this->feedLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,6 +13,7 @@ use JMS\Serializer\Annotation\XmlRoot;
|
|||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Wallabag\AnnotationBundle\Entity\Annotation;
|
||||
use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
|
||||
use Wallabag\CoreBundle\Helper\UrlHasher;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +26,8 @@ use Wallabag\UserBundle\Entity\User;
|
|||
* options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"},
|
||||
* indexes={
|
||||
* @ORM\Index(name="created_at", columns={"created_at"}),
|
||||
* @ORM\Index(name="uid", columns={"uid"})
|
||||
* @ORM\Index(name="uid", columns={"uid"}),
|
||||
* @ORM\Index(name="hashed_url_user_id", columns={"user_id", "hashed_url"}, options={"lengths"={null, 40}})
|
||||
* }
|
||||
* )
|
||||
* @ORM\HasLifecycleCallbacks()
|
||||
|
@ -75,6 +77,13 @@ class Entry
|
|||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="hashed_url", type="string", length=40, nullable=true)
|
||||
*/
|
||||
private $hashedUrl;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*
|
||||
|
@ -86,6 +95,15 @@ class Entry
|
|||
*/
|
||||
private $isArchived = false;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*
|
||||
* @ORM\Column(name="archived_at", type="datetime", nullable=true)
|
||||
*
|
||||
* @Groups({"entries_for_user", "export_all"})
|
||||
*/
|
||||
private $archivedAt = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*
|
||||
|
@ -307,6 +325,7 @@ class Entry
|
|||
public function setUrl($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->hashedUrl = UrlHasher::hashUrl($url);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -335,6 +354,44 @@ class Entry
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* update isArchived and archive_at fields.
|
||||
*
|
||||
* @param bool $isArchived
|
||||
*
|
||||
* @return Entry
|
||||
*/
|
||||
public function updateArchived($isArchived = false)
|
||||
{
|
||||
$this->setArchived($isArchived);
|
||||
$this->setArchivedAt(null);
|
||||
if ($this->isArchived()) {
|
||||
$this->setArchivedAt(new \DateTime());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTime|null
|
||||
*/
|
||||
public function getArchivedAt()
|
||||
{
|
||||
return $this->archivedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime|null $archivedAt
|
||||
*
|
||||
* @return Entry
|
||||
*/
|
||||
public function setArchivedAt($archivedAt = null)
|
||||
{
|
||||
$this->archivedAt = $archivedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get isArchived.
|
||||
*
|
||||
|
@ -357,7 +414,7 @@ class Entry
|
|||
|
||||
public function toggleArchive()
|
||||
{
|
||||
$this->isArchived = $this->isArchived() ^ 1;
|
||||
$this->updateArchived($this->isArchived() ^ 1);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -864,4 +921,24 @@ class Entry
|
|||
{
|
||||
return $this->originUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHashedUrl()
|
||||
{
|
||||
return $this->hashedUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $hashedUrl
|
||||
*
|
||||
* @return Entry
|
||||
*/
|
||||
public function setHashedUrl($hashedUrl)
|
||||
{
|
||||
$this->hashedUrl = $hashedUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,13 @@ class SiteCredential
|
|||
*/
|
||||
private $createdAt;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*
|
||||
* @ORM\Column(name="updated_at", type="datetime")
|
||||
*/
|
||||
private $updatedAt;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="siteCredentials")
|
||||
*/
|
||||
|
@ -178,6 +185,16 @@ class SiteCredential
|
|||
return $this->createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get updatedAt.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getUpdatedAt()
|
||||
{
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Wallabag\CoreBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use KPhoen\RulerZBundle\Validator\Constraints as RulerZAssert;
|
||||
use Symfony\Bridge\RulerZ\Validator\Constraints as RulerZAssert;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,8 +6,10 @@ use Symfony\Component\HttpFoundation\Session\Session;
|
|||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
|
||||
/**
|
||||
* Stores the locale of the user in the session after the
|
||||
* login. This can be used by the LocaleListener afterwards.
|
||||
* Stores the locale of the user in the session after the login.
|
||||
* If no locale are defined (if user doesn't change it from the login screen), override it with the user's config one.
|
||||
*
|
||||
* This can be used by the LocaleListener afterwards.
|
||||
*
|
||||
* @see http://symfony.com/doc/master/cookbook/session/locale_sticky_session.html
|
||||
*/
|
||||
|
@ -30,7 +32,7 @@ class UserLocaleListener
|
|||
{
|
||||
$user = $event->getAuthenticationToken()->getUser();
|
||||
|
||||
if (null !== $user->getConfig()->getLanguage()) {
|
||||
if (null !== $user->getConfig()->getLanguage() && null === $this->session->get('_locale')) {
|
||||
$this->session->set('_locale', $user->getConfig()->getLanguage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,13 @@ class EditEntryType extends AbstractType
|
|||
'disabled' => true,
|
||||
'required' => false,
|
||||
'label' => 'entry.edit.url_label',
|
||||
'default_protocol' => null,
|
||||
])
|
||||
->add('origin_url', UrlType::class, [
|
||||
'required' => false,
|
||||
'property_path' => 'originUrl',
|
||||
'label' => 'entry.edit.origin_url_label',
|
||||
'default_protocol' => null,
|
||||
])
|
||||
->add('save', SubmitType::class, [
|
||||
'label' => 'entry.edit.save_label',
|
||||
|
|
|
@ -7,14 +7,14 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class RssType extends AbstractType
|
||||
class FeedType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('rss_limit', null, [
|
||||
'label' => 'config.form_rss.rss_limit',
|
||||
'property_path' => 'rssLimit',
|
||||
->add('feed_limit', null, [
|
||||
'label' => 'config.form_feed.feed_limit',
|
||||
'property_path' => 'feedLimit',
|
||||
])
|
||||
->add('save', SubmitType::class, [
|
||||
'label' => 'config.form.save',
|
||||
|
@ -31,6 +31,6 @@ class RssType extends AbstractType
|
|||
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'rss_config';
|
||||
return 'feed_config';
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ class NewEntryType extends AbstractType
|
|||
->add('url', UrlType::class, [
|
||||
'required' => true,
|
||||
'label' => 'entry.new.form_new.url_label',
|
||||
'default_protocol' => null,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
|
35
src/Wallabag/CoreBundle/Form/Type/RenameTagType.php
Normal file
35
src/Wallabag/CoreBundle/Form/Type/RenameTagType.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class RenameTagType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('label', TextType::class, [
|
||||
'required' => true,
|
||||
'attr' => [
|
||||
'placeholder' => 'tag.rename.placeholder',
|
||||
],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => 'Wallabag\CoreBundle\Entity\Tag',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'tag';
|
||||
}
|
||||
}
|
|
@ -21,9 +21,14 @@ class UserInformationType extends AbstractType
|
|||
->add('email', EmailType::class, [
|
||||
'label' => 'config.form_user.email_label',
|
||||
])
|
||||
->add('twoFactorAuthentication', CheckboxType::class, [
|
||||
->add('emailTwoFactor', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'config.form_user.twoFactorAuthentication_label',
|
||||
'label' => 'config.form_user.emailTwoFactor_label',
|
||||
])
|
||||
->add('googleTwoFactor', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'config.form_user.googleTwoFactor_label',
|
||||
'mapped' => false,
|
||||
])
|
||||
->add('save', SubmitType::class, [
|
||||
'label' => 'config.form.save',
|
||||
|
|
|
@ -12,8 +12,8 @@ use Wallabag\CoreBundle\Entity\Entry;
|
|||
use Wallabag\CoreBundle\Tools\Utils;
|
||||
|
||||
/**
|
||||
* This kind of proxy class take care of getting the content from an url
|
||||
* and update the entry with what it found.
|
||||
* This kind of proxy class takes care of getting the content from an url
|
||||
* and updates the entry with what it found.
|
||||
*/
|
||||
class ContentProxy
|
||||
{
|
||||
|
@ -54,7 +54,11 @@ class ContentProxy
|
|||
|
||||
if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) {
|
||||
$fetchedContent = $this->graby->fetchContent($url);
|
||||
$fetchedContent['title'] = $this->sanitizeContentTitle($fetchedContent['title'], $fetchedContent['content_type']);
|
||||
|
||||
$fetchedContent['title'] = $this->sanitizeContentTitle(
|
||||
$fetchedContent['title'],
|
||||
isset($fetchedContent['headers']['content-type']) ? $fetchedContent['headers']['content-type'] : ''
|
||||
);
|
||||
|
||||
// when content is imported, we have information in $content
|
||||
// in case fetching content goes bad, we'll keep the imported information instead of overriding them
|
||||
|
@ -188,8 +192,8 @@ class ContentProxy
|
|||
/**
|
||||
* Try to sanitize the title of the fetched content from wrong character encodings and invalid UTF-8 character.
|
||||
*
|
||||
* @param $title
|
||||
* @param $contentType
|
||||
* @param string $title
|
||||
* @param string $contentType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -253,16 +257,14 @@ class ContentProxy
|
|||
|
||||
if (!empty($content['title'])) {
|
||||
$entry->setTitle($content['title']);
|
||||
} elseif (!empty($content['open_graph']['og_title'])) {
|
||||
$entry->setTitle($content['open_graph']['og_title']);
|
||||
}
|
||||
|
||||
if (empty($content['html'])) {
|
||||
$content['html'] = $this->fetchingErrorMessage;
|
||||
|
||||
if (!empty($content['open_graph']['og_description'])) {
|
||||
if (!empty($content['description'])) {
|
||||
$content['html'] .= '<p><i>But we found a short description: </i></p>';
|
||||
$content['html'] .= $content['open_graph']['og_description'];
|
||||
$content['html'] .= $content['description'];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,8 +279,8 @@ class ContentProxy
|
|||
$entry->setPublishedBy($content['authors']);
|
||||
}
|
||||
|
||||
if (!empty($content['all_headers']) && $this->storeArticleHeaders) {
|
||||
$entry->setHeaders($content['all_headers']);
|
||||
if (!empty($content['headers'])) {
|
||||
$entry->setHeaders($content['headers']);
|
||||
}
|
||||
|
||||
if (!empty($content['date'])) {
|
||||
|
@ -289,17 +291,30 @@ class ContentProxy
|
|||
$this->updateLanguage($entry, $content['language']);
|
||||
}
|
||||
|
||||
if (!empty($content['open_graph']['og_image'])) {
|
||||
$this->updatePreviewPicture($entry, $content['open_graph']['og_image']);
|
||||
$previewPictureUrl = '';
|
||||
if (!empty($content['image'])) {
|
||||
$previewPictureUrl = $content['image'];
|
||||
}
|
||||
|
||||
// if content is an image, define it as a preview too
|
||||
if (!empty($content['content_type']) && \in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) {
|
||||
$this->updatePreviewPicture($entry, $content['url']);
|
||||
if (!empty($content['headers']['content-type']) && \in_array($this->mimeGuesser->guess($content['headers']['content-type']), ['jpeg', 'jpg', 'gif', 'png'], true)) {
|
||||
$previewPictureUrl = $content['url'];
|
||||
} elseif (empty($previewPictureUrl)) {
|
||||
$this->logger->debug('Extracting images from content to provide a default preview picture');
|
||||
$imagesUrls = DownloadImages::extractImagesUrlsFromHtml($content['html']);
|
||||
$this->logger->debug(\count($imagesUrls) . ' pictures found');
|
||||
|
||||
if (!empty($imagesUrls)) {
|
||||
$previewPictureUrl = $imagesUrls[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($content['content_type'])) {
|
||||
$entry->setMimetype($content['content_type']);
|
||||
if (!empty($content['headers']['content-type'])) {
|
||||
$entry->setMimetype($content['headers']['content-type']);
|
||||
}
|
||||
|
||||
if (!empty($previewPictureUrl)) {
|
||||
$this->updatePreviewPicture($entry, $previewPictureUrl);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -2,8 +2,13 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Helper;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Message\Response;
|
||||
use Http\Client\Common\HttpMethodsClient;
|
||||
use Http\Client\Common\Plugin\ErrorPlugin;
|
||||
use Http\Client\Common\PluginClient;
|
||||
use Http\Client\HttpClient;
|
||||
use Http\Discovery\MessageFactoryDiscovery;
|
||||
use Http\Message\MessageFactory;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
@ -19,9 +24,9 @@ class DownloadImages
|
|||
private $mimeGuesser;
|
||||
private $wallabagUrl;
|
||||
|
||||
public function __construct(Client $client, $baseFolder, $wallabagUrl, LoggerInterface $logger)
|
||||
public function __construct(HttpClient $client, $baseFolder, $wallabagUrl, LoggerInterface $logger, MessageFactory $messageFactory = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->client = new HttpMethodsClient(new PluginClient($client, [new ErrorPlugin()]), $messageFactory ?: MessageFactoryDiscovery::find());
|
||||
$this->baseFolder = $baseFolder;
|
||||
$this->wallabagUrl = rtrim($wallabagUrl, '/');
|
||||
$this->logger = $logger;
|
||||
|
@ -30,6 +35,25 @@ class DownloadImages
|
|||
$this->setFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the html and extract images URLs from it.
|
||||
*
|
||||
* @param string $html
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function extractImagesUrlsFromHtml($html)
|
||||
{
|
||||
$crawler = new Crawler($html);
|
||||
$imagesCrawler = $crawler
|
||||
->filterXpath('//img');
|
||||
$imagesUrls = $imagesCrawler
|
||||
->extract(['src']);
|
||||
$imagesSrcsetUrls = self::getSrcsetUrls($imagesCrawler);
|
||||
|
||||
return array_unique(array_merge($imagesUrls, $imagesSrcsetUrls));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the html and extract image from it, save them to local and return the updated html.
|
||||
*
|
||||
|
@ -41,13 +65,7 @@ class DownloadImages
|
|||
*/
|
||||
public function processHtml($entryId, $html, $url)
|
||||
{
|
||||
$crawler = new Crawler($html);
|
||||
$imagesCrawler = $crawler
|
||||
->filterXpath('//img');
|
||||
$imagesUrls = $imagesCrawler
|
||||
->extract(['src']);
|
||||
$imagesSrcsetUrls = $this->getSrcsetUrls($imagesCrawler);
|
||||
$imagesUrls = array_unique(array_merge($imagesUrls, $imagesSrcsetUrls));
|
||||
$imagesUrls = self::extractImagesUrlsFromHtml($html);
|
||||
|
||||
$relativePath = $this->getRelativePath($entryId);
|
||||
|
||||
|
@ -122,7 +140,7 @@ class DownloadImages
|
|||
$localPath = $folderPath . '/' . $hashImage . '.' . $ext;
|
||||
|
||||
try {
|
||||
$im = imagecreatefromstring($res->getBody());
|
||||
$im = imagecreatefromstring((string) $res->getBody());
|
||||
} catch (\Exception $e) {
|
||||
$im = false;
|
||||
}
|
||||
|
@ -135,7 +153,21 @@ class DownloadImages
|
|||
|
||||
switch ($ext) {
|
||||
case 'gif':
|
||||
imagegif($im, $localPath);
|
||||
// use Imagick if available to keep GIF animation
|
||||
if (class_exists('\\Imagick')) {
|
||||
try {
|
||||
$imagick = new \Imagick();
|
||||
$imagick->readImageBlob($res->getBody());
|
||||
$imagick->setImageFormat('gif');
|
||||
$imagick->writeImages($localPath, true);
|
||||
} catch (\Exception $e) {
|
||||
// if Imagick fail, fallback to the default solution
|
||||
imagegif($im, $localPath);
|
||||
}
|
||||
} else {
|
||||
imagegif($im, $localPath);
|
||||
}
|
||||
|
||||
$this->logger->debug('DownloadImages: Re-creating gif');
|
||||
break;
|
||||
case 'jpeg':
|
||||
|
@ -185,7 +217,7 @@ class DownloadImages
|
|||
*
|
||||
* @return array An array of urls
|
||||
*/
|
||||
private function getSrcsetUrls(Crawler $imagesCrawler)
|
||||
private static function getSrcsetUrls(Crawler $imagesCrawler)
|
||||
{
|
||||
$urls = [];
|
||||
$iterator = $imagesCrawler
|
||||
|
@ -279,14 +311,14 @@ class DownloadImages
|
|||
/**
|
||||
* Retrieve and validate the extension from the response of the url of the image.
|
||||
*
|
||||
* @param Response $res Guzzle Response
|
||||
* @param string $imagePath Path from the src image from the content (used for log only)
|
||||
* @param ResponseInterface $res Http Response
|
||||
* @param string $imagePath Path from the src image from the content (used for log only)
|
||||
*
|
||||
* @return string|false Extension name or false if validation failed
|
||||
*/
|
||||
private function getExtensionFromResponse(Response $res, $imagePath)
|
||||
private function getExtensionFromResponse(ResponseInterface $res, $imagePath)
|
||||
{
|
||||
$ext = $this->mimeGuesser->guess($res->getHeader('content-type'));
|
||||
$ext = $this->mimeGuesser->guess(current($res->getHeader('content-type')));
|
||||
$this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]);
|
||||
|
||||
// ok header doesn't have the extension, try a different way
|
||||
|
|
|
@ -2,16 +2,18 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Helper;
|
||||
|
||||
use Graby\Ring\Client\SafeCurlHandler;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Event\SubscriberInterface;
|
||||
use Http\Adapter\Guzzle5\Client as GuzzleAdapter;
|
||||
use Http\Client\HttpClient;
|
||||
use Http\HttplugBundle\ClientFactory\ClientFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Builds and configures the Guzzle HTTP client.
|
||||
* Builds and configures the HTTP client.
|
||||
*/
|
||||
class HttpClientFactory
|
||||
class HttpClientFactory implements ClientFactory
|
||||
{
|
||||
/** @var [\GuzzleHttp\Event\SubscriberInterface] */
|
||||
private $subscribers = [];
|
||||
|
@ -36,29 +38,6 @@ class HttpClientFactory
|
|||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \GuzzleHttp\Client|null
|
||||
*/
|
||||
public function buildHttpClient()
|
||||
{
|
||||
$this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]);
|
||||
|
||||
if (0 === (int) $this->restrictedAccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we clear the cookie to avoid websites who use cookies for analytics
|
||||
$this->cookieJar->clear();
|
||||
// need to set the (shared) cookie jar
|
||||
$client = new Client(['handler' => new SafeCurlHandler(), 'defaults' => ['cookies' => $this->cookieJar]]);
|
||||
|
||||
foreach ($this->subscribers as $subscriber) {
|
||||
$client->getEmitter()->attach($subscriber);
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subscriber to the HTTP client.
|
||||
*
|
||||
|
@ -68,4 +47,34 @@ class HttpClientFactory
|
|||
{
|
||||
$this->subscribers[] = $subscriber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input an array of configuration to be able to create a HttpClient.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return HttpClient
|
||||
*/
|
||||
public function createClient(array $config = [])
|
||||
{
|
||||
$this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]);
|
||||
|
||||
if (0 === (int) $this->restrictedAccess) {
|
||||
return new GuzzleAdapter(new GuzzleClient($config));
|
||||
}
|
||||
|
||||
// we clear the cookie to avoid websites who use cookies for analytics
|
||||
$this->cookieJar->clear();
|
||||
if (!isset($config['defaults']['cookies'])) {
|
||||
// need to set the (shared) cookie jar
|
||||
$config['defaults']['cookies'] = $this->cookieJar;
|
||||
}
|
||||
|
||||
$guzzle = new GuzzleClient($config);
|
||||
foreach ($this->subscribers as $subscriber) {
|
||||
$guzzle->getEmitter()->attach($subscriber);
|
||||
}
|
||||
|
||||
return new GuzzleAdapter($guzzle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class PreparePagerForEntries
|
|||
|
||||
/**
|
||||
* @param AdapterInterface $adapter
|
||||
* @param User $user If user isn't logged in, we can force it (like for rss)
|
||||
* @param User $user If user isn't logged in, we can force it (like for feed)
|
||||
*
|
||||
* @return Pagerfanta|null
|
||||
*/
|
||||
|
|
|
@ -6,6 +6,7 @@ use Psr\Log\LoggerInterface;
|
|||
use RulerZ\RulerZ;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
use Wallabag\CoreBundle\Entity\TaggingRule;
|
||||
use Wallabag\CoreBundle\Repository\EntryRepository;
|
||||
use Wallabag\CoreBundle\Repository\TagRepository;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
|
23
src/Wallabag/CoreBundle/Helper/UrlHasher.php
Normal file
23
src/Wallabag/CoreBundle/Helper/UrlHasher.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Helper;
|
||||
|
||||
/**
|
||||
* Hash URLs for privacy and performance.
|
||||
*/
|
||||
class UrlHasher
|
||||
{
|
||||
/**
|
||||
* Hash the given url using the given algorithm.
|
||||
* Hashed url are faster to be retrieved in the database than the real url.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $algorithm
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function hashUrl(string $url, $algorithm = 'sha1')
|
||||
{
|
||||
return hash($algorithm, urldecode($url));
|
||||
}
|
||||
}
|
|
@ -10,12 +10,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
/**
|
||||
* ParamConverter used in the RSS controller to retrieve the right user according to
|
||||
* ParamConverter used in the Feed controller to retrieve the right user according to
|
||||
* username & token given in the url.
|
||||
*
|
||||
* @see http://stfalcon.com/en/blog/post/symfony2-custom-paramconverter
|
||||
*/
|
||||
class UsernameRssTokenConverter implements ParamConverterInterface
|
||||
class UsernameFeedTokenConverter implements ParamConverterInterface
|
||||
{
|
||||
private $registry;
|
||||
|
||||
|
@ -67,7 +67,7 @@ class UsernameRssTokenConverter implements ParamConverterInterface
|
|||
public function apply(Request $request, ParamConverter $configuration)
|
||||
{
|
||||
$username = $request->attributes->get('username');
|
||||
$rssToken = $request->attributes->get('token');
|
||||
$feedToken = $request->attributes->get('token');
|
||||
|
||||
if (!$request->attributes->has('username') || !$request->attributes->has('token')) {
|
||||
return false;
|
||||
|
@ -78,8 +78,8 @@ class UsernameRssTokenConverter implements ParamConverterInterface
|
|||
|
||||
$userRepository = $em->getRepository($configuration->getClass());
|
||||
|
||||
// Try to find user by its username and config rss_token
|
||||
$user = $userRepository->findOneByUsernameAndRsstoken($username, $rssToken);
|
||||
// Try to find user by its username and config feed_token
|
||||
$user = $userRepository->findOneByUsernameAndFeedtoken($username, $feedToken);
|
||||
|
||||
if (null === $user || !($user instanceof User)) {
|
||||
throw new NotFoundHttpException(sprintf('%s not found.', $configuration->getClass()));
|
|
@ -3,11 +3,13 @@
|
|||
namespace Wallabag\CoreBundle\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
use Wallabag\CoreBundle\Helper\UrlHasher;
|
||||
|
||||
class EntryRepository extends EntityRepository
|
||||
{
|
||||
|
@ -50,7 +52,7 @@ class EntryRepository extends EntityRepository
|
|||
public function getBuilderForArchiveByUser($userId)
|
||||
{
|
||||
return $this
|
||||
->getSortedQueryBuilderByUser($userId)
|
||||
->getSortedQueryBuilderByUser($userId, 'archivedAt', 'desc')
|
||||
->andWhere('e.isArchived = true')
|
||||
;
|
||||
}
|
||||
|
@ -110,8 +112,7 @@ class EntryRepository extends EntityRepository
|
|||
*/
|
||||
public function getBuilderForUntaggedByUser($userId)
|
||||
{
|
||||
return $this
|
||||
->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId));
|
||||
return $this->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,15 +140,30 @@ class EntryRepository extends EntityRepository
|
|||
* @param string $order
|
||||
* @param int $since
|
||||
* @param string $tags
|
||||
* @param string $detail 'metadata' or 'full'. Include content field if 'full'
|
||||
*
|
||||
* @todo Breaking change: replace default detail=full by detail=metadata in a future version
|
||||
*
|
||||
* @return Pagerfanta
|
||||
*/
|
||||
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '')
|
||||
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '', $detail = 'full')
|
||||
{
|
||||
if (!\in_array(strtolower($detail), ['full', 'metadata'], true)) {
|
||||
throw new \Exception('Detail "' . $detail . '" parameter is wrong, allowed: full or metadata');
|
||||
}
|
||||
|
||||
$qb = $this->createQueryBuilder('e')
|
||||
->leftJoin('e.tags', 't')
|
||||
->where('e.user = :userId')->setParameter('userId', $userId);
|
||||
|
||||
if ('metadata' === $detail) {
|
||||
$fieldNames = $this->getClassMetadata()->getFieldNames();
|
||||
$fields = array_filter($fieldNames, function ($k) {
|
||||
return 'content' !== $k;
|
||||
});
|
||||
$qb->select(sprintf('partial e.{%s}', implode(',', $fields)));
|
||||
}
|
||||
|
||||
if (null !== $isArchived) {
|
||||
$qb->andWhere('e.isArchived = :isArchived')->setParameter('isArchived', (bool) $isArchived);
|
||||
}
|
||||
|
@ -193,6 +209,8 @@ class EntryRepository extends EntityRepository
|
|||
$qb->orderBy('e.id', $order);
|
||||
} elseif ('updated' === $sort) {
|
||||
$qb->orderBy('e.updatedAt', $order);
|
||||
} elseif ('archived' === $sort) {
|
||||
$qb->orderBy('e.archivedAt', $order);
|
||||
}
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb, true, false);
|
||||
|
@ -324,15 +342,32 @@ class EntryRepository extends EntityRepository
|
|||
* Find an entry by its url and its owner.
|
||||
* If it exists, return the entry otherwise return false.
|
||||
*
|
||||
* @param $url
|
||||
* @param $userId
|
||||
* @param string $url
|
||||
* @param int $userId
|
||||
*
|
||||
* @return Entry|bool
|
||||
*/
|
||||
public function findByUrlAndUserId($url, $userId)
|
||||
{
|
||||
return $this->findByHashedUrlAndUserId(
|
||||
UrlHasher::hashUrl($url),
|
||||
$userId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an entry by its hashed url and its owner.
|
||||
* If it exists, return the entry otherwise return false.
|
||||
*
|
||||
* @param string $hashedUrl Url hashed using sha1
|
||||
* @param int $userId
|
||||
*
|
||||
* @return Entry|bool
|
||||
*/
|
||||
public function findByHashedUrlAndUserId($hashedUrl, $userId)
|
||||
{
|
||||
$res = $this->createQueryBuilder('e')
|
||||
->where('e.url = :url')->setParameter('url', urldecode($url))
|
||||
->where('e.hashedUrl = :hashed_url')->setParameter('hashed_url', $hashedUrl)
|
||||
->andWhere('e.user = :user_id')->setParameter('user_id', $userId)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
@ -416,8 +451,8 @@ class EntryRepository extends EntityRepository
|
|||
/**
|
||||
* Find all entries by url and owner.
|
||||
*
|
||||
* @param $url
|
||||
* @param $userId
|
||||
* @param string $url
|
||||
* @param int $userId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -430,6 +465,49 @@ class EntryRepository extends EntityRepository
|
|||
->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random entry, filtering by status.
|
||||
*
|
||||
* @param int $userId
|
||||
* @param string $type Can be unread, archive, starred, etc
|
||||
*
|
||||
* @throws NoResultException
|
||||
*
|
||||
* @return Entry
|
||||
*/
|
||||
public function getRandomEntry($userId, $type = '')
|
||||
{
|
||||
$qb = $this->getQueryBuilderByUser($userId)
|
||||
->select('e.id');
|
||||
|
||||
switch ($type) {
|
||||
case 'unread':
|
||||
$qb->andWhere('e.isArchived = false');
|
||||
break;
|
||||
case 'archive':
|
||||
$qb->andWhere('e.isArchived = true');
|
||||
break;
|
||||
case 'starred':
|
||||
$qb->andWhere('e.isStarred = true');
|
||||
break;
|
||||
case 'untagged':
|
||||
$qb->leftJoin('e.tags', 't');
|
||||
$qb->andWhere('t.id is null');
|
||||
break;
|
||||
}
|
||||
|
||||
$ids = $qb->getQuery()->getArrayResult();
|
||||
|
||||
if (empty($ids)) {
|
||||
throw new NoResultException();
|
||||
}
|
||||
|
||||
// random select one in the list
|
||||
$randomId = $ids[mt_rand(0, \count($ids) - 1)]['id'];
|
||||
|
||||
return $this->find($randomId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a query builder to be used by other getBuilderFor* method.
|
||||
*
|
||||
|
@ -468,7 +546,6 @@ class EntryRepository extends EntityRepository
|
|||
*/
|
||||
private function sortQueryBuilder(QueryBuilder $qb, $sortBy = 'createdAt', $direction = 'desc')
|
||||
{
|
||||
return $qb
|
||||
->orderBy(sprintf('e.%s', $sortBy), $direction);
|
||||
return $qb->orderBy(sprintf('e.%s', $sortBy), $direction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ services:
|
|||
tags:
|
||||
- { name: form.type }
|
||||
|
||||
wallabag_core.param_converter.username_rsstoken_converter:
|
||||
class: Wallabag\CoreBundle\ParamConverter\UsernameRssTokenConverter
|
||||
wallabag_core.param_converter.username_feed_token_converter:
|
||||
class: Wallabag\CoreBundle\ParamConverter\UsernameFeedTokenConverter
|
||||
tags:
|
||||
- { name: request.param_converter, converter: username_rsstoken_converter }
|
||||
- { name: request.param_converter, converter: username_feed_token_converter }
|
||||
arguments:
|
||||
- "@doctrine"
|
||||
|
||||
|
@ -42,7 +42,7 @@ services:
|
|||
-
|
||||
error_message: '%wallabag_core.fetching_error_message%'
|
||||
error_message_title: '%wallabag_core.fetching_error_message_title%'
|
||||
- "@wallabag_core.guzzle.http_client"
|
||||
- "@wallabag_core.http_client"
|
||||
- "@wallabag_core.graby.config_builder"
|
||||
calls:
|
||||
- [ setLogger, [ "@logger" ] ]
|
||||
|
@ -55,9 +55,8 @@ services:
|
|||
- {}
|
||||
- "@logger"
|
||||
|
||||
wallabag_core.guzzle.http_client:
|
||||
class: GuzzleHttp\ClientInterface
|
||||
factory: ["@wallabag_core.guzzle.http_client_factory", buildHttpClient]
|
||||
wallabag_core.http_client:
|
||||
alias: 'httplug.client.wallabag_core'
|
||||
|
||||
wallabag_core.guzzle_authenticator.config_builder:
|
||||
class: Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder
|
||||
|
@ -73,7 +72,7 @@ services:
|
|||
bd_guzzle_site_authenticator.site_config_builder:
|
||||
alias: wallabag_core.guzzle_authenticator.config_builder
|
||||
|
||||
wallabag_core.guzzle.http_client_factory:
|
||||
wallabag_core.http_client_factory:
|
||||
class: Wallabag\CoreBundle\Helper\HttpClientFactory
|
||||
arguments:
|
||||
- "@wallabag_core.guzzle.cookie_jar"
|
||||
|
@ -181,6 +180,7 @@ services:
|
|||
|
||||
wallabag_core.exception_controller:
|
||||
class: Wallabag\CoreBundle\Controller\ExceptionController
|
||||
public: true
|
||||
arguments:
|
||||
- '@twig'
|
||||
- '%kernel.debug%'
|
||||
|
@ -211,10 +211,38 @@ services:
|
|||
- "@logger"
|
||||
|
||||
wallabag_core.entry.download_images.client:
|
||||
class: GuzzleHttp\Client
|
||||
alias: 'httplug.client.wallabag_core.entry.download_images'
|
||||
|
||||
wallabag_core.helper.crypto_proxy:
|
||||
class: Wallabag\CoreBundle\Helper\CryptoProxy
|
||||
arguments:
|
||||
- "%wallabag_core.site_credentials.encryption_key_path%"
|
||||
- "@logger"
|
||||
|
||||
wallabag_core.command.clean_duplicates:
|
||||
class: Wallabag\CoreBundle\Command\CleanDuplicatesCommand
|
||||
tags: ['console.command']
|
||||
|
||||
wallabag_core.command.export:
|
||||
class: Wallabag\CoreBundle\Command\ExportCommand
|
||||
tags: ['console.command']
|
||||
|
||||
wallabag_core.command.install:
|
||||
class: Wallabag\CoreBundle\Command\InstallCommand
|
||||
tags: ['console.command']
|
||||
|
||||
wallabag_core.command.list_user:
|
||||
class: Wallabag\CoreBundle\Command\ListUserCommand
|
||||
tags: ['console.command']
|
||||
|
||||
wallabag_core.command.reload_entry:
|
||||
class: Wallabag\CoreBundle\Command\ReloadEntryCommand
|
||||
tags: ['console.command']
|
||||
|
||||
wallabag_core.command.show_user:
|
||||
class: Wallabag\CoreBundle\Command\ShowUserCommand
|
||||
tags: ['console.command']
|
||||
|
||||
wallabag_core.command.tag_all:
|
||||
class: Wallabag\CoreBundle\Command\TagAllCommand
|
||||
tags: ['console.command']
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Tilføj ny artikel'
|
||||
search: 'Søg'
|
||||
filter_entries: 'Filtrer artikler'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
# export: 'Export'
|
||||
search_form:
|
||||
input_label: 'Indtast søgning'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Opsætning'
|
||||
tab_menu:
|
||||
settings: 'Indstillinger'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Brugeroplysninger'
|
||||
password: 'Adgangskode'
|
||||
# rules: 'Tagging rules'
|
||||
new_user: 'Tilføj bruger'
|
||||
# reset: 'Reset area'
|
||||
form:
|
||||
save: 'Gem'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,33 @@ config:
|
|||
# help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
|
||||
# help_language: "You can change the language of wallabag interface."
|
||||
# help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'RSS-feeds fra wallabag gør det muligt at læse de artikler, der gemmes i wallabag, med din RSS-læser. Det kræver, at du genererer et token først.'
|
||||
token_label: 'RSS-Token'
|
||||
no_token: 'Intet token'
|
||||
token_create: 'Opret token'
|
||||
token_reset: 'Nulstil token'
|
||||
rss_links: 'RSS-Links'
|
||||
rss_link:
|
||||
feed_links: 'RSS-Links'
|
||||
feed_link:
|
||||
unread: 'Ulæst'
|
||||
starred: 'Favoritter'
|
||||
archive: 'Arkiv'
|
||||
# all: 'All'
|
||||
# rss_limit: 'Number of items in the feed'
|
||||
# feed_limit: 'Number of items in the feed'
|
||||
form_user:
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Navn'
|
||||
email_label: 'Emailadresse'
|
||||
# twoFactorAuthentication_label: 'Two factor authentication'
|
||||
# help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
|
||||
two_factor:
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
# title: Delete my account (a.k.a danger zone)
|
||||
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
|
||||
|
@ -159,6 +169,15 @@ config:
|
|||
# and: 'One rule AND another'
|
||||
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
|
||||
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
# default_title: 'Title of the entry'
|
||||
|
@ -353,7 +372,7 @@ quickstart:
|
|||
# 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'
|
||||
# feed: 'Enable RSS feeds'
|
||||
# tagging_rules: 'Write rules to automatically tag your articles'
|
||||
# admin:
|
||||
# title: 'Administration'
|
||||
|
@ -404,6 +423,8 @@ tag:
|
|||
new:
|
||||
# add: 'Add'
|
||||
# placeholder: 'You can add several tags, separated by a comma.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +550,8 @@ user:
|
|||
email_label: 'Emailadresse'
|
||||
# enabled_label: 'Enabled'
|
||||
# last_login_label: 'Last login'
|
||||
# twofactor_label: Two factor authentication
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
# save: Save
|
||||
# delete: Delete
|
||||
# delete_confirm: Are you sure?
|
||||
|
@ -567,10 +589,10 @@ flashes:
|
|||
password_updated: 'Adgangskode opdateret'
|
||||
# password_not_updated_demo: "In demonstration mode, you can't change password for this user."
|
||||
user_updated: 'Oplysninger opdateret'
|
||||
rss_updated: 'RSS-oplysninger opdateret'
|
||||
feed_updated: 'RSS-oplysninger opdateret'
|
||||
# tagging_rules_updated: 'Tagging rules updated'
|
||||
# tagging_rules_deleted: 'Tagging rule deleted'
|
||||
# rss_token_updated: 'RSS token updated'
|
||||
# feed_token_updated: 'RSS token updated'
|
||||
# annotations_reset: Annotations reset
|
||||
# tags_reset: Tags reset
|
||||
# entries_reset: Entries reset
|
||||
|
@ -588,9 +610,11 @@ flashes:
|
|||
entry_starred: 'Artikel markeret som favorit'
|
||||
entry_unstarred: 'Artikel ikke længere markeret som favorit'
|
||||
entry_deleted: 'Artikel slettet'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
# tag_added: 'Tag added'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
# failed: 'Import failed, please try again.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Neuen Artikel hinzufügen'
|
||||
search: 'Suche'
|
||||
filter_entries: 'Artikel filtern'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Exportieren'
|
||||
search_form:
|
||||
input_label: 'Suchbegriff hier eingeben'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Einstellungen'
|
||||
tab_menu:
|
||||
settings: 'Einstellungen'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Benutzerinformation'
|
||||
password: 'Kennwort'
|
||||
rules: 'Tagging-Regeln'
|
||||
new_user: 'Benutzer hinzufügen'
|
||||
reset: 'Zurücksetzen'
|
||||
form:
|
||||
save: 'Speichern'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,33 @@ config:
|
|||
help_reading_speed: "wallabag berechnet eine Lesezeit pro Artikel. Hier kannst du definieren, ob du ein schneller oder langsamer Leser bist. wallabag wird die Lesezeiten danach neu berechnen."
|
||||
help_language: "Du kannst die Sprache der wallabag-Oberfläche ändern."
|
||||
help_pocket_consumer_key: "Nötig für den Pocket-Import. Du kannst ihn in deinem Pocket account einrichten."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'Die RSS-Feeds von wallabag erlauben es dir, deine gespeicherten Artikel mit deinem bevorzugten RSS-Reader zu lesen. Vorher musst du jedoch einen Token erstellen.'
|
||||
token_label: 'RSS-Token'
|
||||
no_token: 'Kein Token'
|
||||
token_create: 'Token erstellen'
|
||||
token_reset: 'Token zurücksetzen'
|
||||
rss_links: 'RSS-Links'
|
||||
rss_link:
|
||||
feed_links: 'RSS-Links'
|
||||
feed_link:
|
||||
unread: 'Ungelesene'
|
||||
starred: 'Favoriten'
|
||||
archive: 'Archivierte'
|
||||
all: 'Alle'
|
||||
rss_limit: 'Anzahl der Einträge pro Feed'
|
||||
feed_limit: 'Anzahl der Einträge pro Feed'
|
||||
form_user:
|
||||
two_factor_description: "Wenn du die Zwei-Faktor-Authentifizierung aktivierst, erhältst du eine E-Mail mit einem Code bei jeder nicht vertrauenswürdigen Verbindung"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Name'
|
||||
email_label: 'E-Mail-Adresse'
|
||||
twoFactorAuthentication_label: 'Zwei-Faktor-Authentifizierung'
|
||||
help_twoFactorAuthentication: "Wenn du 2FA aktivierst, wirst du bei jedem Login einen Code per E-Mail bekommen."
|
||||
two_factor:
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: 'Lösche mein Konto (a.k.a Gefahrenzone)'
|
||||
description: 'Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.'
|
||||
|
@ -353,7 +363,7 @@ quickstart:
|
|||
title: 'Anwendung konfigurieren'
|
||||
description: 'Um die Applikation für dich anzupassen, schau in die Konfiguration von wallabag.'
|
||||
language: 'Sprache und Design ändern'
|
||||
rss: 'RSS-Feeds aktivieren'
|
||||
feed: 'RSS-Feeds aktivieren'
|
||||
tagging_rules: 'Schreibe Regeln, um deine Beiträge automatisch zu taggen (verschlagworten)'
|
||||
admin:
|
||||
title: 'Administration'
|
||||
|
@ -404,6 +414,8 @@ tag:
|
|||
new:
|
||||
add: 'Hinzufügen'
|
||||
placeholder: 'Du kannst verschiedene Tags, getrennt von einem Komma, hinzufügen.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
export:
|
||||
footer_template: '<div style="text-align:center;"><p>Generiert von wallabag mit Hilfe von %method%</p><p>Bitte öffne <a href="https://github.com/wallabag/wallabag/issues">ein Ticket</a> wenn du ein Problem mit der Darstellung von diesem E-Book auf deinem Gerät hast.</p></div>'
|
||||
|
@ -529,7 +541,8 @@ user:
|
|||
email_label: 'E-Mail-Adresse'
|
||||
enabled_label: 'Aktiviert'
|
||||
last_login_label: 'Letzter Login'
|
||||
twofactor_label: 'Zwei-Faktor-Authentifizierung'
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: 'Speichern'
|
||||
delete: 'Löschen'
|
||||
delete_confirm: 'Bist du sicher?'
|
||||
|
@ -567,14 +580,14 @@ flashes:
|
|||
password_updated: 'Kennwort aktualisiert'
|
||||
password_not_updated_demo: 'Im Testmodus kannst du das Kennwort nicht ändern.'
|
||||
user_updated: 'Information aktualisiert'
|
||||
rss_updated: 'RSS-Informationen aktualisiert'
|
||||
feed_updated: 'RSS-Informationen aktualisiert'
|
||||
tagging_rules_updated: 'Tagging-Regeln aktualisiert'
|
||||
tagging_rules_deleted: 'Tagging-Regel gelöscht'
|
||||
rss_token_updated: 'RSS-Token aktualisiert'
|
||||
annotations_reset: 'Anmerkungen zurücksetzen'
|
||||
tags_reset: 'Tags zurücksetzen'
|
||||
entries_reset: 'Einträge zurücksetzen'
|
||||
archived_reset: 'Archiverte Einträge zurücksetzen'
|
||||
feed_token_updated: 'RSS-Token aktualisiert'
|
||||
annotations_reset: Anmerkungen zurücksetzen
|
||||
tags_reset: Tags zurücksetzen
|
||||
entries_reset: Einträge zurücksetzen
|
||||
archived_reset: Archiverte Einträge zurücksetzen
|
||||
entry:
|
||||
notice:
|
||||
entry_already_saved: 'Eintrag bereits am %date% gespeichert'
|
||||
|
@ -588,9 +601,11 @@ flashes:
|
|||
entry_starred: 'Eintrag favorisiert'
|
||||
entry_unstarred: 'Eintrag defavorisiert'
|
||||
entry_deleted: 'Eintrag gelöscht'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Tag hinzugefügt'
|
||||
#tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Import fehlgeschlagen, bitte erneut probieren.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Add a new entry'
|
||||
search: 'Search'
|
||||
filter_entries: 'Filter entries'
|
||||
random_entry: Jump to a random entry from that list
|
||||
export: 'Export'
|
||||
search_form:
|
||||
input_label: 'Enter your search here'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Config'
|
||||
tab_menu:
|
||||
settings: 'Settings'
|
||||
rss: 'RSS'
|
||||
feed: 'Feeds'
|
||||
user_info: 'User information'
|
||||
password: 'Password'
|
||||
rules: 'Tagging rules'
|
||||
new_user: 'Add a user'
|
||||
reset: 'Reset area'
|
||||
form:
|
||||
save: 'Save'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,33 @@ config:
|
|||
help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
|
||||
help_language: "You can change the language of wallabag interface."
|
||||
help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account."
|
||||
form_rss:
|
||||
description: 'RSS feeds provided by wallabag allow you to read your saved articles with your favourite RSS reader. You need to generate a token first.'
|
||||
token_label: 'RSS token'
|
||||
form_feed:
|
||||
description: 'Atom feeds provided by wallabag allow you to read your saved articles with your favourite Atom reader. You need to generate a token first.'
|
||||
token_label: 'Feed token'
|
||||
no_token: 'No token'
|
||||
token_create: 'Create your token'
|
||||
token_reset: 'Regenerate your token'
|
||||
rss_links: 'RSS links'
|
||||
rss_link:
|
||||
feed_links: 'Feed links'
|
||||
feed_link:
|
||||
unread: 'Unread'
|
||||
starred: 'Starred'
|
||||
archive: 'Archived'
|
||||
all: 'All'
|
||||
rss_limit: 'Number of items in the feed'
|
||||
feed_limit: 'Number of items in the feed'
|
||||
form_user:
|
||||
two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connection."
|
||||
two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Name'
|
||||
email_label: 'Email'
|
||||
twoFactorAuthentication_label: 'Two factor authentication'
|
||||
help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
|
||||
two_factor:
|
||||
emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
table_method: Method
|
||||
table_state: State
|
||||
table_action: Action
|
||||
state_enabled: Enabled
|
||||
state_disabled: Disabled
|
||||
action_email: Use email
|
||||
action_app: Use OTP App
|
||||
delete:
|
||||
title: Delete my account (a.k.a danger zone)
|
||||
description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
|
||||
|
@ -159,6 +169,15 @@ config:
|
|||
and: 'One rule AND another'
|
||||
matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
|
||||
notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
page_title: Two-factor authentication
|
||||
app:
|
||||
two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
cancel: Cancel
|
||||
enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: 'Title of the entry'
|
||||
|
@ -353,7 +372,7 @@ quickstart:
|
|||
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'
|
||||
feed: 'Enable feeds'
|
||||
tagging_rules: 'Write rules to automatically tag your articles'
|
||||
admin:
|
||||
title: 'Administration'
|
||||
|
@ -404,6 +423,8 @@ tag:
|
|||
new:
|
||||
add: 'Add'
|
||||
placeholder: 'You can add several tags, separated by a comma.'
|
||||
rename:
|
||||
placeholder: 'You can update tag name.'
|
||||
|
||||
export:
|
||||
footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +550,8 @@ user:
|
|||
email_label: 'Email'
|
||||
enabled_label: 'Enabled'
|
||||
last_login_label: 'Last login'
|
||||
twofactor_label: Two factor authentication
|
||||
twofactor_email_label: Two factor authentication by email
|
||||
twofactor_google_label: Two factor authentication by OTP app
|
||||
save: Save
|
||||
delete: Delete
|
||||
delete_confirm: Are you sure?
|
||||
|
@ -567,14 +589,15 @@ flashes:
|
|||
password_updated: 'Password updated'
|
||||
password_not_updated_demo: "In demonstration mode, you can't change password for this user."
|
||||
user_updated: 'Information updated'
|
||||
rss_updated: 'RSS information updated'
|
||||
feed_updated: 'Feed information updated'
|
||||
tagging_rules_updated: 'Tagging rules updated'
|
||||
tagging_rules_deleted: 'Tagging rule deleted'
|
||||
rss_token_updated: 'RSS token updated'
|
||||
feed_token_updated: 'Feed token updated'
|
||||
annotations_reset: Annotations reset
|
||||
tags_reset: Tags reset
|
||||
entries_reset: Entries reset
|
||||
archived_reset: Archived entries deleted
|
||||
otp_enabled: Two-factor authentication enabled
|
||||
entry:
|
||||
notice:
|
||||
entry_already_saved: 'Entry already saved on %date%'
|
||||
|
@ -588,9 +611,11 @@ flashes:
|
|||
entry_starred: 'Entry starred'
|
||||
entry_unstarred: 'Entry unstarred'
|
||||
entry_deleted: 'Entry deleted'
|
||||
no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Tag added'
|
||||
tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Import failed, please try again.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Añadir un nuevo artículo'
|
||||
search: 'Buscar'
|
||||
filter_entries: 'Filtrar los artículos'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Exportar'
|
||||
search_form:
|
||||
input_label: 'Introduzca su búsqueda aquí'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Configuración'
|
||||
tab_menu:
|
||||
settings: 'Configuración'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Información de usuario'
|
||||
password: 'Contraseña'
|
||||
rules: 'Reglas de etiquetado automáticas'
|
||||
new_user: 'Añadir un usuario'
|
||||
reset: 'Reiniciar mi cuenta'
|
||||
form:
|
||||
save: 'Guardar'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,33 @@ config:
|
|||
help_reading_speed: "wallabag calcula un tiempo de lectura para cada artículo. Puedes definir aquí, gracias a esta lista, si eres un lector rápido o lento. wallabag recalculará el tiempo de lectura para cada artículo."
|
||||
help_language: "Puedes cambiar el idioma de la interfaz de wallabag."
|
||||
help_pocket_consumer_key: "Requerido para la importación desde Pocket. Puedes crearla en tu cuenta de Pocket."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'Los feeds RSS de wallabag permiten leer los artículos guardados con su lector RSS favorito. Primero necesitas generar un token.'
|
||||
token_label: 'Token RSS'
|
||||
no_token: 'Sin token'
|
||||
token_create: 'Crear token'
|
||||
token_reset: 'Reiniciar token'
|
||||
rss_links: 'URLs de feeds RSS'
|
||||
rss_link:
|
||||
feed_links: 'URLs de feeds RSS'
|
||||
feed_link:
|
||||
unread: 'sin leer'
|
||||
starred: 'favoritos'
|
||||
archive: 'archivados'
|
||||
# all: 'All'
|
||||
rss_limit: 'Límite de artículos en feed RSS'
|
||||
feed_limit: 'Límite de artículos en feed RSS'
|
||||
form_user:
|
||||
two_factor_description: "Con la autenticación en dos pasos recibirá código por e-mail en cada nueva conexión que no sea de confianza."
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Nombre'
|
||||
email_label: 'Dirección de e-mail'
|
||||
twoFactorAuthentication_label: 'Autenticación en dos pasos'
|
||||
help_twoFactorAuthentication: "Si activas la autenticación en dos pasos, cada vez que quieras iniciar sesión en wallabag recibirás un código por e-mail."
|
||||
two_factor:
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: Eliminar mi cuenta (Zona peligrosa)
|
||||
description: Si eliminas tu cuenta, TODOS tus artículos, TODAS tus etiquetas, TODAS tus anotaciones y tu cuenta serán eliminadas de forma PERMANENTE (no se puede deshacer). Después serás desconectado.
|
||||
|
@ -159,6 +169,15 @@ config:
|
|||
and: 'Una regla Y la otra'
|
||||
matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>'
|
||||
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: 'Título del artículo'
|
||||
|
@ -353,7 +372,7 @@ quickstart:
|
|||
title: 'Configure la aplicación'
|
||||
description: 'Para que la aplicación se ajuste a tus necesidades, echa un vistazo a la configuración de wallabag.'
|
||||
language: 'Cambie el idioma y el diseño'
|
||||
rss: 'Activar los feeds RSS'
|
||||
feed: 'Activar los feeds RSS'
|
||||
tagging_rules: 'Escribe reglas para etiquetar automáticamente tus artículos'
|
||||
admin:
|
||||
title: 'Administración'
|
||||
|
@ -404,6 +423,8 @@ tag:
|
|||
new:
|
||||
add: 'Añadir'
|
||||
placeholder: 'Puedes añadir varias etiquetas, separadas por una coma.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +550,8 @@ user:
|
|||
email_label: 'E-mail'
|
||||
enabled_label: 'Activado'
|
||||
last_login_label: 'Último inicio de sesión'
|
||||
twofactor_label: Autenticación en dos pasos
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: Guardar
|
||||
delete: Eliminar
|
||||
delete_confirm: ¿Estás seguro?
|
||||
|
@ -567,10 +589,10 @@ flashes:
|
|||
password_updated: 'Contraseña actualizada'
|
||||
password_not_updated_demo: "En el modo demo, no puede cambiar la contraseña del usuario."
|
||||
user_updated: 'Información actualizada'
|
||||
rss_updated: 'Configuración RSS actualizada'
|
||||
feed_updated: 'Configuración RSS actualizada'
|
||||
tagging_rules_updated: 'Regla de etiquetado actualizada'
|
||||
tagging_rules_deleted: 'Regla de etiquetado eliminada'
|
||||
rss_token_updated: 'Token RSS actualizado'
|
||||
feed_token_updated: 'Token RSS actualizado'
|
||||
annotations_reset: Anotaciones reiniciadas
|
||||
tags_reset: Etiquetas reiniciadas
|
||||
entries_reset: Artículos reiniciados
|
||||
|
@ -588,9 +610,11 @@ flashes:
|
|||
entry_starred: 'Artículo marcado como favorito'
|
||||
entry_unstarred: 'Artículo desmarcado como favorito'
|
||||
entry_deleted: 'Artículo eliminado'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Etiqueta añadida'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Importación fallida, por favor, inténtelo de nuevo.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'افزودن مقالهٔ تازه'
|
||||
search: 'جستجو'
|
||||
filter_entries: 'فیلترکردن مقالهها'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'برونبری'
|
||||
search_form:
|
||||
input_label: 'جستجوی خود را اینجا بنویسید:'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'پیکربندی'
|
||||
tab_menu:
|
||||
settings: 'تنظیمات'
|
||||
rss: 'آر-اس-اس'
|
||||
feed: 'آر-اس-اس'
|
||||
user_info: 'اطلاعات کاربر'
|
||||
password: 'رمز'
|
||||
rules: 'برچسبگذاری خودکار'
|
||||
new_user: 'افزودن کاربر'
|
||||
# reset: 'Reset area'
|
||||
form:
|
||||
save: 'ذخیره'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,33 @@ config:
|
|||
# help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
|
||||
# help_language: "You can change the language of wallabag interface."
|
||||
# help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'با خوراک آر-اس-اس که wallabag در اختیارتان میگذارد، میتوانید مقالههای ذخیرهشده را در نرمافزار آر-اس-اس دلخواه خود بخوانید. برای این کار نخست باید یک کد بسازید.'
|
||||
token_label: 'کد آر-اس-اس'
|
||||
no_token: 'بدون کد'
|
||||
token_create: 'کد خود را بسازید'
|
||||
token_reset: 'بازنشانی کد'
|
||||
rss_links: 'پیوند آر-اس-اس'
|
||||
rss_link:
|
||||
feed_links: 'پیوند آر-اس-اس'
|
||||
feed_link:
|
||||
unread: 'خواندهنشده'
|
||||
starred: 'برگزیده'
|
||||
archive: 'بایگانی'
|
||||
# all: 'All'
|
||||
rss_limit: 'محدودیت آر-اس-اس'
|
||||
feed_limit: 'محدودیت آر-اس-اس'
|
||||
form_user:
|
||||
two_factor_description: "با فعالکردن تأیید ۲مرحلهای هر بار که اتصال تأییدنشدهای برقرار شد، به شما یک کد از راه ایمیل فرستاده میشود"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'نام'
|
||||
email_label: 'نشانی ایمیل'
|
||||
twoFactorAuthentication_label: 'تأیید ۲مرحلهای'
|
||||
# help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
|
||||
two_factor:
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
# title: Delete my account (a.k.a danger zone)
|
||||
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
|
||||
|
@ -159,6 +169,15 @@ config:
|
|||
# and: 'One rule AND another'
|
||||
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
|
||||
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
# default_title: 'Title of the entry'
|
||||
|
@ -353,7 +372,7 @@ quickstart:
|
|||
title: 'برنامه را تنظیم کنید'
|
||||
# description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
|
||||
language: 'زبان و نمای برنامه را تغییر دهید'
|
||||
rss: 'خوراک آر-اس-اس را فعال کنید'
|
||||
feed: 'خوراک آر-اس-اس را فعال کنید'
|
||||
tagging_rules: 'قانونهای برچسبگذاری خودکار مقالههایتان را تعریف کنید'
|
||||
admin:
|
||||
title: 'مدیریت'
|
||||
|
@ -404,6 +423,8 @@ tag:
|
|||
new:
|
||||
# add: 'Add'
|
||||
# placeholder: 'You can add several tags, separated by a comma.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +550,8 @@ user:
|
|||
email_label: 'نشانی ایمیل'
|
||||
# enabled_label: 'Enabled'
|
||||
# last_login_label: 'Last login'
|
||||
# twofactor_label: Two factor authentication
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
# save: Save
|
||||
# delete: Delete
|
||||
# delete_confirm: Are you sure?
|
||||
|
@ -567,10 +589,10 @@ flashes:
|
|||
password_updated: 'رمز بهروز شد'
|
||||
password_not_updated_demo: "در حالت نمایشی نمیتوانید رمز کاربر را عوض کنید."
|
||||
user_updated: 'اطلاعات بهروز شد'
|
||||
rss_updated: 'اطلاعات آر-اس-اس بهروز شد'
|
||||
feed_updated: 'اطلاعات آر-اس-اس بهروز شد'
|
||||
tagging_rules_updated: 'برچسبگذاری خودکار بهروز شد'
|
||||
tagging_rules_deleted: 'قانون برچسبگذاری پاک شد'
|
||||
rss_token_updated: 'کد آر-اس-اس بهروز شد'
|
||||
feed_token_updated: 'کد آر-اس-اس بهروز شد'
|
||||
# annotations_reset: Annotations reset
|
||||
# tags_reset: Tags reset
|
||||
# entries_reset: Entries reset
|
||||
|
@ -588,9 +610,11 @@ flashes:
|
|||
entry_starred: 'مقاله برگزیده شد'
|
||||
entry_unstarred: 'مقاله نابرگزیده شد'
|
||||
entry_deleted: 'مقاله پاک شد'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'برچسب افزوده شد'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'درونریزی شکست خورد. لطفاً دوباره تلاش کنید.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: "Sauvegarder un nouvel article"
|
||||
search: "Rechercher"
|
||||
filter_entries: "Filtrer les articles"
|
||||
random_entry: Aller à un article aléatoire de cette liste
|
||||
export: "Exporter"
|
||||
search_form:
|
||||
input_label: "Saisissez votre terme de recherche"
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: "Configuration"
|
||||
tab_menu:
|
||||
settings: "Paramètres"
|
||||
rss: "RSS"
|
||||
feed: "Flux"
|
||||
user_info: "Mon compte"
|
||||
password: "Mot de passe"
|
||||
rules: "Règles de tag automatiques"
|
||||
new_user: "Créer un compte"
|
||||
reset: "Réinitialisation"
|
||||
form:
|
||||
save: "Enregistrer"
|
||||
form_settings:
|
||||
|
@ -83,25 +85,33 @@ config:
|
|||
help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article."
|
||||
help_language: "Vous pouvez définir la langue de l’interface de wallabag."
|
||||
help_pocket_consumer_key: "Nécessaire pour l’import depuis Pocket. Vous pouvez le créer depuis votre compte Pocket."
|
||||
form_rss:
|
||||
description: "Les flux RSS fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton."
|
||||
token_label: "Jeton RSS"
|
||||
form_feed:
|
||||
description: "Les flux Atom fournis par wallabag vous permettent de lire vos articles sauvegardés dans votre lecteur de flux préféré. Pour pouvoir les utiliser, vous devez d’abord créer un jeton."
|
||||
token_label: "Jeton de flux"
|
||||
no_token: "Aucun jeton généré"
|
||||
token_create: "Créez votre jeton"
|
||||
token_reset: "Réinitialisez votre jeton"
|
||||
rss_links: "Adresses de vos flux RSS"
|
||||
rss_link:
|
||||
feed_links: "Adresses de vos flux"
|
||||
feed_link:
|
||||
unread: "Non lus"
|
||||
starred: "Favoris"
|
||||
archive: "Lus"
|
||||
all: "Tous"
|
||||
rss_limit: "Nombre d’articles dans le flux"
|
||||
feed_limit: "Nombre d’articles dans le flux"
|
||||
form_user:
|
||||
two_factor_description: "Activer l’authentification double-facteur veut dire que vous allez recevoir un code par courriel à chaque nouvelle connexion non approuvée."
|
||||
two_factor_description: "Activer l’authentification double-facteur veut dire que vous allez recevoir un code par courriel OU que vous devriez utiliser une application de mot de passe à usage unique (comme Google Authenticator, Authy or FreeOTP) pour obtenir un code temporaire à chaque nouvelle connexion non approuvée. Vous ne pouvez pas choisir les deux options."
|
||||
name_label: "Nom"
|
||||
email_label: "Adresse courriel"
|
||||
twoFactorAuthentication_label: "Double authentification"
|
||||
help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email."
|
||||
two_factor:
|
||||
emailTwoFactor_label: 'En utlisant l’email (recevez un code par email)'
|
||||
googleTwoFactor_label: 'En utilisant une application de mot de passe à usage unique (ouvrez l’app, comme Google Authenticator, Authy or FreeOTP, pour obtenir un mot de passe à usage unique)'
|
||||
table_method: Méthode
|
||||
table_state: État
|
||||
table_action: Action
|
||||
state_enabled: Activé
|
||||
state_disabled: Désactivé
|
||||
action_email: Utiliser l'email
|
||||
action_app: Utiliser une app OTP
|
||||
delete:
|
||||
title: "Supprimer mon compte (attention danger !)"
|
||||
description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté."
|
||||
|
@ -159,6 +169,15 @@ config:
|
|||
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>"
|
||||
notmatches: "Teste si un <i>sujet</i> ne correspond pas à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title notmatches \"football\"</code>"
|
||||
otp:
|
||||
page_title: Authentification double-facteur
|
||||
app:
|
||||
two_factor_code_description_1: Vous venez d’activer l’authentification double-facteur, ouvrez votre application OTP pour configurer la génération du mot de passe à usage unique. Ces informations disparaîtront après un rechargement de la page.
|
||||
two_factor_code_description_2: 'Vous pouvez scanner le QR code avec votre application :'
|
||||
two_factor_code_description_3: 'N’oubliez pas de sauvegarder ces codes de secours dans un endroit sûr, vous pourrez les utiliser si vous ne pouvez plus accéder à votre application OTP :'
|
||||
two_factor_code_description_4: 'Testez un code généré par votre application OTP :'
|
||||
cancel: Annuler
|
||||
enable: Activer
|
||||
|
||||
entry:
|
||||
default_title: "Titre de l’article"
|
||||
|
@ -353,7 +372,7 @@ quickstart:
|
|||
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"
|
||||
feed: "Activez les flux Atom"
|
||||
tagging_rules: "Écrivez des règles pour classer automatiquement vos articles"
|
||||
admin:
|
||||
title: "Administration"
|
||||
|
@ -404,6 +423,8 @@ tag:
|
|||
new:
|
||||
add: "Ajouter"
|
||||
placeholder: "Vous pouvez ajouter plusieurs tags, séparés par une virgule."
|
||||
rename:
|
||||
placeholder: 'Vous pouvez changer le nom de votre tag.'
|
||||
|
||||
export:
|
||||
footer_template: '<div style="text-align:center;"><p>Généré par wallabag with %method%</p><p>Merci d''ouvrir <a href="https://github.com/wallabag/wallabag/issues">un ticket</a> si vous rencontrez des soucis d''affichage avec ce document sur votre support.</p></div>'
|
||||
|
@ -530,6 +551,8 @@ user:
|
|||
enabled_label: "Activé"
|
||||
last_login_label: "Dernière connexion"
|
||||
twofactor_label: "Double authentification"
|
||||
twofactor_email_label: Double authentification par email
|
||||
twofactor_google_label: Double authentification par OTP app
|
||||
save: "Sauvegarder"
|
||||
delete: "Supprimer"
|
||||
delete_confirm: "Êtes-vous sûr ?"
|
||||
|
@ -567,14 +590,15 @@ flashes:
|
|||
password_updated: "Votre mot de passe a bien été mis à jour"
|
||||
password_not_updated_demo: "En démo, vous ne pouvez pas changer le mot de passe de cet utilisateur."
|
||||
user_updated: "Vos informations personnelles ont bien été mises à jour"
|
||||
rss_updated: "La configuration des flux RSS a bien été mise à jour"
|
||||
feed_updated: "La configuration des flux a bien été mise à jour"
|
||||
tagging_rules_updated: "Règles mises à jour"
|
||||
tagging_rules_deleted: "Règle supprimée"
|
||||
rss_token_updated: "Jeton RSS mis à jour"
|
||||
feed_token_updated: "Jeton des flux mis à jour"
|
||||
annotations_reset: "Annotations supprimées"
|
||||
tags_reset: "Tags supprimés"
|
||||
entries_reset: "Articles supprimés"
|
||||
archived_reset: "Articles archivés supprimés"
|
||||
otp_enabled: "Authentification à double-facteur activée"
|
||||
entry:
|
||||
notice:
|
||||
entry_already_saved: "Article déjà sauvegardé le %date%"
|
||||
|
@ -588,9 +612,11 @@ flashes:
|
|||
entry_starred: "Article ajouté dans les favoris"
|
||||
entry_unstarred: "Article retiré des favoris"
|
||||
entry_deleted: "Article supprimé"
|
||||
no_random_entry: "Aucun article correspond aux critères n'a été trouvé"
|
||||
tag:
|
||||
notice:
|
||||
tag_added: "Tag ajouté"
|
||||
tag_renamed: "Tag renommé"
|
||||
import:
|
||||
notice:
|
||||
failed: "L’import a échoué, veuillez ré-essayer"
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Aggiungi un nuovo contenuto'
|
||||
search: 'Cerca'
|
||||
filter_entries: 'Filtra contenuti'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Esporta'
|
||||
search_form:
|
||||
input_label: 'Inserisci qui la tua ricerca'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Configurazione'
|
||||
tab_menu:
|
||||
settings: 'Impostazioni'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Informazioni utente'
|
||||
password: 'Password'
|
||||
rules: 'Regole di etichettatura'
|
||||
new_user: 'Aggiungi utente'
|
||||
reset: 'Area di reset'
|
||||
form:
|
||||
save: 'Salva'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,32 @@ config:
|
|||
help_reading_speed: "wallabag calcola un tempo di lettura per ogni articolo. Puoi definire qui, grazie a questa lista, se sei un lettore lento o veloce. wallabag ricalcolerà la velocità di lettura per ogni articolo."
|
||||
help_language: "Puoi cambiare la lingua dell'interfaccia di wallabag."
|
||||
help_pocket_consumer_key: "Richiesta per importare da Pocket. La puoi creare nel tuo account Pocket."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'I feed RSS generati da wallabag ti permettono di leggere i tuoi contenuti salvati con il tuo lettore di RSS preferito. Prima, devi generare un token.'
|
||||
token_label: 'Token RSS'
|
||||
no_token: 'Nessun token'
|
||||
token_create: 'Crea il tuo token'
|
||||
token_reset: 'Rigenera il tuo token'
|
||||
rss_links: 'Collegamenti RSS'
|
||||
rss_link:
|
||||
feed_links: 'Collegamenti RSS'
|
||||
feed_link:
|
||||
unread: 'Non letti'
|
||||
starred: 'Preferiti'
|
||||
archive: 'Archiviati'
|
||||
# all: 'All'
|
||||
rss_limit: 'Numero di elementi nel feed'
|
||||
feed_limit: 'Numero di elementi nel feed'
|
||||
form_user:
|
||||
two_factor_description: "Abilitando l'autenticazione a due fattori riceverai una e-mail con un codice per ogni nuova connesione non verificata"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Nome'
|
||||
email_label: 'E-mail'
|
||||
twoFactorAuthentication_label: 'Autenticazione a due fattori'
|
||||
help_twoFactorAuthentication: "Se abiliti l'autenticazione a due fattori, ogni volta che vorrai connetterti a wallabag, riceverai un codice via E-mail."
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: Cancella il mio account (zona pericolosa)
|
||||
description: Rimuovendo il tuo account, TUTTI i tuoi articoli, TUTTE le tue etichette, TUTTE le tue annotazioni ed il tuo account verranno rimossi PERMANENTEMENTE (impossibile da ANNULLARE). Verrai poi disconnesso.
|
||||
|
@ -159,6 +168,15 @@ config:
|
|||
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>'
|
||||
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: "Titolo del contenuto"
|
||||
|
@ -353,7 +371,7 @@ quickstart:
|
|||
title: "Configura l'applicazione"
|
||||
description: "Per avere un'applicazione che ti soddisfi, dai un'occhiata alla configurazione di wallabag."
|
||||
language: 'Cambia lingua e design'
|
||||
rss: 'Abilita i feed RSS'
|
||||
feed: 'Abilita i feed RSS'
|
||||
tagging_rules: 'Scrivi delle regole per taggare automaticamente i contenuti'
|
||||
admin:
|
||||
title: 'Amministrazione'
|
||||
|
@ -404,6 +422,8 @@ tag:
|
|||
new:
|
||||
add: 'Aggiungi'
|
||||
placeholder: 'Puoi aggiungere varie etichette, separate da una virgola.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +549,8 @@ user:
|
|||
email_label: 'E-mail'
|
||||
enabled_label: 'Abilitato'
|
||||
last_login_label: 'Ultima connessione'
|
||||
twofactor_label: Autenticazione a due fattori
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: Salva
|
||||
delete: Cancella
|
||||
delete_confirm: Sei sicuro?
|
||||
|
@ -567,10 +588,10 @@ flashes:
|
|||
password_updated: 'Password aggiornata'
|
||||
password_not_updated_demo: "In modalità demo, non puoi cambiare la password dell'utente."
|
||||
user_updated: 'Informazioni aggiornate'
|
||||
rss_updated: 'Informazioni RSS aggiornate'
|
||||
feed_updated: 'Informazioni RSS aggiornate'
|
||||
tagging_rules_updated: 'Regole di etichettatura aggiornate'
|
||||
tagging_rules_deleted: 'Regola di etichettatura eliminate'
|
||||
rss_token_updated: 'RSS token aggiornato'
|
||||
feed_token_updated: 'RSS token aggiornato'
|
||||
annotations_reset: Reset annotazioni
|
||||
tags_reset: Reset etichette
|
||||
entries_reset: Reset articoli
|
||||
|
@ -588,9 +609,11 @@ flashes:
|
|||
entry_starred: 'Contenuto segnato come preferito'
|
||||
entry_unstarred: 'Contenuto rimosso dai preferiti'
|
||||
entry_deleted: 'Contenuto eliminato'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Etichetta aggiunta'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Importazione fallita, riprova.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Enregistrar un novèl article'
|
||||
search: 'Cercar'
|
||||
filter_entries: 'Filtrar los articles'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Exportar'
|
||||
search_form:
|
||||
input_label: 'Picatz vòstre mot-clau a cercar aquí'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Configuracion'
|
||||
tab_menu:
|
||||
settings: 'Paramètres'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Mon compte'
|
||||
password: 'Senhal'
|
||||
rules: "Règlas d'etiquetas automaticas"
|
||||
new_user: 'Crear un compte'
|
||||
reset: 'Zòna de reïnicializacion'
|
||||
form:
|
||||
save: 'Enregistrar'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,32 @@ config:
|
|||
help_reading_speed: "wallabag calcula lo temps de lectura per cada article. Podètz lo definir aquí, gràcias a aquesta lista, se sètz un legeire rapid o lent. wallabag tornarà calcular lo temps de lectura per cada article."
|
||||
help_language: "Podètz cambiar la lenga de l'interfàcia de wallabag."
|
||||
help_pocket_consumer_key: "Requesida per l'importacion de Pocket. Podètz la crear dins vòstre compte Pocket."
|
||||
form_rss:
|
||||
form_feed:
|
||||
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: 'Pas cap de geton generat'
|
||||
token_create: 'Creatz vòstre geton'
|
||||
token_reset: 'Reïnicializatz vòstre geton'
|
||||
rss_links: 'URLs de vòstres fluxes RSS'
|
||||
rss_link:
|
||||
feed_links: 'URLs de vòstres fluxes RSS'
|
||||
feed_link:
|
||||
unread: 'Pas legits'
|
||||
starred: 'Favorits'
|
||||
archive: 'Legits'
|
||||
all: 'Totes'
|
||||
rss_limit: "Nombre d'articles dins un flux RSS"
|
||||
feed_limit: "Nombre d'articles dins un flux"
|
||||
form_user:
|
||||
two_factor_description: "Activar l'autentificacion en dos temps vòl dire que recebretz un còdi per corrièl per cada novèla connexion pas aprovada."
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Nom'
|
||||
email_label: 'Adreça de corrièl'
|
||||
twoFactorAuthentication_label: 'Dobla autentificacion'
|
||||
help_twoFactorAuthentication: "S'avètz activat l'autentificacion en dos temps, cada còp que volètz vos connectar a wallabag, recebretz un còdi per corrièl."
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: Suprimir mon compte (Mèfi zòna perilhosa)
|
||||
description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat.
|
||||
|
@ -159,6 +168,15 @@ config:
|
|||
and: "Una règla E l'autra"
|
||||
matches: 'Teste se un <i>subjècte</i> correspond a una <i>recèrca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>'
|
||||
notmatches: 'Teste se <i>subjècte</i> correspond pas a una <i>recèrca</i> (sensibla a la cassa).<br />Example : <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: "Títol de l'article"
|
||||
|
@ -353,7 +371,7 @@ quickstart:
|
|||
title: "Configuratz l'aplicacion"
|
||||
description: "Per fin d'aver una aplicacion que vos va ben, anatz veire la configuracion de wallabag."
|
||||
language: "Cambiatz la lenga e l'estil de l'aplicacion"
|
||||
rss: 'Activatz los fluxes RSS'
|
||||
feed: 'Activatz los fluxes RSS'
|
||||
tagging_rules: 'Escrivètz de règlas per classar automaticament vòstres articles'
|
||||
admin:
|
||||
title: 'Administracion'
|
||||
|
@ -404,6 +422,8 @@ tag:
|
|||
new:
|
||||
add: 'Ajustar'
|
||||
placeholder: "Podètz ajustar mai qu'una etiqueta, separadas per de virgula."
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
export:
|
||||
footer_template: '<div style="text-align:center;"><p>Produch per wallabag amb %method%</p><p>Mercés de dobrir <a href="https://github.com/wallabag/wallabag/issues">una sollicitacion</a> s’avètz de problèmas amb l’afichatge d’aqueste E-Book sus vòstre periferic.</p></div>'
|
||||
|
@ -529,7 +549,8 @@ user:
|
|||
email_label: 'Adreça de corrièl'
|
||||
enabled_label: 'Actiu'
|
||||
last_login_label: 'Darrièra connexion'
|
||||
twofactor_label: 'Autentificacion doble-factor'
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: 'Enregistrar'
|
||||
delete: 'Suprimir'
|
||||
delete_confirm: 'Sètz segur ?'
|
||||
|
@ -567,10 +588,10 @@ flashes:
|
|||
password_updated: 'Vòstre senhal es ben estat mes a jorn'
|
||||
password_not_updated_demo: "En demostracion, podètz pas cambiar lo senhal d'aqueste utilizaire."
|
||||
user_updated: 'Vòstres informacions personnelas son ben estadas mesas a jorn'
|
||||
rss_updated: 'La configuracion dels fluxes RSS es ben estada mesa a jorn'
|
||||
feed_updated: 'La configuracion dels fluxes RSS es ben estada mesa a jorn'
|
||||
tagging_rules_updated: 'Règlas misa a jorn'
|
||||
tagging_rules_deleted: 'Règla suprimida'
|
||||
rss_token_updated: 'Geton RSS mes a jorn'
|
||||
feed_token_updated: 'Geton RSS mes a jorn'
|
||||
annotations_reset: Anotacions levadas
|
||||
tags_reset: Etiquetas levadas
|
||||
entries_reset: Articles levats
|
||||
|
@ -588,9 +609,11 @@ flashes:
|
|||
entry_starred: 'Article ajustat dins los favorits'
|
||||
entry_unstarred: 'Article quitat dels favorits'
|
||||
entry_deleted: 'Article suprimit'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Etiqueta ajustada'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: "L'importacion a fracassat, mercés de tornar ensajar."
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Dodaj nowy wpis'
|
||||
search: 'Szukaj'
|
||||
filter_entries: 'Filtruj wpisy'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Eksportuj'
|
||||
search_form:
|
||||
input_label: 'Wpisz swoje zapytanie tutaj'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Konfiguracja'
|
||||
tab_menu:
|
||||
settings: 'Ustawienia'
|
||||
rss: 'Kanał RSS'
|
||||
feed: 'Kanał RSS'
|
||||
user_info: 'Informacje o użytkowniku'
|
||||
password: 'Hasło'
|
||||
rules: 'Zasady tagowania'
|
||||
new_user: 'Dodaj użytkownika'
|
||||
reset: 'Reset'
|
||||
form:
|
||||
save: 'Zapisz'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,32 @@ config:
|
|||
help_reading_speed: "wallabag oblicza czas czytania każdego artykułu. Dzięki tej liście możesz określić swoje tempo. Wallabag przeliczy ponownie czas potrzebny, na przeczytanie każdego z artykułów."
|
||||
help_language: "Możesz zmienić język interfejsu wallabag."
|
||||
help_pocket_consumer_key: "Wymagane dla importu z Pocket. Możesz go stworzyć na swoim koncie Pocket."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'Kanały RSS prowadzone przez wallabag pozwalają Ci na czytanie twoich zapisanych artykułów w twoim ulubionym czytniku RSS. Musisz najpierw wynegenerować tokena.'
|
||||
token_label: 'Token RSS'
|
||||
no_token: 'Brak tokena'
|
||||
token_create: 'Stwórz tokena'
|
||||
token_reset: 'Zresetuj swojego tokena'
|
||||
rss_links: 'RSS links'
|
||||
rss_link:
|
||||
feed_links: 'RSS links'
|
||||
feed_link:
|
||||
unread: 'Nieprzeczytane'
|
||||
starred: 'Oznaczone gwiazdką'
|
||||
archive: 'Archiwum'
|
||||
all: 'Wszystkie'
|
||||
rss_limit: 'Link do RSS'
|
||||
feed_limit: 'Link do RSS'
|
||||
form_user:
|
||||
two_factor_description: "Włączenie autoryzacji dwuetapowej oznacza, że będziesz otrzymywał maile z kodem przy każdym nowym, niezaufanym połączeniu"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Nazwa'
|
||||
email_label: 'Adres email'
|
||||
twoFactorAuthentication_label: 'Autoryzacja dwuetapowa'
|
||||
help_twoFactorAuthentication: "Jeżeli włączysz autoryzację dwuetapową. Za każdym razem, kiedy będziesz chciał się zalogować, dostaniesz kod na swój e-mail."
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: Usuń moje konto (niebezpieczna strefa !)
|
||||
description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany.
|
||||
|
@ -159,6 +168,15 @@ config:
|
|||
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>'
|
||||
notmatches: 'Sprawdź czy <i>temat</i> nie zawiera <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł nie zawiera "piłka nożna"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: 'Tytuł wpisu'
|
||||
|
@ -353,7 +371,7 @@ quickstart:
|
|||
title: 'Konfiguruj aplikację'
|
||||
description: 'W celu dopasowania aplikacji do swoich upodobań, zobacz konfigurację aplikacji'
|
||||
language: 'Zmień język i wygląd'
|
||||
rss: 'Włącz kanały RSS'
|
||||
feed: 'Włącz kanały RSS'
|
||||
tagging_rules: 'Napisz reguły pozwalające na automatyczne otagowanie twoich artykułów'
|
||||
admin:
|
||||
title: 'Administracja'
|
||||
|
@ -404,6 +422,8 @@ tag:
|
|||
new:
|
||||
add: 'Dodaj'
|
||||
placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.'
|
||||
rename:
|
||||
placeholder: 'Możesz zaktualizować nazwę taga.'
|
||||
|
||||
export:
|
||||
footer_template: '<div style="text-align:center;"><p>Stworzone przez wallabag z %method%</p><p>Proszę zgłoś <a href="https://github.com/wallabag/wallabag/issues">sprawę</a>, jeżeli masz problem z wyświetleniem tego e-booka na swoim urządzeniu.</p></div>'
|
||||
|
@ -529,7 +549,8 @@ user:
|
|||
email_label: 'Adres email'
|
||||
enabled_label: 'Włączony'
|
||||
last_login_label: 'Ostatnie logowanie'
|
||||
twofactor_label: Autoryzacja dwuetapowa
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: Zapisz
|
||||
delete: Usuń
|
||||
delete_confirm: Jesteś pewien?
|
||||
|
@ -567,10 +588,10 @@ flashes:
|
|||
password_updated: 'Hasło zaktualizowane'
|
||||
password_not_updated_demo: "In demonstration mode, you can't change password for this user."
|
||||
user_updated: 'Informacje zaktualizowane'
|
||||
rss_updated: 'Informacje RSS zaktualizowane'
|
||||
feed_updated: 'Informacje RSS zaktualizowane'
|
||||
tagging_rules_updated: 'Reguły tagowania zaktualizowane'
|
||||
tagging_rules_deleted: 'Reguła tagowania usunięta'
|
||||
rss_token_updated: 'Token kanału RSS zaktualizowany'
|
||||
feed_token_updated: 'Token kanału RSS zaktualizowany'
|
||||
annotations_reset: Zresetuj adnotacje
|
||||
tags_reset: Zresetuj tagi
|
||||
entries_reset: Zresetuj wpisy
|
||||
|
@ -588,9 +609,11 @@ flashes:
|
|||
entry_starred: 'Wpis oznaczony gwiazdką'
|
||||
entry_unstarred: 'Wpis odznaczony gwiazdką'
|
||||
entry_deleted: 'Wpis usunięty'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Tag dodany'
|
||||
tag_renamed: 'Nazwa taga zmieniona'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Nieudany import, prosimy spróbować ponownie.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Adicionar uma nova entrada'
|
||||
search: 'Pesquisa'
|
||||
filter_entries: 'Filtrar entradas'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Exportar'
|
||||
search_form:
|
||||
input_label: 'Digite aqui sua pesquisa'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Config'
|
||||
tab_menu:
|
||||
settings: 'Configurações'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Informação do Usuário'
|
||||
password: 'Senha'
|
||||
rules: 'Regras de tags'
|
||||
new_user: 'Adicionar um usuário'
|
||||
# reset: 'Reset area'
|
||||
form:
|
||||
save: 'Salvar'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,32 @@ config:
|
|||
# help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
|
||||
# help_language: "You can change the language of wallabag interface."
|
||||
# help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'Feeds RSS providos pelo wallabag permitem que você leia seus artigos salvos em seu leitor de RSS favorito. Você precisa gerar um token primeiro.'
|
||||
token_label: 'Token RSS'
|
||||
no_token: 'Nenhum Token'
|
||||
token_create: 'Criar seu token'
|
||||
token_reset: 'Gerar novamente seu token'
|
||||
rss_links: 'Links RSS'
|
||||
rss_link:
|
||||
feed_links: 'Links RSS'
|
||||
feed_link:
|
||||
unread: 'Não lido'
|
||||
starred: 'Destacado'
|
||||
archive: 'Arquivado'
|
||||
# all: 'All'
|
||||
rss_limit: 'Número de itens no feed'
|
||||
feed_limit: 'Número de itens no feed'
|
||||
form_user:
|
||||
two_factor_description: 'Habilitar autenticação de dois passos significa que você receberá um e-mail com um código a cada nova conexão desconhecida.'
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Nome'
|
||||
email_label: 'E-mail'
|
||||
twoFactorAuthentication_label: 'Autenticação de dois passos'
|
||||
# help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
# title: Delete my account (a.k.a danger zone)
|
||||
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
|
||||
|
@ -159,6 +168,15 @@ config:
|
|||
and: 'Uma regra E outra'
|
||||
matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>'
|
||||
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: 'Título da entrada'
|
||||
|
@ -353,7 +371,7 @@ quickstart:
|
|||
title: 'Configurar a aplicação'
|
||||
description: 'Para ter uma aplicação que atende você, dê uma olhada na configuração do wallabag.'
|
||||
language: 'Alterar idioma e design'
|
||||
rss: 'Habilitar feeds RSS'
|
||||
feed: 'Habilitar feeds RSS'
|
||||
tagging_rules: 'Escrever regras para acrescentar tags automaticamente em seus artigos'
|
||||
admin:
|
||||
title: 'Administração'
|
||||
|
@ -404,6 +422,8 @@ tag:
|
|||
new:
|
||||
# add: 'Add'
|
||||
# placeholder: 'You can add several tags, separated by a comma.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +549,8 @@ user:
|
|||
email_label: 'E-mail'
|
||||
enabled_label: 'Habilitado'
|
||||
last_login_label: 'Último login'
|
||||
twofactor_label: 'Autenticação de dois passos'
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: 'Salvar'
|
||||
delete: 'Apagar'
|
||||
delete_confirm: 'Tem certeza?'
|
||||
|
@ -567,10 +588,10 @@ flashes:
|
|||
password_updated: 'Senha atualizada'
|
||||
password_not_updated_demo: 'Em modo de demonstração, você não pode alterar a senha deste usuário.'
|
||||
# user_updated: 'Information updated'
|
||||
rss_updated: 'Informação de RSS atualizada'
|
||||
feed_updated: 'Informação de RSS atualizada'
|
||||
tagging_rules_updated: 'Regras de tags atualizadas'
|
||||
tagging_rules_deleted: 'Regra de tag apagada'
|
||||
rss_token_updated: 'Token RSS atualizado'
|
||||
feed_token_updated: 'Token RSS atualizado'
|
||||
# annotations_reset: Annotations reset
|
||||
# tags_reset: Tags reset
|
||||
# entries_reset: Entries reset
|
||||
|
@ -588,9 +609,11 @@ flashes:
|
|||
entry_starred: 'Entrada destacada'
|
||||
entry_unstarred: 'Entrada não destacada'
|
||||
entry_deleted: 'Entrada apagada'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Tag adicionada'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Importação falhou, por favor tente novamente.'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'Introdu un nou articol'
|
||||
search: 'Căutare'
|
||||
filter_entries: 'Filtrează articolele'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
# export: 'Export'
|
||||
search_form:
|
||||
input_label: 'Introdu căutarea ta'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'Configurație'
|
||||
tab_menu:
|
||||
settings: 'Setări'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Informații despre utilizator'
|
||||
password: 'Parolă'
|
||||
# rules: 'Tagging rules'
|
||||
new_user: 'Crează un utilizator'
|
||||
# reset: 'Reset area'
|
||||
form:
|
||||
save: 'Salvează'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,32 @@ config:
|
|||
# help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
|
||||
# help_language: "You can change the language of wallabag interface."
|
||||
# help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'Feed-urile RSS oferite de wallabag îți permit să-ți citești articolele salvate în reader-ul tău preferat RSS.'
|
||||
token_label: 'RSS-Token'
|
||||
no_token: 'Fără token'
|
||||
token_create: 'Crează-ți token'
|
||||
token_reset: 'Resetează-ți token-ul'
|
||||
rss_links: 'Link-uri RSS'
|
||||
rss_link:
|
||||
feed_links: 'Link-uri RSS'
|
||||
feed_link:
|
||||
unread: 'Unread'
|
||||
starred: 'Starred'
|
||||
archive: 'Archived'
|
||||
# all: 'All'
|
||||
rss_limit: 'Limită RSS'
|
||||
feed_limit: 'Limită RSS'
|
||||
form_user:
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Nume'
|
||||
email_label: 'E-mail'
|
||||
# twoFactorAuthentication_label: 'Two factor authentication'
|
||||
# help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
# title: Delete my account (a.k.a danger zone)
|
||||
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
|
||||
|
@ -159,6 +168,15 @@ config:
|
|||
# and: 'One rule AND another'
|
||||
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
|
||||
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
# default_title: 'Title of the entry'
|
||||
|
@ -353,7 +371,7 @@ quickstart:
|
|||
# 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'
|
||||
# feed: 'Enable RSS feeds'
|
||||
# tagging_rules: 'Write rules to automatically tag your articles'
|
||||
# admin:
|
||||
# title: 'Administration'
|
||||
|
@ -404,6 +422,8 @@ tag:
|
|||
new:
|
||||
# add: 'Add'
|
||||
# placeholder: 'You can add several tags, separated by a comma.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -529,7 +549,8 @@ user:
|
|||
email_label: 'E-mail'
|
||||
# enabled_label: 'Enabled'
|
||||
# last_login_label: 'Last login'
|
||||
# twofactor_label: Two factor authentication
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
# save: Save
|
||||
# delete: Delete
|
||||
# delete_confirm: Are you sure?
|
||||
|
@ -567,10 +588,10 @@ flashes:
|
|||
password_updated: 'Parolă actualizată'
|
||||
password_not_updated_demo: "In demonstration mode, you can't change password for this user."
|
||||
user_updated: 'Informație actualizată'
|
||||
rss_updated: 'Informație RSS actualizată'
|
||||
feed_updated: 'Informație RSS actualizată'
|
||||
# tagging_rules_updated: 'Tagging rules updated'
|
||||
# tagging_rules_deleted: 'Tagging rule deleted'
|
||||
# rss_token_updated: 'RSS token updated'
|
||||
# feed_token_updated: 'RSS token updated'
|
||||
# annotations_reset: Annotations reset
|
||||
# tags_reset: Tags reset
|
||||
# entries_reset: Entries reset
|
||||
|
@ -588,9 +609,11 @@ flashes:
|
|||
entry_starred: 'Articol adăugat la favorite'
|
||||
entry_unstarred: 'Articol șters de la favorite'
|
||||
entry_deleted: 'Articol șters'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
# tag_added: 'Tag added'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
# failed: 'Import failed, please try again.'
|
||||
|
|
|
@ -36,6 +36,7 @@ menu:
|
|||
add_new_entry: 'Добавить новую запись'
|
||||
search: 'Поиск'
|
||||
filter_entries: 'Фильтр записей'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'Экспорт'
|
||||
search_form:
|
||||
input_label: 'Введите текст для поиска'
|
||||
|
@ -52,11 +53,12 @@ config:
|
|||
page_title: 'Настройки'
|
||||
tab_menu:
|
||||
settings: 'Настройки'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'Информация о пользователе'
|
||||
password: 'Пароль'
|
||||
rules: 'Правила настройки простановки тегов'
|
||||
new_user: 'Добавить пользователя'
|
||||
reset: 'Сброс данных'
|
||||
form:
|
||||
save: 'Сохранить'
|
||||
form_settings:
|
||||
|
@ -81,24 +83,31 @@ config:
|
|||
help_reading_speed: "wallabag посчитает сколько времени занимает чтение каждой записи. Вы можете определить здесь, как быстро вы читаете. wallabag пересчитает время чтения для каждой записи."
|
||||
help_language: "Вы можете изменить язык интерфейса wallabag."
|
||||
help_pocket_consumer_key: "Обязательно для импорта из Pocket. Вы можете создать это в Вашем аккаунте на Pocket."
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'RSS фид созданный с помощью wallabag позволяет читать Ваши записи через Ваш любимый RSS агрегатор. Для начала Вам потребуется создать ключ.'
|
||||
token_label: 'RSS ключ'
|
||||
no_token: 'Ключ не задан'
|
||||
token_create: 'Создать ключ'
|
||||
token_reset: 'Пересоздать ключ'
|
||||
rss_links: 'ссылка на RSS'
|
||||
rss_link:
|
||||
feed_links: 'ссылка на RSS'
|
||||
feed_link:
|
||||
unread: 'непрочитанные'
|
||||
starred: 'помеченные'
|
||||
archive: 'архивные'
|
||||
rss_limit: 'Количество записей в фиде'
|
||||
feed_limit: 'Количество записей в фиде'
|
||||
form_user:
|
||||
two_factor_description: "Включить двухфакторную аутентификацию, Вы получите сообщение на указанный email с кодом, при каждом новом непроверенном подключении."
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'Имя'
|
||||
email_label: 'Email'
|
||||
twoFactorAuthentication_label: 'Двухфакторная аутентификация'
|
||||
help_twoFactorAuthentication: "Если Вы включите двухфакторную аутентификацию, то Вы будете получать код на указанный ранее email, каждый раз при входе в wallabag."
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: "Удалить мой аккаунт (или опасная зона)"
|
||||
description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы."
|
||||
|
@ -154,6 +163,15 @@ config:
|
|||
or: 'Одно правило ИЛИ другое'
|
||||
and: 'Одно правило И другое'
|
||||
matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: 'Название записи'
|
||||
|
@ -341,7 +359,7 @@ quickstart:
|
|||
title: 'Настроить приложение'
|
||||
description: 'Чтобы иметь приложение, которое вам подходит, ознакомьтесь с конфигурацией wallabag.'
|
||||
language: 'Выбрать язык и дизайн'
|
||||
rss: 'Включить RSS фид'
|
||||
feed: 'Включить RSS фид'
|
||||
tagging_rules: 'Создать правило для автоматической установки тегов'
|
||||
admin:
|
||||
title: 'Администрирование'
|
||||
|
@ -392,6 +410,8 @@ tag:
|
|||
new:
|
||||
add: 'Добавить'
|
||||
placeholder: 'Вы можете добавить несколько тегов, разделенных запятой.'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
# export:
|
||||
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %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>'
|
||||
|
@ -517,7 +537,8 @@ user:
|
|||
email_label: 'Email'
|
||||
enabled_label: 'Включить'
|
||||
last_login_label: 'Последний вход'
|
||||
twofactor_label: "Двухфакторная аутентификация"
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: "Сохранить"
|
||||
delete: "Удалить"
|
||||
delete_confirm: "Вы уверены?"
|
||||
|
@ -533,10 +554,10 @@ flashes:
|
|||
password_updated: 'Пароль обновлен'
|
||||
password_not_updated_demo: "В режиме демонстрации нельзя изменять пароль для этого пользователя."
|
||||
user_updated: 'Информация обновлена'
|
||||
rss_updated: 'RSS информация обновлена'
|
||||
feed_updated: 'RSS информация обновлена'
|
||||
tagging_rules_updated: 'Правила тегировния обновлены'
|
||||
tagging_rules_deleted: 'Правила тегировния удалены'
|
||||
rss_token_updated: 'RSS ключ обновлен'
|
||||
feed_token_updated: 'RSS ключ обновлен'
|
||||
annotations_reset: "Аннотации сброшены"
|
||||
tags_reset: "Теги сброшены"
|
||||
entries_reset: "Записи сброшены"
|
||||
|
@ -553,9 +574,11 @@ flashes:
|
|||
entry_starred: 'Запись помечена звездочкой'
|
||||
entry_unstarred: 'Пометка звездочкой у записи убрана'
|
||||
entry_deleted: 'Запись удалена'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'Тег добавлен'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'Во время импорта произошла ошибка, повторите попытку.'
|
||||
|
@ -573,4 +596,4 @@ flashes:
|
|||
notice:
|
||||
added: 'Пользователь "%username%" добавлен'
|
||||
updated: 'Пользователь "%username%" обновлен'
|
||||
deleted: 'Пользователь "%username%" удален'
|
||||
deleted: 'Пользователь "%username%" удален'
|
||||
|
|
|
@ -37,6 +37,7 @@ menu:
|
|||
add_new_entry: 'เพิ่มรายการใหม่'
|
||||
search: 'ค้นหา'
|
||||
filter_entries: 'ตัวกรองรายการ'
|
||||
# random_entry: Jump to a random entry from that list
|
||||
export: 'นำข้อมูลออก'
|
||||
search_form:
|
||||
input_label: 'ค้นหาที่นี้'
|
||||
|
@ -53,11 +54,12 @@ config:
|
|||
page_title: 'กำหนดค่า'
|
||||
tab_menu:
|
||||
settings: 'ตั้งค่า'
|
||||
rss: 'RSS'
|
||||
feed: 'RSS'
|
||||
user_info: 'ข้อมูลผู้ใช้'
|
||||
password: 'รหัสผ่าน'
|
||||
rules: 'การแท็กข้อบังคับ'
|
||||
new_user: 'เพิ่มผู้ใช้'
|
||||
reset: 'รีเซ็ตพื้นที่ '
|
||||
form:
|
||||
save: 'บันทึก'
|
||||
form_settings:
|
||||
|
@ -83,25 +85,32 @@ config:
|
|||
help_reading_speed: "wallabag จะคำนวณเวลาการอ่านในแต่ละรายการซึ่งคุณสามารถกำหนดได้ที่นี้,ต้องขอบคุณรายการนี้,หากคุณเป็นนักอ่านที่เร็วหรือช้า wallabag จะทำการคำนวณเวลาที่อ่านใหม่ในแต่ละรายการ"
|
||||
help_language: "คุณสามารถเปลี่ยภาษาของ wallabag interface ได้"
|
||||
help_pocket_consumer_key: "การ้องขอการเก็บการนำข้อมูลเข้า คุณสามารถสร้างบัญชีการเก็บของคุณ"
|
||||
form_rss:
|
||||
form_feed:
|
||||
description: 'RSS จะเก็บเงื่อนไขโดย wallabag ต้องยอมรับการอ่านรายการของคุณกับผู้อ่านที่ชอบ RSS คุณต้องทำเครื่องหมายก่อน'
|
||||
token_label: 'เครื่องหมาย RSS'
|
||||
no_token: 'ไม่มีเครื่องหมาย'
|
||||
token_create: 'สร้างเครื่องหมาย'
|
||||
token_reset: 'ทำเครื่องหมาย'
|
||||
rss_links: 'ลิงค์ RSS'
|
||||
rss_link:
|
||||
feed_links: 'ลิงค์ RSS'
|
||||
feed_link:
|
||||
unread: 'ยังไมได้่อ่าน'
|
||||
starred: 'ทำการแสดง'
|
||||
archive: 'เอกสาร'
|
||||
all: 'ทั้งหมด'
|
||||
rss_limit: 'จำนวนไอเทมที่เก็บ'
|
||||
feed_limit: 'จำนวนไอเทมที่เก็บ'
|
||||
form_user:
|
||||
two_factor_description: "การเปิดใช้งาน two factor authentication คือคุณจะต้องได้รับอีเมลกับ code ที่ยังไม่ตรวจสอบในการเชื่อมต่อ"
|
||||
# two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option."
|
||||
name_label: 'ชื่อ'
|
||||
email_label: 'อีเมล'
|
||||
twoFactorAuthentication_label: 'Two factor authentication'
|
||||
help_twoFactorAuthentication: "ถ้าคุณเปิด 2FA, ในแต่ละช่วงเวลาที่คุณต้องการลงชื่อเข้าใช wallabag, คุณจะต้องได้รับ code จากอีเมล"
|
||||
# emailTwoFactor_label: 'Using email (receive a code by email)'
|
||||
# googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)'
|
||||
# table_method: Method
|
||||
# table_state: State
|
||||
# table_action: Action
|
||||
# state_enabled: Enabled
|
||||
# state_disabled: Disabled
|
||||
# action_email: Use email
|
||||
# action_app: Use OTP App
|
||||
delete:
|
||||
title: ลบบัญชีของฉัน (โซนที่เป็นภัย!)
|
||||
description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก
|
||||
|
@ -159,6 +168,15 @@ config:
|
|||
and: 'หนึ่งข้อบังคับและอื่นๆ'
|
||||
matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>'
|
||||
notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>'
|
||||
otp:
|
||||
# page_title: Two-factor authentication
|
||||
# app:
|
||||
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
|
||||
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
|
||||
# two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
|
||||
# two_factor_code_description_4: 'Test an OTP code from your configured app:'
|
||||
# cancel: Cancel
|
||||
# enable: Enable
|
||||
|
||||
entry:
|
||||
default_title: 'หัวข้อรายการ'
|
||||
|
@ -351,7 +369,7 @@ quickstart:
|
|||
title: 'กำหนดค่าแอพพลิเคชั่น'
|
||||
description: 'ภายใน order จะมี application suit ของคุณ, จะมองหาองค์ประกอบของ wallabag'
|
||||
language: 'เปลี่ยนภาษาและออกแบบ'
|
||||
rss: 'เปิดใช้ RSS'
|
||||
feed: 'เปิดใช้ RSS'
|
||||
tagging_rules: 'เขียนข้อบังคับการแท็กอัตโนมัติของบทความของคุณ'
|
||||
admin:
|
||||
title: 'ผู้ดูแลระบบ'
|
||||
|
@ -402,6 +420,8 @@ tag:
|
|||
new:
|
||||
add: 'เพิ่ม'
|
||||
placeholder: 'คุณสามารถเพิ่มได้หลายแท็ก, จากการแบ่งโดย comma'
|
||||
rename:
|
||||
# placeholder: 'You can update tag name.'
|
||||
|
||||
export:
|
||||
footer_template: '<div style="text-align:center;"><p>ผลิตโดย wallabag กับ %method%</p><p>ให้ทำการเปิด <a href="https://github.com/wallabag/wallabag/issues">ฉบับนี้</a> ถ้าคุณมีข้อบกพร่องif you have trouble with the display of this E-Book on your device.</p></div>'
|
||||
|
@ -527,7 +547,8 @@ user:
|
|||
email_label: 'อีเมล'
|
||||
enabled_label: 'เปิดใช้งาน'
|
||||
last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย'
|
||||
twofactor_label: Two factor authentication
|
||||
# twofactor_email_label: Two factor authentication by email
|
||||
# twofactor_google_label: Two factor authentication by OTP app
|
||||
save: บันทึก
|
||||
delete: ลบ
|
||||
delete_confirm: ตุณแน่ใจหรือไม่?
|
||||
|
@ -565,10 +586,10 @@ flashes:
|
|||
password_updated: 'อัปเดตรหัสผ่าน'
|
||||
password_not_updated_demo: "In demonstration mode, you can't change password for this user."
|
||||
user_updated: 'อัปเดตข้อมูล'
|
||||
rss_updated: 'อัปเดตข้อมูล RSS'
|
||||
feed_updated: 'อัปเดตข้อมูล RSS'
|
||||
tagging_rules_updated: 'อัปเดตการแท็กข้อบังคับ'
|
||||
tagging_rules_deleted: 'การลบข้อบังคับของแท็ก'
|
||||
rss_token_updated: 'อัปเดตเครื่องหมาย RSS '
|
||||
feed_token_updated: 'อัปเดตเครื่องหมาย RSS '
|
||||
annotations_reset: รีเซ็ตหมายเหตุ
|
||||
tags_reset: รีเซ็ตแท็ก
|
||||
entries_reset: รีเซ็ตรายการ
|
||||
|
@ -586,9 +607,11 @@ flashes:
|
|||
entry_starred: 'รายการที่แสดง'
|
||||
entry_unstarred: 'รายการที่ไม่ได้แสดง'
|
||||
entry_deleted: 'รายการที่ถูกลบ'
|
||||
# no_random_entry: 'No article with these criterias was found'
|
||||
tag:
|
||||
notice:
|
||||
tag_added: 'แท็กที่เพิ่ม'
|
||||
# tag_renamed: 'Tag renamed'
|
||||
import:
|
||||
notice:
|
||||
failed: 'นำข้อมูลเข้าล้มเหลว, ลองใหม่อีกครั้ง'
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue