mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-26 19:11:07 +00:00
Merge pull request #1436 from wallabag/v2-register
Public registration & oAuth2 \o/
This commit is contained in:
commit
16dabc3263
82 changed files with 1148 additions and 1350 deletions
|
@ -26,6 +26,8 @@ class AppKernel extends Kernel
|
|||
new Wallabag\ApiBundle\WallabagApiBundle(),
|
||||
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(),
|
||||
new Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle(),
|
||||
new FOS\OAuthServerBundle\FOSOAuthServerBundle(),
|
||||
new Wallabag\UserBundle\WallabagUserBundle(),
|
||||
);
|
||||
|
||||
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
|
||||
|
|
|
@ -110,7 +110,9 @@ fos_rest:
|
|||
routing_loader:
|
||||
default_format: json
|
||||
|
||||
nelmio_api_doc: ~
|
||||
nelmio_api_doc:
|
||||
sandbox:
|
||||
enabled: false
|
||||
|
||||
nelmio_cors:
|
||||
defaults:
|
||||
|
@ -156,4 +158,16 @@ liip_theme:
|
|||
fos_user:
|
||||
db_driver: orm
|
||||
firewall_name: main
|
||||
user_class: Wallabag\CoreBundle\Entity\User
|
||||
user_class: Wallabag\UserBundle\Entity\User
|
||||
registration:
|
||||
confirmation:
|
||||
enabled: true
|
||||
|
||||
fos_oauth_server:
|
||||
db_driver: orm
|
||||
client_class: Wallabag\ApiBundle\Entity\Client
|
||||
access_token_class: Wallabag\ApiBundle\Entity\AccessToken
|
||||
refresh_token_class: Wallabag\ApiBundle\Entity\RefreshToken
|
||||
auth_code_class: Wallabag\ApiBundle\Entity\AuthCode
|
||||
service:
|
||||
user_provider: fos_user.user_manager
|
||||
|
|
|
@ -17,11 +17,6 @@ monolog:
|
|||
type: fingers_crossed
|
||||
action_level: error
|
||||
handler: nested
|
||||
wsse:
|
||||
type: stream
|
||||
path: %kernel.logs_dir%/%kernel.environment%.wsse.log
|
||||
level: error
|
||||
channels: [wsse]
|
||||
nested:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
|
|
|
@ -10,16 +10,6 @@ doc-api:
|
|||
resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
|
||||
prefix: /api/doc
|
||||
|
||||
login:
|
||||
pattern: /login
|
||||
defaults: { _controller: WallabagCoreBundle:Security:login }
|
||||
|
||||
login_check:
|
||||
pattern: /login_check
|
||||
|
||||
logout:
|
||||
path: /logout
|
||||
|
||||
rest :
|
||||
type : rest
|
||||
resource : "routing_rest.yml"
|
||||
|
@ -30,3 +20,9 @@ homepage:
|
|||
defaults: { _controller: WallabagCoreBundle:Entry:showUnread, page : 1 }
|
||||
requirements:
|
||||
page: \d+
|
||||
|
||||
fos_user:
|
||||
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
|
||||
|
||||
fos_oauth_server_token:
|
||||
resource: "@FOSOAuthServerBundle/Resources/config/routing/token.xml"
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
security:
|
||||
encoders:
|
||||
Wallabag\CoreBundle\Entity\User:
|
||||
algorithm: sha1
|
||||
encode_as_base64: false
|
||||
iterations: 1
|
||||
FOS\UserBundle\Model\UserInterface: sha512
|
||||
|
||||
role_hierarchy:
|
||||
ROLE_ADMIN: ROLE_USER
|
||||
|
@ -11,18 +8,23 @@ security:
|
|||
|
||||
providers:
|
||||
administrators:
|
||||
entity: { class: WallabagCoreBundle:User, property: username }
|
||||
entity: { class: WallabagUserBundle:User, property: username }
|
||||
fos_userbundle:
|
||||
id: fos_user.user_provider.username
|
||||
|
||||
# the main part of the security, where you can set up firewalls
|
||||
# for specific sections of your app
|
||||
firewalls:
|
||||
wsse_secured:
|
||||
pattern: /api/.*
|
||||
wsse: true
|
||||
stateless: true
|
||||
anonymous: true
|
||||
oauth_token:
|
||||
pattern: ^/oauth/v2/token
|
||||
security: false
|
||||
|
||||
api:
|
||||
pattern: /api/.*
|
||||
fos_oauth: true
|
||||
stateless: true
|
||||
anonymous: true
|
||||
|
||||
login_firewall:
|
||||
pattern: ^/login$
|
||||
anonymous: ~
|
||||
|
@ -45,9 +47,9 @@ security:
|
|||
target: /
|
||||
|
||||
access_control:
|
||||
- { path: ^/api/salt, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/forgot-password, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/, roles: ROLE_USER }
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
# Learn more about services, parameters and containers at
|
||||
# http://symfony.com/doc/current/book/service_container.html
|
||||
parameters:
|
||||
security.authentication.provider.dao.class: Wallabag\CoreBundle\Security\Authentication\Provider\WallabagAuthenticationProvider
|
||||
security.encoder.digest.class: Wallabag\CoreBundle\Security\Authentication\Encoder\WallabagPasswordEncoder
|
||||
security.validator.user_password.class: Wallabag\CoreBundle\Security\Validator\WallabagUserPasswordValidator
|
||||
lexik_form_filter.get_filter.doctrine_orm.class: Wallabag\CoreBundle\Event\Subscriber\CustomDoctrineORMSubscriber
|
||||
|
||||
services:
|
||||
|
|
|
@ -53,7 +53,8 @@
|
|||
"pagerfanta/pagerfanta": "~1.0.3",
|
||||
"lexik/form-filter-bundle": "~4.0",
|
||||
"j0k3r/graby": "~1.0",
|
||||
"friendsofsymfony/user-bundle": "dev-master"
|
||||
"friendsofsymfony/user-bundle": "dev-master",
|
||||
"friendsofsymfony/oauth-server-bundle": "^1.4@dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-fixtures-bundle": "~2.2.0",
|
||||
|
|
158
composer.lock
generated
158
composer.lock
generated
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "350d05d95be50b6d93e8a046f784e00c",
|
||||
"hash": "7c1f2c88df608eb6e1b4bc7c5ed24acc",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
|
@ -858,6 +858,129 @@
|
|||
],
|
||||
"time": "2014-05-20 12:10:12"
|
||||
},
|
||||
{
|
||||
"name": "friendsofsymfony/oauth-server-bundle",
|
||||
"version": "1.4.2",
|
||||
"target-dir": "FOS/OAuthServerBundle",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfSymfony/FOSOAuthServerBundle.git",
|
||||
"reference": "9e15c229eff547443d686445d629e9356ab0672e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSOAuthServerBundle/zipball/9e15c229eff547443d686445d629e9356ab0672e",
|
||||
"reference": "9e15c229eff547443d686445d629e9356ab0672e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"friendsofsymfony/oauth2-php": "~1.1.0",
|
||||
"php": ">=5.3.3",
|
||||
"symfony/framework-bundle": "~2.1",
|
||||
"symfony/security-bundle": "~2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-bundle": "~1.0",
|
||||
"doctrine/mongodb-odm": "1.0.*@dev",
|
||||
"doctrine/orm": ">=2.2,<2.5-dev",
|
||||
"symfony/class-loader": "~2.1",
|
||||
"symfony/yaml": "~2.1",
|
||||
"willdurand/propel-typehintable-behavior": "1.0.*"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/doctrine-bundle": "*",
|
||||
"doctrine/mongodb-odm-bundle": "*",
|
||||
"propel/propel-bundle": "If you want to use Propel with Symfony2, then you will have to install the PropelBundle",
|
||||
"willdurand/propel-typehintable-behavior": "The Typehintable behavior is useful to add type hints on generated methods, to be compliant with interfaces"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"FOS\\OAuthServerBundle": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Arnaud Le Blanc",
|
||||
"email": "arnaud.lb@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "FriendsOfSymfony Community",
|
||||
"homepage": "https://github.com/FriendsOfSymfony/FOSOAuthServerBundle/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony2 OAuth Server Bundle",
|
||||
"homepage": "http://friendsofsymfony.github.com",
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"server"
|
||||
],
|
||||
"time": "2014-10-31 13:44:14"
|
||||
},
|
||||
{
|
||||
"name": "friendsofsymfony/oauth2-php",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfSymfony/oauth2-php.git",
|
||||
"reference": "23e76537c4a02e666ab4ba5abe67a69a886a0310"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfSymfony/oauth2-php/zipball/23e76537c4a02e666ab4ba5abe67a69a886a0310",
|
||||
"reference": "23e76537c4a02e666ab4ba5abe67a69a886a0310",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"symfony/http-foundation": "~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OAuth2\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Arnaud Le Blanc",
|
||||
"email": "arnaud.lb@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "FriendsOfSymfony Community",
|
||||
"homepage": "https://github.com/FriendsOfSymfony/oauth2-php/contributors"
|
||||
}
|
||||
],
|
||||
"description": "OAuth2 library",
|
||||
"homepage": "https://github.com/FriendsOfSymfony/oauth2-php",
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2"
|
||||
],
|
||||
"time": "2014-11-03 10:21:20"
|
||||
},
|
||||
{
|
||||
"name": "friendsofsymfony/rest-bundle",
|
||||
"version": "1.7.1",
|
||||
|
@ -2787,12 +2910,12 @@
|
|||
"version": "v2.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/AsseticBundle.git",
|
||||
"url": "https://github.com/symfony/assetic-bundle.git",
|
||||
"reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/AsseticBundle/zipball/3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5",
|
||||
"url": "https://api.github.com/repos/symfony/assetic-bundle/zipball/3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5",
|
||||
"reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5",
|
||||
"shasum": ""
|
||||
},
|
||||
|
@ -2857,12 +2980,12 @@
|
|||
"version": "v2.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/MonologBundle.git",
|
||||
"url": "https://github.com/symfony/monolog-bundle.git",
|
||||
"reference": "9320b6863404c70ebe111e9040dab96f251de7ac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/MonologBundle/zipball/9320b6863404c70ebe111e9040dab96f251de7ac",
|
||||
"url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/9320b6863404c70ebe111e9040dab96f251de7ac",
|
||||
"reference": "9320b6863404c70ebe111e9040dab96f251de7ac",
|
||||
"shasum": ""
|
||||
},
|
||||
|
@ -2916,12 +3039,12 @@
|
|||
"version": "v2.3.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/SwiftmailerBundle.git",
|
||||
"url": "https://github.com/symfony/swiftmailer-bundle.git",
|
||||
"reference": "970b13d01871207e81d17b17ddda025e7e21e797"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/SwiftmailerBundle/zipball/970b13d01871207e81d17b17ddda025e7e21e797",
|
||||
"url": "https://api.github.com/repos/symfony/swiftmailer-bundle/zipball/970b13d01871207e81d17b17ddda025e7e21e797",
|
||||
"reference": "970b13d01871207e81d17b17ddda025e7e21e797",
|
||||
"shasum": ""
|
||||
},
|
||||
|
@ -2970,20 +3093,20 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/symfony",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/symfony.git",
|
||||
"reference": "619528a274647cffc1792063c3ea04c4fa8266a0"
|
||||
"reference": "1fdf23fe28876844b887b0e1935c9adda43ee645"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/symfony/zipball/619528a274647cffc1792063c3ea04c4fa8266a0",
|
||||
"reference": "619528a274647cffc1792063c3ea04c4fa8266a0",
|
||||
"url": "https://api.github.com/repos/symfony/symfony/zipball/1fdf23fe28876844b887b0e1935c9adda43ee645",
|
||||
"reference": "1fdf23fe28876844b887b0e1935c9adda43ee645",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/common": "~2.4",
|
||||
"doctrine/common": "~2.3",
|
||||
"php": ">=5.3.9",
|
||||
"psr/log": "~1.0",
|
||||
"twig/twig": "~1.20|~2.0"
|
||||
|
@ -3036,9 +3159,9 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"doctrine/data-fixtures": "1.0.*",
|
||||
"doctrine/dbal": "~2.4",
|
||||
"doctrine/dbal": "~2.2",
|
||||
"doctrine/doctrine-bundle": "~1.2",
|
||||
"doctrine/orm": "~2.4,>=2.4.5",
|
||||
"doctrine/orm": "~2.2,>=2.2.3",
|
||||
"egulias/email-validator": "~1.2",
|
||||
"ircmaxell/password-compat": "~1.0",
|
||||
"monolog/monolog": "~1.11",
|
||||
|
@ -3088,7 +3211,7 @@
|
|||
"keywords": [
|
||||
"framework"
|
||||
],
|
||||
"time": "2015-09-25 11:16:52"
|
||||
"time": "2015-09-08 14:26:39"
|
||||
},
|
||||
{
|
||||
"name": "tecnickcom/tcpdf",
|
||||
|
@ -4488,7 +4611,8 @@
|
|||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"friendsofsymfony/user-bundle": 20
|
||||
"friendsofsymfony/user-bundle": 20,
|
||||
"friendsofsymfony/oauth-server-bundle": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
|
|
|
@ -4,8 +4,8 @@ lock '3.4.0'
|
|||
set :application, 'wallabag'
|
||||
set :repo_url, 'git@github.com:wallabag/wallabag.git'
|
||||
|
||||
set :ssh_user, 'ssh_user'
|
||||
server 'server_ip', user: fetch(:ssh_user), roles: %w{web app db}
|
||||
set :ssh_user, 'framasoft_bag'
|
||||
server '78.46.248.87', user: fetch(:ssh_user), roles: %w{web app db}
|
||||
|
||||
set :scm, :git
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
set :branch, 'v2'
|
||||
set :deploy_to, '/var/www/'
|
||||
set :deploy_to, '/var/www/v2.wallabag.org/web/'
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Wallabag\ApiBundle\Controller;
|
||||
|
||||
use FOS\RestBundle\Controller\FOSRestController;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
|
@ -11,7 +11,7 @@ use Wallabag\CoreBundle\Entity\Tag;
|
|||
use Hateoas\Configuration\Route;
|
||||
use Hateoas\Representation\Factory\PagerfantaFactory;
|
||||
|
||||
class WallabagRestController extends Controller
|
||||
class WallabagRestController extends FOSRestController
|
||||
{
|
||||
/**
|
||||
* @param Entry $entry
|
||||
|
@ -38,29 +38,11 @@ class WallabagRestController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve salt for a giver user.
|
||||
*
|
||||
* @ApiDoc(
|
||||
* parameters={
|
||||
* {"name"="username", "dataType"="string", "required"=true, "description"="username"}
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSaltAction($username)
|
||||
private function validateAuthentication()
|
||||
{
|
||||
$user = $this
|
||||
->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByUsername($username);
|
||||
|
||||
if (is_null($user)) {
|
||||
throw $this->createNotFoundException();
|
||||
if (false === $this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
|
||||
throw new AccessDeniedException();
|
||||
}
|
||||
|
||||
return array($user->getSalt() ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,6 +64,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function getEntriesAction(Request $request)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$isArchived = $request->query->get('archive');
|
||||
$isStarred = $request->query->get('star');
|
||||
$sort = $request->query->get('sort', 'created');
|
||||
|
@ -122,7 +106,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function getEntryAction(Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$json = $this->get('serializer')->serialize($entry, 'json');
|
||||
|
||||
|
@ -144,6 +129,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function postEntriesAction(Request $request)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$url = $request->request->get('url');
|
||||
|
||||
$entry = $this->get('wallabag_core.content_proxy')->updateEntry(
|
||||
|
@ -184,7 +171,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function patchEntriesAction(Entry $entry, Request $request)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$title = $request->request->get('title');
|
||||
$isArchived = $request->request->get('is_archived');
|
||||
|
@ -228,7 +216,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function deleteEntriesAction(Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($entry);
|
||||
|
@ -250,7 +239,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function getEntriesTagsAction(Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$json = $this->get('serializer')->serialize($entry->getTags(), 'json');
|
||||
|
||||
|
@ -271,7 +261,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function postEntriesTagsAction(Request $request, Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$tags = $request->request->get('tags', '');
|
||||
if (!empty($tags)) {
|
||||
|
@ -299,7 +290,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function deleteEntriesTagsAction(Entry $entry, Tag $tag)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$entry->removeTag($tag);
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
@ -318,6 +310,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function getTagsAction()
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
$json = $this->get('serializer')->serialize($this->getUser()->getTags(), 'json');
|
||||
|
||||
return $this->renderJsonResponse($json);
|
||||
|
@ -334,7 +327,8 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function deleteTagAction(Tag $tag)
|
||||
{
|
||||
$this->validateUserAccess($tag->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($tag->getUser()->getId());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($tag);
|
||||
|
@ -350,12 +344,12 @@ class WallabagRestController extends Controller
|
|||
* If not, throw exception. It means a user try to access information from an other user.
|
||||
*
|
||||
* @param int $requestUserId User id from the requested source
|
||||
* @param int $currentUserId User id from the retrieved source
|
||||
*/
|
||||
private function validateUserAccess($requestUserId, $currentUserId)
|
||||
private function validateUserAccess($requestUserId)
|
||||
{
|
||||
if ($requestUserId != $currentUserId) {
|
||||
throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$currentUserId);
|
||||
$user = $this->get('security.context')->getToken()->getUser();
|
||||
if ($requestUserId != $user->getId()) {
|
||||
throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
|
||||
|
||||
class WsseFactory implements SecurityFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||
{
|
||||
$providerId = 'security.authentication.provider.wsse.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new DefinitionDecorator('wsse.security.authentication.provider'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
;
|
||||
|
||||
$listenerId = 'security.authentication.listener.wsse.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('wsse.security.authentication.listener'));
|
||||
|
||||
return array($providerId, $listenerId, $defaultEntryPoint);
|
||||
}
|
||||
|
||||
public function getPosition()
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'wsse';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -3,9 +3,7 @@
|
|||
namespace Wallabag\ApiBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
|
||||
class WallabagApiExtension extends Extension
|
||||
{
|
||||
|
@ -13,9 +11,6 @@ class WallabagApiExtension extends Extension
|
|||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
}
|
||||
|
||||
public function getAlias()
|
||||
|
|
31
src/Wallabag/ApiBundle/Entity/AccessToken.php
Normal file
31
src/Wallabag/ApiBundle/Entity/AccessToken.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_access_tokens")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class AccessToken extends BaseAccessToken
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Client")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
31
src/Wallabag/ApiBundle/Entity/AuthCode.php
Normal file
31
src/Wallabag/ApiBundle/Entity/AuthCode.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_auth_codes")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class AuthCode extends BaseAuthCode
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Client")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
25
src/Wallabag/ApiBundle/Entity/Client.php
Normal file
25
src/Wallabag/ApiBundle/Entity/Client.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\Client as BaseClient;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_clients")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
31
src/Wallabag/ApiBundle/Entity/RefreshToken.php
Normal file
31
src/Wallabag/ApiBundle/Entity/RefreshToken.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_refresh_tokens")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class RefreshToken extends BaseRefreshToken
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Client")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
services:
|
||||
wsse.security.authentication.provider:
|
||||
class: Wallabag\ApiBundle\Security\Authentication\Provider\WsseProvider
|
||||
public: false
|
||||
arguments: ['', '%kernel.cache_dir%/security/nonces']
|
||||
|
||||
wsse.security.authentication.listener:
|
||||
class: Wallabag\ApiBundle\Security\Firewall\WsseListener
|
||||
public: false
|
||||
tags:
|
||||
- { name: monolog.logger, channel: wsse }
|
||||
arguments: ['@security.context', '@security.authentication.manager', '@logger']
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Security\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\NonceExpiredException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken;
|
||||
|
||||
class WsseProvider implements AuthenticationProviderInterface
|
||||
{
|
||||
private $userProvider;
|
||||
private $cacheDir;
|
||||
|
||||
public function __construct(UserProviderInterface $userProvider, $cacheDir)
|
||||
{
|
||||
$this->userProvider = $userProvider;
|
||||
$this->cacheDir = $cacheDir;
|
||||
|
||||
// If cache directory does not exist we create it
|
||||
if (!is_dir($this->cacheDir)) {
|
||||
mkdir($this->cacheDir, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function authenticate(TokenInterface $token)
|
||||
{
|
||||
$user = $this->userProvider->loadUserByUsername($token->getUsername());
|
||||
|
||||
if (!$user) {
|
||||
throw new AuthenticationException('Bad credentials. Did you forgot your username?');
|
||||
}
|
||||
|
||||
if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) {
|
||||
$authenticatedToken = new WsseUserToken($user->getRoles());
|
||||
$authenticatedToken->setUser($user);
|
||||
|
||||
return $authenticatedToken;
|
||||
}
|
||||
|
||||
throw new AuthenticationException('The WSSE authentication failed.');
|
||||
}
|
||||
|
||||
protected function validateDigest($digest, $nonce, $created, $secret)
|
||||
{
|
||||
// Check created time is not in the future
|
||||
if (strtotime($created) > time()) {
|
||||
throw new AuthenticationException('Back to the future...');
|
||||
}
|
||||
|
||||
// Expire timestamp after 5 minutes
|
||||
if (time() - strtotime($created) > 300) {
|
||||
throw new AuthenticationException('Too late for this timestamp... Watch your watch.');
|
||||
}
|
||||
|
||||
// Validate nonce is unique within 5 minutes
|
||||
if (file_exists($this->cacheDir.'/'.$nonce) && file_get_contents($this->cacheDir.'/'.$nonce) + 300 > time()) {
|
||||
throw new NonceExpiredException('Previously used nonce detected');
|
||||
}
|
||||
|
||||
file_put_contents($this->cacheDir.'/'.$nonce, time());
|
||||
|
||||
// Validate Secret
|
||||
$expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true));
|
||||
|
||||
if ($digest !== $expected) {
|
||||
throw new AuthenticationException('Bad credentials ! Digest is not as expected.');
|
||||
}
|
||||
|
||||
return $digest === $expected;
|
||||
}
|
||||
|
||||
public function supports(TokenInterface $token)
|
||||
{
|
||||
return $token instanceof WsseUserToken;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Security\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
|
||||
|
||||
class WsseUserToken extends AbstractToken
|
||||
{
|
||||
public $created;
|
||||
public $digest;
|
||||
public $nonce;
|
||||
|
||||
public function __construct(array $roles = array())
|
||||
{
|
||||
parent::__construct($roles);
|
||||
|
||||
$this->setAuthenticated(count($roles) > 0);
|
||||
}
|
||||
|
||||
public function getCredentials()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Security\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\SecurityContextInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class WsseListener implements ListenerInterface
|
||||
{
|
||||
protected $securityContext;
|
||||
protected $authenticationManager;
|
||||
protected $logger;
|
||||
|
||||
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger)
|
||||
{
|
||||
$this->securityContext = $securityContext;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function handle(GetResponseEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/';
|
||||
if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$token = new WsseUserToken();
|
||||
$token->setUser($matches[1]);
|
||||
|
||||
$token->digest = $matches[2];
|
||||
$token->nonce = $matches[3];
|
||||
$token->created = $matches[4];
|
||||
|
||||
try {
|
||||
$authToken = $this->authenticationManager->authenticate($token);
|
||||
|
||||
$this->securityContext->setToken($authToken);
|
||||
|
||||
return;
|
||||
} catch (AuthenticationException $failed) {
|
||||
$failedMessage = 'WSSE Login failed for '.$token->getUsername().'. Why ? '.$failed->getMessage();
|
||||
$this->logger->err($failedMessage);
|
||||
|
||||
// Deny authentication with a '403 Forbidden' HTTP response
|
||||
$response = new Response();
|
||||
$response->setStatusCode(403);
|
||||
$response->setContent($failedMessage);
|
||||
$event->setResponse($response);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
46
src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php
Normal file
46
src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Tests;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
|
||||
abstract class AbstractControllerTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $client = null;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->client = $this->createAuthorizedClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Client
|
||||
*/
|
||||
protected function createAuthorizedClient()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$container = $client->getContainer();
|
||||
|
||||
$session = $container->get('session');
|
||||
/** @var $userManager \FOS\UserBundle\Doctrine\UserManager */
|
||||
$userManager = $container->get('fos_user.user_manager');
|
||||
/** @var $loginManager \FOS\UserBundle\Security\LoginManager */
|
||||
$loginManager = $container->get('fos_user.security.login_manager');
|
||||
$firewallName = $container->getParameter('fos_user.firewall_name');
|
||||
|
||||
$user = $userManager->findUserBy(array('username' => 'admin'));
|
||||
$loginManager->loginUser($firewallName, $user);
|
||||
|
||||
// save the login token into the session and put it in a cookie
|
||||
$container->get('session')->set('_security_'.$firewallName,
|
||||
serialize($container->get('security.context')->getToken()));
|
||||
$container->get('session')->save();
|
||||
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
|
@ -2,99 +2,15 @@
|
|||
|
||||
namespace Wallabag\ApiBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Wallabag\ApiBundle\Tests\AbstractControllerTest;
|
||||
|
||||
class WallabagRestControllerTest extends WebTestCase
|
||||
class WallabagRestControllerTest extends AbstractControllerTest
|
||||
{
|
||||
protected static $salt;
|
||||
|
||||
/**
|
||||
* Grab the salt once and store it to be available for all tests.
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$client = self::createClient();
|
||||
|
||||
$user = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
self::$salt = $user->getSalt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTTP headers for authenticate user on API.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function generateHeaders($username, $password)
|
||||
{
|
||||
$encryptedPassword = sha1($password.$username.self::$salt);
|
||||
$nonce = substr(md5(uniqid('nonce_', true)), 0, 16);
|
||||
|
||||
$now = new \DateTime('now', new \DateTimeZone('UTC'));
|
||||
$created = (string) $now->format('Y-m-d\TH:i:s\Z');
|
||||
$digest = base64_encode(sha1(base64_decode($nonce).$created.$encryptedPassword, true));
|
||||
|
||||
return array(
|
||||
'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"',
|
||||
'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="'.$username.'", PasswordDigest="'.$digest.'", Nonce="'.$nonce.'", Created="'.$created.'"',
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSalt()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$client->request('GET', '/api/salts/admin.json');
|
||||
|
||||
$user = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey(0, $content);
|
||||
$this->assertEquals($user->getSalt(), $content[0]);
|
||||
|
||||
$client->request('GET', '/api/salts/notfound.json');
|
||||
$this->assertEquals(404, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testWithBadHeaders()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
|
||||
$entry = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByIsArchived(false);
|
||||
|
||||
if (!$entry) {
|
||||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$badHeaders = array(
|
||||
'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"',
|
||||
'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="admin", PasswordDigest="Wr0ngDig3st", Nonce="n0Nc3", Created="2015-01-01T13:37:00Z"',
|
||||
);
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $badHeaders);
|
||||
$this->assertEquals(403, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testGetOneEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneBy(array('user' => 1, 'isArchived' => false));
|
||||
|
@ -103,18 +19,17 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'.json');
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertEquals($entry->getTitle(), $content['title']);
|
||||
$this->assertEquals($entry->getUrl(), $content['url']);
|
||||
$this->assertCount(count($entry->getTags()), $content['tags']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -123,10 +38,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetOneEntryWrongUser()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneBy(array('user' => 2, 'isArchived' => false));
|
||||
|
@ -135,21 +47,18 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'.json');
|
||||
|
||||
$this->assertEquals(403, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(403, $this->client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testGetEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/entries');
|
||||
|
||||
$client->request('GET', '/api/entries', array(), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
|
@ -158,7 +67,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -167,14 +76,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetStarredEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'));
|
||||
|
||||
$client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
|
@ -183,7 +89,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -192,14 +98,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetArchiveEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/entries', array('archive' => 1));
|
||||
|
||||
$client->request('GET', '/api/entries', array('archive' => 1), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
|
@ -208,7 +111,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -217,10 +120,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testDeleteEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
|
@ -229,36 +129,31 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertEquals($entry->getTitle(), $content['title']);
|
||||
$this->assertEquals($entry->getUrl(), $content['url']);
|
||||
|
||||
// We'll try to delete this entry again
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json');
|
||||
|
||||
$client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
|
||||
$this->assertEquals(404, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(404, $this->client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testPostEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$client->request('POST', '/api/entries.json', array(
|
||||
$this->client->request('POST', '/api/entries.json', array(
|
||||
'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html',
|
||||
'tags' => 'google',
|
||||
), array(), $headers);
|
||||
));
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThan(0, $content['id']);
|
||||
$this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']);
|
||||
|
@ -269,10 +164,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testPatchEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
|
@ -284,16 +176,16 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
// hydrate the tags relations
|
||||
$nbTags = count($entry->getTags());
|
||||
|
||||
$client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array(
|
||||
$this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array(
|
||||
'title' => 'New awesome title',
|
||||
'tags' => 'new tag '.uniqid(),
|
||||
'star' => true,
|
||||
'archive' => false,
|
||||
), array(), $headers);
|
||||
));
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertEquals($entry->getId(), $content['id']);
|
||||
$this->assertEquals($entry->getUrl(), $content['url']);
|
||||
|
@ -303,10 +195,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetTagsEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneWithTags(1);
|
||||
|
@ -322,17 +211,14 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel());
|
||||
}
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'/tags', array(), array(), $headers);
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'/tags');
|
||||
|
||||
$this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $client->getResponse()->getContent());
|
||||
$this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $this->client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testPostTagsOnEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
|
@ -345,16 +231,16 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
$newTags = 'tag1,tag2,tag3';
|
||||
|
||||
$client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags), array(), $headers);
|
||||
$this->client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags));
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('tags', $content);
|
||||
$this->assertEquals($nbTags + 3, count($content['tags']));
|
||||
|
||||
$entryDB = $client->getContainer()
|
||||
$entryDB = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->find($entry->getId());
|
||||
|
@ -369,15 +255,13 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
}
|
||||
}
|
||||
|
||||
public function testDeleteOneTagEntrie()
|
||||
public function testDeleteOneTagEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
->findOneWithTags(1);
|
||||
$entry = $entry[0];
|
||||
|
||||
if (!$entry) {
|
||||
$this->markTestSkipped('No content found in db.');
|
||||
|
@ -387,11 +271,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$nbTags = count($entry->getTags());
|
||||
$tag = $entry->getTags()[0];
|
||||
|
||||
$client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('tags', $content);
|
||||
$this->assertEquals($nbTags - 1, count($content['tags']));
|
||||
|
@ -399,14 +283,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetUserTags()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/tags.json');
|
||||
|
||||
$client->request('GET', '/api/tags.json', array(), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThan(0, $content);
|
||||
$this->assertArrayHasKey('id', $content[0]);
|
||||
|
@ -420,14 +301,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
*/
|
||||
public function testDeleteUserTag($tag)
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json');
|
||||
|
||||
$client->request('DELETE', '/api/tags/'.$tag['id'].'.json', array(), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('label', $content);
|
||||
$this->assertEquals($tag['label'], $content['label']);
|
||||
|
|
|
@ -3,16 +3,7 @@
|
|||
namespace Wallabag\ApiBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Wallabag\ApiBundle\DependencyInjection\Security\Factory\WsseFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class WallabagApiBundle extends Bundle
|
||||
{
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$extension = $container->getExtension('security');
|
||||
$extension->addSecurityListenerFactory(new WsseFactory());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use Symfony\Component\Console\Input\InputOption;
|
|||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
|
||||
class InstallCommand extends ContainerAwareCommand
|
||||
|
@ -188,9 +188,10 @@ class InstallCommand extends ContainerAwareCommand
|
|||
|
||||
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
|
||||
|
||||
$user = new User();
|
||||
$userManager = $this->getContainer()->get('fos_user.user_manager');
|
||||
$user = $userManager->createUser();
|
||||
$user->setUsername($dialog->ask($this->defaultOutput, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setPassword($dialog->ask($this->defaultOutput, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setPlainPassword($dialog->ask($this->defaultOutput, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setEmail($dialog->ask($this->defaultOutput, '<question>Email:</question>', ''));
|
||||
$user->setEnabled(true);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
|||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
|
||||
use Wallabag\CoreBundle\Form\Type\UserInformationType;
|
||||
use Wallabag\CoreBundle\Form\Type\NewUserType;
|
||||
|
@ -25,6 +25,7 @@ class ConfigController extends Controller
|
|||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$config = $this->getConfig();
|
||||
$userManager = $this->container->get('fos_user.user_manager');
|
||||
$user = $this->getUser();
|
||||
|
||||
// handle basic config detail (this form is defined as a service)
|
||||
|
@ -52,9 +53,8 @@ class ConfigController extends Controller
|
|||
$pwdForm->handleRequest($request);
|
||||
|
||||
if ($pwdForm->isValid()) {
|
||||
$user->setPassword($pwdForm->get('new_password')->getData());
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
$user->setPlainPassword($pwdForm->get('new_password')->getData());
|
||||
$userManager->updateUser($user, true);
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
|
@ -69,8 +69,7 @@ class ConfigController extends Controller
|
|||
$userForm->handleRequest($request);
|
||||
|
||||
if ($userForm->isValid()) {
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
$userManager->updateUser($user, true);
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
|
@ -97,14 +96,14 @@ class ConfigController extends Controller
|
|||
}
|
||||
|
||||
// handle adding new user
|
||||
$newUser = new User();
|
||||
$newUser = $userManager->createUser();
|
||||
// enable created user by default
|
||||
$newUser->setEnabled(true);
|
||||
$newUserForm = $this->createForm(new NewUserType(), $newUser, array('validation_groups' => array('Profile')));
|
||||
$newUserForm->handleRequest($request);
|
||||
|
||||
if ($newUserForm->isValid()) {
|
||||
$em->persist($newUser);
|
||||
if ($newUserForm->isValid() && $this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$userManager->updateUser($newUser, true);
|
||||
|
||||
$config = new Config($newUser);
|
||||
$config->setTheme($this->container->getParameter('theme'));
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Wallabag\CoreBundle\Controller;
|
|||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
|
@ -16,7 +16,7 @@ class RssController extends Controller
|
|||
* Shows unread entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"})
|
||||
* @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter")
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@ class RssController extends Controller
|
|||
* Shows read entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/archive.xml", name="archive_rss")
|
||||
* @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter")
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
|
@ -42,7 +42,7 @@ class RssController extends Controller
|
|||
* Shows starred entries for current user.
|
||||
*
|
||||
* @Route("/{username}/{token}/starred.xml", name="starred_rss")
|
||||
* @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter")
|
||||
* @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter")
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\SecurityContext;
|
||||
use Wallabag\CoreBundle\Form\Type\ResetPasswordType;
|
||||
|
||||
class SecurityController extends Controller
|
||||
{
|
||||
public function loginAction(Request $request)
|
||||
{
|
||||
$session = $request->getSession();
|
||||
// get the login error if there is one
|
||||
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
|
||||
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
|
||||
} else {
|
||||
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
|
||||
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
|
||||
}
|
||||
|
||||
return $this->render('WallabagCoreBundle:Security:login.html.twig', array(
|
||||
// last username entered by the user
|
||||
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
|
||||
'error' => $error,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request forgot password: show form.
|
||||
*
|
||||
* @Route("/forgot-password", name="forgot_password")
|
||||
*
|
||||
* @Method({"GET", "POST"})
|
||||
*/
|
||||
public function forgotPasswordAction(Request $request)
|
||||
{
|
||||
$form = $this->createForm('forgot_password');
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$user = $this->getDoctrine()->getRepository('WallabagCoreBundle:User')->findOneByEmail($form->get('email')->getData());
|
||||
|
||||
// generate "hard" token
|
||||
$user->setConfirmationToken(rtrim(strtr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), '+/', '-_'), '='));
|
||||
$user->setPasswordRequestedAt(new \DateTime());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
|
||||
$message = \Swift_Message::newInstance()
|
||||
->setSubject('Reset Password')
|
||||
->setFrom($this->container->getParameter('from_email'))
|
||||
->setTo($user->getEmail())
|
||||
->setBody($this->renderView('WallabagCoreBundle:Mail:forgotPassword.txt.twig', array(
|
||||
'username' => $user->getUsername(),
|
||||
'confirmationUrl' => $this->generateUrl('forgot_password_reset', array('token' => $user->getConfirmationToken()), true),
|
||||
)))
|
||||
;
|
||||
$this->get('mailer')->send($message);
|
||||
|
||||
return $this->redirect($this->generateUrl('forgot_password_check_email',
|
||||
array('email' => $this->getObfuscatedEmail($user->getEmail()))
|
||||
));
|
||||
}
|
||||
|
||||
return $this->render('WallabagCoreBundle:Security:forgotPassword.html.twig', array(
|
||||
'form' => $form->createView(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the user to check his email provider.
|
||||
*
|
||||
* @Route("/forgot-password/check-email", name="forgot_password_check_email")
|
||||
*
|
||||
* @Method({"GET"})
|
||||
*/
|
||||
public function checkEmailAction(Request $request)
|
||||
{
|
||||
$email = $request->query->get('email');
|
||||
|
||||
if (empty($email)) {
|
||||
// the user does not come from the forgotPassword action
|
||||
return $this->redirect($this->generateUrl('forgot_password'));
|
||||
}
|
||||
|
||||
return $this->render('WallabagCoreBundle:Security:checkEmail.html.twig', array(
|
||||
'email' => $email,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset user password.
|
||||
*
|
||||
* @Route("/forgot-password/{token}", name="forgot_password_reset")
|
||||
*
|
||||
* @Method({"GET", "POST"})
|
||||
*/
|
||||
public function resetAction(Request $request, $token)
|
||||
{
|
||||
$user = $this->getDoctrine()->getRepository('WallabagCoreBundle:User')->findOneByConfirmationToken($token);
|
||||
|
||||
if (null === $user) {
|
||||
throw $this->createNotFoundException(sprintf('No user found with token "%s"', $token));
|
||||
}
|
||||
|
||||
$form = $this->createForm(new ResetPasswordType());
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$user->setPassword($form->get('new_password')->getData());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
'The password has been reset successfully'
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('login'));
|
||||
}
|
||||
|
||||
return $this->render('WallabagCoreBundle:Security:reset.html.twig', array(
|
||||
'token' => $token,
|
||||
'form' => $form->createView(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the truncated email displayed when requesting the resetting.
|
||||
*
|
||||
* Keeping only the part following @ in the address.
|
||||
*
|
||||
* @param string $email
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getObfuscatedEmail($email)
|
||||
{
|
||||
if (false !== $pos = strpos($email, '@')) {
|
||||
$email = '...'.substr($email, $pos);
|
||||
}
|
||||
|
||||
return $email;
|
||||
}
|
||||
}
|
|
@ -72,14 +72,14 @@ class Config
|
|||
private $rssLimit;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="User", inversedBy="config")
|
||||
* @ORM\OneToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="config")
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/*
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
public function __construct(\Wallabag\UserBundle\Entity\User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
@ -169,11 +169,11 @@ class Config
|
|||
/**
|
||||
* Set user.
|
||||
*
|
||||
* @param \Wallabag\CoreBundle\Entity\User $user
|
||||
* @param User $user
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function setUser(\Wallabag\CoreBundle\Entity\User $user = null)
|
||||
public function setUser(User $user = null)
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
|
@ -183,7 +183,7 @@ class Config
|
|||
/**
|
||||
* Get user.
|
||||
*
|
||||
* @return \Wallabag\CoreBundle\Entity\User
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Hateoas\Configuration\Annotation as Hateoas;
|
||||
use JMS\Serializer\Annotation\XmlRoot;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
/**
|
||||
* Entry.
|
||||
|
@ -129,7 +130,7 @@ class Entry
|
|||
private $isPublic;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="User", inversedBy="entries")
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="entries")
|
||||
*/
|
||||
private $user;
|
||||
|
||||
|
@ -142,7 +143,7 @@ class Entry
|
|||
/*
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
public function __construct(\Wallabag\UserBundle\Entity\User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->tags = new ArrayCollection();
|
||||
|
|
|
@ -42,11 +42,11 @@ class Tag
|
|||
private $entries;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="User", inversedBy="tags")
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="tags")
|
||||
*/
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
public function __construct(\Wallabag\UserBundle\Entity\User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->entries = new ArrayCollection();
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use FOS\UserBundle\Event\FilterUserResponseEvent;
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
|
||||
class RegistrationConfirmedListener implements EventSubscriberInterface
|
||||
{
|
||||
private $em;
|
||||
private $theme;
|
||||
private $itemsOnPage;
|
||||
private $rssLimit;
|
||||
private $language;
|
||||
|
||||
public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->theme = $theme;
|
||||
$this->itemsOnPage = $itemsOnPage;
|
||||
$this->rssLimit = $rssLimit;
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
FOSUserEvents::REGISTRATION_CONFIRMED => 'authenticate',
|
||||
);
|
||||
}
|
||||
|
||||
public function authenticate(FilterUserResponseEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null)
|
||||
{
|
||||
if (!$event->getUser()->isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = new Config($event->getUser());
|
||||
$config->setTheme($this->theme);
|
||||
$config->setItemsPerPage($this->itemsOnPage);
|
||||
$config->setRssLimit($this->rssLimit);
|
||||
$config->setLanguage($this->language);
|
||||
$this->em->persist($config);
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
|||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
class EntryFilterType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
use Symfony\Component\Validator\ExecutionContextInterface;
|
||||
use Doctrine\Bundle\DoctrineBundle\Registry;
|
||||
|
||||
class ForgotPasswordType extends AbstractType
|
||||
{
|
||||
private $doctrine = null;
|
||||
|
||||
public function __construct(Registry $doctrine)
|
||||
{
|
||||
$this->doctrine = $doctrine;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('email', 'email', array(
|
||||
'required' => true,
|
||||
'constraints' => array(
|
||||
new Constraints\Email(),
|
||||
new Constraints\NotBlank(),
|
||||
new Constraints\Callback(array(array($this, 'validateEmail'))),
|
||||
),
|
||||
))
|
||||
;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'forgot_password';
|
||||
}
|
||||
|
||||
public function validateEmail($email, ExecutionContextInterface $context)
|
||||
{
|
||||
$user = $this->doctrine
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByEmail($email);
|
||||
|
||||
if (!$user) {
|
||||
$context->addViolationAt(
|
||||
'email',
|
||||
'No user found with this email',
|
||||
array(),
|
||||
$email
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,8 @@ class NewUserType extends AbstractType
|
|||
{
|
||||
$builder
|
||||
->add('username', 'text', array('required' => true))
|
||||
->add('password', 'password', array(
|
||||
->add('plainPassword', 'repeated', array(
|
||||
'type' => 'password',
|
||||
'constraints' => array(
|
||||
new Constraints\Length(array(
|
||||
'min' => 8,
|
||||
|
@ -30,7 +31,7 @@ class NewUserType extends AbstractType
|
|||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults(array(
|
||||
'data_class' => 'Wallabag\CoreBundle\Entity\User',
|
||||
'data_class' => 'Wallabag\UserBundle\Entity\User',
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
|
||||
class ResetPasswordType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('new_password', 'repeated', array(
|
||||
'type' => 'password',
|
||||
'invalid_message' => 'The password fields must match.',
|
||||
'required' => true,
|
||||
'first_options' => array('label' => 'New password'),
|
||||
'second_options' => array('label' => 'Repeat new password'),
|
||||
'constraints' => array(
|
||||
new Constraints\Length(array(
|
||||
'min' => 8,
|
||||
'minMessage' => 'Password should by at least 8 chars long',
|
||||
)),
|
||||
new Constraints\NotBlank(),
|
||||
),
|
||||
))
|
||||
;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'change_passwd';
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ class UserInformationType extends AbstractType
|
|||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults(array(
|
||||
'data_class' => 'Wallabag\CoreBundle\Entity\User',
|
||||
'data_class' => 'Wallabag\UserBundle\Entity\User',
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Wallabag\CoreBundle\Helper;
|
|||
|
||||
use Liip\ThemeBundle\Helper\DeviceDetectionInterface;
|
||||
use Symfony\Component\Security\Core\SecurityContextInterface;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
/**
|
||||
* This class intend to detect the active theme for the logged in user.
|
||||
|
|
|
@ -7,7 +7,7 @@ use Doctrine\Common\Persistence\ManagerRegistry;
|
|||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
/**
|
||||
* ParamConverter used in the RSS controller to retrieve the right user according to
|
||||
|
@ -49,7 +49,7 @@ class UsernameRssTokenConverter implements ParamConverterInterface
|
|||
$em = $this->registry->getManagerForClass($configuration->getClass());
|
||||
|
||||
// Check, if class name is what we need
|
||||
if ('Wallabag\CoreBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) {
|
||||
if ('Wallabag\UserBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,11 @@ services:
|
|||
tags:
|
||||
- { name: form.type, alias: config }
|
||||
|
||||
wallabag_core.form.registration:
|
||||
class: Wallabag\CoreBundle\Form\Type\RegistrationType
|
||||
tags:
|
||||
- { name: form.type, alias: wallabag_user_registration }
|
||||
|
||||
wallabag_core.form.type.forgot_password:
|
||||
class: Wallabag\CoreBundle\Form\Type\ForgotPasswordType
|
||||
arguments:
|
||||
|
@ -29,7 +34,8 @@ services:
|
|||
|
||||
wallabag_core.doctrine.prefixed_naming_strategy:
|
||||
class: Wallabag\CoreBundle\Doctrine\Mapping\PrefixedNamingStrategy
|
||||
arguments: [%database_table_prefix%]
|
||||
arguments:
|
||||
- %database_table_prefix%
|
||||
|
||||
wallabag_core.graby:
|
||||
class: Graby\Graby
|
||||
|
@ -40,3 +46,14 @@ services:
|
|||
class: Wallabag\CoreBundle\Helper\ContentProxy
|
||||
arguments:
|
||||
- @wallabag_core.graby
|
||||
|
||||
wallabag_core.registration_confirmed:
|
||||
class: Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener
|
||||
arguments:
|
||||
- @doctrine.orm.entity_manager
|
||||
- %theme%
|
||||
- %items_on_page%
|
||||
- %rss_limit%
|
||||
- %language%
|
||||
tags:
|
||||
- { name: kernel.event_subscriber }
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<script src="{{ asset('themes/_global/js/bookmarklet.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
<title>{% block title %}{% endblock %} - wallabag</title>
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
|
@ -60,7 +60,7 @@
|
|||
|
||||
{% block messages %}{% endblock %}
|
||||
|
||||
<div id="content" class="w600p">
|
||||
<div id="content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
{{ form_rest(form.pwd) }}
|
||||
</form>
|
||||
|
||||
{% if is_granted('ROLE_SUPER_ADMIN') %}
|
||||
<h2>{% trans %}Add a user{% endtrans %}</h2>
|
||||
|
||||
<form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}>
|
||||
|
@ -150,9 +151,17 @@
|
|||
|
||||
<fieldset class="w500p inline">
|
||||
<div class="row">
|
||||
{{ form_label(form.new_user.password) }}
|
||||
{{ form_errors(form.new_user.password) }}
|
||||
{{ form_widget(form.new_user.password) }}
|
||||
{{ form_label(form.new_user.plainPassword.first) }}
|
||||
{{ form_errors(form.new_user.plainPassword.first) }}
|
||||
{{ form_widget(form.new_user.plainPassword.first) }}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="w500p inline">
|
||||
<div class="row">
|
||||
{{ form_label(form.new_user.plainPassword.second) }}
|
||||
{{ form_errors(form.new_user.plainPassword.second) }}
|
||||
{{ form_widget(form.new_user.plainPassword.second) }}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
@ -165,5 +174,6 @@
|
|||
</fieldset>
|
||||
|
||||
{{ form_rest(form.new_user) }}
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{% trans %}Forgot password{% endtrans %}{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ path('forgot_password') }}" method="post" name="forgotPasswordform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans %}Forgot password{% endtrans %}</h2>
|
||||
|
||||
{{ form_errors(form) }}
|
||||
|
||||
<p>Enter your email address below and we'll send you password reset instructions.</p>
|
||||
|
||||
<div class="row">
|
||||
{{ form_label(form.email) }}
|
||||
{{ form_errors(form.email) }}
|
||||
{{ form_widget(form.email) }}
|
||||
</div>
|
||||
|
||||
<div class="row mts txtcenter">
|
||||
<button type="submit">Send me reset instructions</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{ form_rest(form) }}
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,35 +0,0 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{% trans %}Change password{% endtrans %}{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ path('forgot_password_reset', {'token': token}) }}" method="post" name="loginform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans %}Change password{% endtrans %}</h2>
|
||||
|
||||
{{ form_errors(form) }}
|
||||
|
||||
<div class="row">
|
||||
{{ form_label(form.new_password.first) }}
|
||||
{{ form_errors(form.new_password.first) }}
|
||||
{{ form_widget(form.new_password.first) }}
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{{ form_label(form.new_password.second) }}
|
||||
{{ form_errors(form.new_password.second) }}
|
||||
{{ form_widget(form.new_password.second) }}
|
||||
</div>
|
||||
|
||||
<div class="row mts txtcenter">
|
||||
<button type="submit">Change password</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{ form_rest(form) }}
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -52,7 +52,7 @@
|
|||
</li>
|
||||
<li><a href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li>
|
||||
<li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li>
|
||||
<li><a class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
|
||||
<li><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
<li class="tab col s3"><a href="#set2">{% trans %}RSS{% endtrans %}</a></li>
|
||||
<li class="tab col s3"><a href="#set3">{% trans %}User information{% endtrans %}</a></li>
|
||||
<li class="tab col s3"><a href="#set4">{% trans %}Password{% endtrans %}</a></li>
|
||||
{% if is_granted('ROLE_SUPER_ADMIN') %}
|
||||
<li class="tab col s3"><a href="#set5">{% trans %}Add a user{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -175,7 +177,7 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
{% if is_granted('ROLE_SUPER_ADMIN') %}
|
||||
<div id="set5" class="col s12">
|
||||
<form action="{{ path('config') }}#set5" method="post" {{ form_enctype(form.new_user) }}>
|
||||
{{ form_errors(form.new_user) }}
|
||||
|
@ -190,9 +192,17 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.new_user.password) }}
|
||||
{{ form_errors(form.new_user.password) }}
|
||||
{{ form_widget(form.new_user.password) }}
|
||||
{{ form_label(form.new_user.plainPassword.first) }}
|
||||
{{ form_errors(form.new_user.plainPassword.first) }}
|
||||
{{ form_widget(form.new_user.plainPassword.first) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.new_user.plainPassword.second) }}
|
||||
{{ form_errors(form.new_user.plainPassword.second) }}
|
||||
{{ form_widget(form.new_user.plainPassword.second) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -211,6 +221,7 @@
|
|||
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -49,11 +49,12 @@
|
|||
{% trans %}Login{% endtrans %}
|
||||
<i class="mdi-content-send right"></i>
|
||||
</button>
|
||||
<a href="{{ path('fos_user_registration_register') }}">{% trans %}Register{% endtrans %}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="center">
|
||||
<a href="{{ path('forgot_password') }}">{% trans %}Forgot your password?{% endtrans %}</a>
|
||||
<a href="{{ path('fos_user_resetting_request') }}">{% trans %}Forgot your password?{% endtrans %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
<li class="bold border-bottom {% if currentRoute == 'tags' %}active{% endif %}"><a class="waves-effect" href="{{ path('tag') }}">{% trans %}tags{% endtrans %}</a></li>
|
||||
<li class="bold {% if currentRoute == 'config' %}active{% endif %}"><a class="waves-effect" href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li>
|
||||
<li class="bold {% if currentRoute == 'howto' %}active{% endif %}"><a class="waves-effect" href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li>
|
||||
<li class="bold border-bottom {% if currentRoute == 'about' %}active{% endif %}"><a class="waves-effect" href="{{ path('about') }}">{% trans %}About{% endtrans %}</a></li>
|
||||
<li class="bold"><a class="waves-effect" class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
|
||||
<li class="bold"><a class="waves-effect" class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
|
||||
</ul>
|
||||
<div class="nav-wrapper nav-panels">
|
||||
<a href="#" data-activates="slide-out" class="nav-panel-menu button-collapse"><i class="mdi-navigation-menu"></i></a>
|
||||
|
|
|
@ -24,6 +24,10 @@ body {
|
|||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
body.login main {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#warning_message {
|
||||
position: fixed;
|
||||
background-color: #ff6347;
|
||||
|
@ -250,9 +254,14 @@ main ul.row {
|
|||
}
|
||||
|
||||
.card .card-action a {
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card .card-action a:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.settings .div_tabs {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3 KiB |
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Security\Authentication\Encoder;
|
||||
|
||||
use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
|
||||
/**
|
||||
* This override just add en extra variable (username) to be able to salt the password
|
||||
* the way Wallabag v1 does. It will avoid to break compatibility with Wallabag v1.
|
||||
*/
|
||||
class WallabagPasswordEncoder extends BasePasswordEncoder
|
||||
{
|
||||
private $algorithm;
|
||||
private $encodeHashAsBase64;
|
||||
private $iterations;
|
||||
private $username = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $algorithm The digest algorithm to use
|
||||
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
|
||||
* @param int $iterations The number of iterations to use to stretch the password hash
|
||||
*/
|
||||
public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000)
|
||||
{
|
||||
$this->algorithm = $algorithm;
|
||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||
$this->iterations = $iterations;
|
||||
}
|
||||
|
||||
public function setUsername($username)
|
||||
{
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function encodePassword($raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
throw new BadCredentialsException('Invalid password.');
|
||||
}
|
||||
|
||||
if (!in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
||||
$salted = $this->mergePasswordAndSalt($raw, $salt);
|
||||
$digest = hash($this->algorithm, $salted, true);
|
||||
|
||||
// "stretch" hash
|
||||
for ($i = 1; $i < $this->iterations; ++$i) {
|
||||
$digest = hash($this->algorithm, $digest.$salted, true);
|
||||
}
|
||||
|
||||
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* We inject the username inside the salted password
|
||||
*/
|
||||
protected function mergePasswordAndSalt($password, $salt)
|
||||
{
|
||||
if (null === $this->username) {
|
||||
throw new \LogicException('We can not check the password without a username.');
|
||||
}
|
||||
|
||||
if (empty($salt)) {
|
||||
return $password;
|
||||
}
|
||||
|
||||
return $password.$this->username.$salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isPasswordValid($encoded, $raw, $salt)
|
||||
{
|
||||
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Security\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider;
|
||||
|
||||
class WallabagAuthenticationProvider extends UserAuthenticationProvider
|
||||
{
|
||||
private $encoderFactory;
|
||||
private $userProvider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param UserProviderInterface $userProvider An UserProviderInterface instance
|
||||
* @param UserCheckerInterface $userChecker An UserCheckerInterface instance
|
||||
* @param string $providerKey The provider key
|
||||
* @param EncoderFactoryInterface $encoderFactory An EncoderFactoryInterface instance
|
||||
* @param bool $hideUserNotFoundExceptions Whether to hide user not found exception or not
|
||||
*/
|
||||
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
|
||||
{
|
||||
parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
|
||||
|
||||
$this->encoderFactory = $encoderFactory;
|
||||
$this->userProvider = $userProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token)
|
||||
{
|
||||
$currentUser = $token->getUser();
|
||||
if ($currentUser instanceof UserInterface) {
|
||||
if ($currentUser->getPassword() !== $user->getPassword()) {
|
||||
throw new BadCredentialsException('The credentials were changed from another session.');
|
||||
}
|
||||
} else {
|
||||
if ('' === ($presentedPassword = $token->getCredentials())) {
|
||||
throw new BadCredentialsException('The presented password cannot be empty.');
|
||||
}
|
||||
|
||||
// give username, it's used to hash the password
|
||||
$encoder = $this->encoderFactory->getEncoder($user);
|
||||
$encoder->setUsername($user->getUsername());
|
||||
|
||||
if (!$encoder->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) {
|
||||
throw new BadCredentialsException('The presented password is invalid.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function retrieveUser($username, UsernamePasswordToken $token)
|
||||
{
|
||||
$user = $token->getUser();
|
||||
if ($user instanceof UserInterface) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
try {
|
||||
$user = $this->userProvider->loadUserByUsername($username);
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new AuthenticationServiceException('The user provider must return a UserInterface object.');
|
||||
}
|
||||
|
||||
return $user;
|
||||
} catch (UsernameNotFoundException $notFound) {
|
||||
$notFound->setUsername($username);
|
||||
throw $notFound;
|
||||
} catch (\Exception $repositoryProblem) {
|
||||
$ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem);
|
||||
$ex->setToken($token);
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Security\Validator;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
|
||||
|
||||
/**
|
||||
* @see Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator
|
||||
*/
|
||||
class WallabagUserPasswordValidator extends ConstraintValidator
|
||||
{
|
||||
private $securityContext;
|
||||
private $encoderFactory;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, EncoderFactoryInterface $encoderFactory)
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->encoderFactory = $encoderFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($password, Constraint $constraint)
|
||||
{
|
||||
if (!$constraint instanceof UserPassword) {
|
||||
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword');
|
||||
}
|
||||
|
||||
$user = $this->tokenStorage->getToken()->getUser();
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.');
|
||||
}
|
||||
|
||||
// give username, it's used to hash the password
|
||||
$encoder = $this->encoderFactory->getEncoder($user);
|
||||
$encoder->setUsername($user->getUsername());
|
||||
|
||||
if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
|
||||
$this->context->addViolation($constraint->message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -258,7 +258,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => '',
|
||||
'new_user[password]' => '',
|
||||
'new_user[plainPassword][first]' => '',
|
||||
'new_user[plainPassword][second]' => '',
|
||||
'new_user[email]' => '',
|
||||
),
|
||||
'Please enter a username',
|
||||
|
@ -266,7 +267,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => 'a',
|
||||
'new_user[password]' => 'mypassword',
|
||||
'new_user[plainPassword][first]' => 'mypassword',
|
||||
'new_user[plainPassword][second]' => 'mypassword',
|
||||
'new_user[email]' => '',
|
||||
),
|
||||
'The username is too short',
|
||||
|
@ -274,7 +276,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => 'wallace',
|
||||
'new_user[password]' => 'mypassword',
|
||||
'new_user[plainPassword][first]' => 'mypassword',
|
||||
'new_user[plainPassword][second]' => 'mypassword',
|
||||
'new_user[email]' => 'test',
|
||||
),
|
||||
'The email is not valid',
|
||||
|
@ -282,11 +285,21 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => 'admin',
|
||||
'new_user[password]' => 'wallacewallace',
|
||||
'new_user[plainPassword][first]' => 'wallacewallace',
|
||||
'new_user[plainPassword][second]' => 'wallacewallace',
|
||||
'new_user[email]' => 'wallace@wallace.me',
|
||||
),
|
||||
'The username is already used',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'new_user[username]' => 'wallace',
|
||||
'new_user[plainPassword][first]' => 'mypassword1',
|
||||
'new_user[plainPassword][second]' => 'mypassword2',
|
||||
'new_user[email]' => 'wallace@wallace.me',
|
||||
),
|
||||
'This value is not valid',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -325,7 +338,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
|
||||
$data = array(
|
||||
'new_user[username]' => 'wallace',
|
||||
'new_user[password]' => 'wallace1',
|
||||
'new_user[plainPassword][first]' => 'wallace1',
|
||||
'new_user[plainPassword][second]' => 'wallace1',
|
||||
'new_user[email]' => 'wallace@wallace.me',
|
||||
);
|
||||
|
||||
|
@ -340,7 +354,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $em
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->getRepository('WallabagUserBundle:User')
|
||||
->findOneByUsername('wallace');
|
||||
|
||||
$this->assertTrue(false !== $user);
|
||||
|
@ -355,7 +369,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
// reset the token
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $em
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->getRepository('WallabagUserBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
if (!$user) {
|
||||
|
|
|
@ -64,7 +64,7 @@ class RssControllerTest extends WallabagCoreTestCase
|
|||
$client = $this->getClient();
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $em
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->getRepository('WallabagUserBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
$config = $user->getConfig();
|
||||
|
@ -85,7 +85,7 @@ class RssControllerTest extends WallabagCoreTestCase
|
|||
$client = $this->getClient();
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $em
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->getRepository('WallabagUserBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
$config = $user->getConfig();
|
||||
|
@ -107,7 +107,7 @@ class RssControllerTest extends WallabagCoreTestCase
|
|||
$client = $this->getClient();
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $em
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->getRepository('WallabagUserBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
$config = $user->getConfig();
|
||||
|
|
|
@ -1,201 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Wallabag\CoreBundle\Tests\WallabagCoreTestCase;
|
||||
|
||||
class SecurityControllerTest extends WallabagCoreTestCase
|
||||
{
|
||||
public function testLogin()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/new');
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('login', $client->getResponse()->headers->get('location'));
|
||||
}
|
||||
|
||||
public function testLoginFail()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/login');
|
||||
|
||||
$form = $crawler->filter('button[type=submit]')->form();
|
||||
$data = array(
|
||||
'_username' => 'admin',
|
||||
'_password' => 'admin',
|
||||
);
|
||||
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('login', $client->getResponse()->headers->get('location'));
|
||||
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
$this->assertContains('Bad credentials', $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testRedirectionAfterLogin()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
$client->followRedirects();
|
||||
|
||||
$crawler = $client->request('GET', '/config');
|
||||
|
||||
$form = $crawler->filter('button[type=submit]')->form();
|
||||
|
||||
$data = array(
|
||||
'_username' => 'admin',
|
||||
'_password' => 'mypassword',
|
||||
);
|
||||
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertContains('RSS', $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testForgotPassword()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/forgot-password');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertContains('Forgot password', $client->getResponse()->getContent());
|
||||
|
||||
$form = $crawler->filter('button[type=submit]');
|
||||
|
||||
$this->assertCount(1, $form);
|
||||
|
||||
return array(
|
||||
'form' => $form->form(),
|
||||
'client' => $client,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testForgotPassword
|
||||
*/
|
||||
public function testSubmitForgotPasswordFail($parameters)
|
||||
{
|
||||
$form = $parameters['form'];
|
||||
$client = $parameters['client'];
|
||||
|
||||
$data = array(
|
||||
'forgot_password[email]' => 'material',
|
||||
);
|
||||
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('No user found with this email', $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testForgotPassword
|
||||
*
|
||||
* Instead of using collector which slow down the test suite
|
||||
* http://symfony.com/doc/current/cookbook/email/testing.html
|
||||
*
|
||||
* Use a different way where Swift store email as file
|
||||
*/
|
||||
public function testSubmitForgotPassword($parameters)
|
||||
{
|
||||
$form = $parameters['form'];
|
||||
$client = $parameters['client'];
|
||||
|
||||
$spoolDir = $client->getKernel()->getContainer()->getParameter('swiftmailer.spool.default.file.path');
|
||||
|
||||
// cleanup pool dir
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->remove($spoolDir);
|
||||
|
||||
// to use `getCollector` since `collect: false` in config_test.yml
|
||||
$client->enableProfiler();
|
||||
|
||||
$data = array(
|
||||
'forgot_password[email]' => 'bobby@wallabag.org',
|
||||
);
|
||||
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
$this->assertContains('An email has been sent to', $client->getResponse()->getContent());
|
||||
|
||||
// find every files (ie: emails) inside the spool dir except hidden files
|
||||
$finder = new Finder();
|
||||
$finder
|
||||
->in($spoolDir)
|
||||
->ignoreDotFiles(true)
|
||||
->files();
|
||||
|
||||
$this->assertCount(1, $finder, 'Only one email has been sent');
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$message = unserialize(file_get_contents($file));
|
||||
|
||||
$this->assertInstanceOf('Swift_Message', $message);
|
||||
$this->assertEquals('Reset Password', $message->getSubject());
|
||||
$this->assertEquals('no-reply@wallabag.org', key($message->getFrom()));
|
||||
$this->assertEquals('bobby@wallabag.org', key($message->getTo()));
|
||||
$this->assertContains(
|
||||
'To reset your password - please visit',
|
||||
$message->getBody()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testReset()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
$user = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByEmail('bobby@wallabag.org');
|
||||
|
||||
$crawler = $client->request('GET', '/forgot-password/'.$user->getConfirmationToken());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertCount(2, $crawler->filter('input[type=password]'));
|
||||
$this->assertCount(1, $form = $crawler->filter('button[type=submit]'));
|
||||
$this->assertCount(1, $form);
|
||||
|
||||
$data = array(
|
||||
'change_passwd[new_password][first]' => 'mypassword',
|
||||
'change_passwd[new_password][second]' => 'mypassword',
|
||||
);
|
||||
|
||||
$client->submit($form->form(), $data);
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('login', $client->getResponse()->headers->get('location'));
|
||||
}
|
||||
|
||||
public function testResetBadToken()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$client->request('GET', '/forgot-password/UIZOAU29UE902IEPZO');
|
||||
|
||||
$this->assertEquals(404, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testCheckEmailWithoutEmail()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$client->request('GET', '/forgot-password/check-email');
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('forgot-password', $client->getResponse()->headers->get('location'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Tests\EventListener;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use FOS\UserBundle\Event\FilterUserResponseEvent;
|
||||
use Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
class RegistrationConfirmedListenerTest extends KernelTestCase
|
||||
{
|
||||
private $em;
|
||||
private $listener;
|
||||
private $dispatcher;
|
||||
private $request;
|
||||
private $response;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->listener = new RegistrationConfirmedListener(
|
||||
$this->em,
|
||||
'baggy',
|
||||
20,
|
||||
50,
|
||||
'fr'
|
||||
);
|
||||
|
||||
$this->dispatcher = new EventDispatcher();
|
||||
$this->dispatcher->addSubscriber($this->listener);
|
||||
|
||||
$this->request = Request::create('/');
|
||||
$this->response = Response::create();
|
||||
}
|
||||
|
||||
public function testWithInvalidUser()
|
||||
{
|
||||
$user = new User();
|
||||
$user->setEnabled(false);
|
||||
|
||||
$event = new FilterUserResponseEvent(
|
||||
$user,
|
||||
$this->request,
|
||||
$this->response
|
||||
);
|
||||
|
||||
$this->em->expects($this->never())->method('persist');
|
||||
$this->em->expects($this->never())->method('flush');
|
||||
|
||||
$this->dispatcher->dispatch(
|
||||
FOSUserEvents::REGISTRATION_CONFIRMED,
|
||||
$event
|
||||
);
|
||||
}
|
||||
|
||||
public function testWithValidUser()
|
||||
{
|
||||
$user = new User();
|
||||
$user->setEnabled(true);
|
||||
|
||||
$event = new FilterUserResponseEvent(
|
||||
$user,
|
||||
$this->request,
|
||||
$this->response
|
||||
);
|
||||
|
||||
$config = new Config($user);
|
||||
$config->setTheme('baggy');
|
||||
$config->setItemsPerPage(20);
|
||||
$config->setRssLimit(50);
|
||||
$config->setLanguage('fr');
|
||||
|
||||
$this->em->expects($this->once())
|
||||
->method('persist')
|
||||
->will($this->returnValue($config));
|
||||
$this->em->expects($this->once())
|
||||
->method('flush');
|
||||
|
||||
$this->dispatcher->dispatch(
|
||||
FOSUserEvents::REGISTRATION_CONFIRMED,
|
||||
$event
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Wallabag\CoreBundle\Tests\Helper;
|
|||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Helper\ContentProxy;
|
||||
|
||||
class ContentProxyTest extends KernelTestCase
|
||||
|
|
|
@ -6,7 +6,7 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
|||
use Wallabag\CoreBundle\ParamConverter\UsernameRssTokenConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
class UsernameRssTokenConverterTest extends KernelTestCase
|
||||
{
|
||||
|
@ -96,7 +96,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$meta->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('Wallabag\CoreBundle\Entity\User'));
|
||||
->will($this->returnValue('Wallabag\UserBundle\Entity\User'));
|
||||
|
||||
$em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')
|
||||
->disableOriginalConstructor()
|
||||
|
@ -104,7 +104,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$em->expects($this->once())
|
||||
->method('getClassMetadata')
|
||||
->with('WallabagCoreBundle:User')
|
||||
->with('WallabagUserBundle:User')
|
||||
->will($this->returnValue($meta));
|
||||
|
||||
$registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')
|
||||
|
@ -117,10 +117,10 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$registry->expects($this->once())
|
||||
->method('getManagerForClass')
|
||||
->with('WallabagCoreBundle:User')
|
||||
->with('WallabagUserBundle:User')
|
||||
->will($this->returnValue($em));
|
||||
|
||||
$params = new ParamConverter(array('class' => 'WallabagCoreBundle:User'));
|
||||
$params = new ParamConverter(array('class' => 'WallabagUserBundle:User'));
|
||||
$converter = new UsernameRssTokenConverter($registry);
|
||||
|
||||
$this->assertTrue($converter->supports($params));
|
||||
|
@ -144,7 +144,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
*/
|
||||
public function testApplyUserNotFound()
|
||||
{
|
||||
$repo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\UserRepository')
|
||||
$repo = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
|
@ -159,7 +159,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$em->expects($this->once())
|
||||
->method('getRepository')
|
||||
->with('WallabagCoreBundle:User')
|
||||
->with('WallabagUserBundle:User')
|
||||
->will($this->returnValue($repo));
|
||||
|
||||
$registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')
|
||||
|
@ -168,10 +168,10 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$registry->expects($this->once())
|
||||
->method('getManagerForClass')
|
||||
->with('WallabagCoreBundle:User')
|
||||
->with('WallabagUserBundle:User')
|
||||
->will($this->returnValue($em));
|
||||
|
||||
$params = new ParamConverter(array('class' => 'WallabagCoreBundle:User'));
|
||||
$params = new ParamConverter(array('class' => 'WallabagUserBundle:User'));
|
||||
$converter = new UsernameRssTokenConverter($registry);
|
||||
$request = new Request(array(), array(), array('username' => 'test', 'token' => 'test'));
|
||||
|
||||
|
@ -182,7 +182,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
{
|
||||
$user = new User();
|
||||
|
||||
$repo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\UserRepository')
|
||||
$repo = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
|
@ -197,7 +197,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$em->expects($this->once())
|
||||
->method('getRepository')
|
||||
->with('WallabagCoreBundle:User')
|
||||
->with('WallabagUserBundle:User')
|
||||
->will($this->returnValue($repo));
|
||||
|
||||
$registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')
|
||||
|
@ -206,10 +206,10 @@ class UsernameRssTokenConverterTest extends KernelTestCase
|
|||
|
||||
$registry->expects($this->once())
|
||||
->method('getManagerForClass')
|
||||
->with('WallabagCoreBundle:User')
|
||||
->with('WallabagUserBundle:User')
|
||||
->will($this->returnValue($em));
|
||||
|
||||
$params = new ParamConverter(array('class' => 'WallabagCoreBundle:User', 'name' => 'user'));
|
||||
$params = new ParamConverter(array('class' => 'WallabagUserBundle:User', 'name' => 'user'));
|
||||
$converter = new UsernameRssTokenConverter($registry);
|
||||
$request = new Request(array(), array(), array('username' => 'test', 'token' => 'test'));
|
||||
|
||||
|
|
75
src/Wallabag/UserBundle/Controller/ResettingController.php
Normal file
75
src/Wallabag/UserBundle/Controller/ResettingController.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\UserBundle\Controller;
|
||||
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use FOS\UserBundle\Event\FormEvent;
|
||||
use FOS\UserBundle\Event\GetResponseUserEvent;
|
||||
use FOS\UserBundle\Event\FilterUserResponseEvent;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class ResettingController extends \FOS\UserBundle\Controller\ResettingController
|
||||
{
|
||||
/**
|
||||
* Extends ResettingController to change the redirection after success.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $token
|
||||
*
|
||||
* @return null|RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function resetAction(Request $request, $token)
|
||||
{
|
||||
/** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
|
||||
$formFactory = $this->get('fos_user.resetting.form.factory');
|
||||
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
|
||||
$userManager = $this->get('fos_user.user_manager');
|
||||
/** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
|
||||
$dispatcher = $this->get('event_dispatcher');
|
||||
|
||||
$user = $userManager->findUserByConfirmationToken($token);
|
||||
|
||||
if (null === $user) {
|
||||
throw new NotFoundHttpException(sprintf('The user with "confirmation token" does not exist for value "%s"', $token));
|
||||
}
|
||||
|
||||
$event = new GetResponseUserEvent($user, $request);
|
||||
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_INITIALIZE, $event);
|
||||
|
||||
if (null !== $event->getResponse()) {
|
||||
return $event->getResponse();
|
||||
}
|
||||
|
||||
$form = $formFactory->createForm();
|
||||
$form->setData($user);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$event = new FormEvent($form, $request);
|
||||
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event);
|
||||
|
||||
$userManager->updateUser($user);
|
||||
|
||||
if (null === $response = $event->getResponse()) {
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
'Password updated'
|
||||
);
|
||||
$url = $this->generateUrl('homepage');
|
||||
$response = new RedirectResponse($url);
|
||||
}
|
||||
|
||||
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->render('FOSUserBundle:Resetting:reset.html.twig', array(
|
||||
'token' => $token,
|
||||
'form' => $form->createView(),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
namespace Wallabag\UserBundle\DataFixtures\ORM;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
|
||||
class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
|
@ -18,8 +18,9 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
|
|||
$userAdmin->setName('Big boss');
|
||||
$userAdmin->setEmail('bigboss@wallabag.org');
|
||||
$userAdmin->setUsername('admin');
|
||||
$userAdmin->setPassword('mypassword');
|
||||
$userAdmin->setPlainPassword('mypassword');
|
||||
$userAdmin->setEnabled(true);
|
||||
$userAdmin->addRole('ROLE_SUPER_ADMIN');
|
||||
|
||||
$manager->persist($userAdmin);
|
||||
|
||||
|
@ -29,7 +30,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
|
|||
$bobUser->setName('Bobby');
|
||||
$bobUser->setEmail('bobby@wallabag.org');
|
||||
$bobUser->setUsername('bob');
|
||||
$bobUser->setPassword('mypassword');
|
||||
$bobUser->setPlainPassword('mypassword');
|
||||
$bobUser->setEnabled(true);
|
||||
|
||||
$manager->persist($bobUser);
|
|
@ -1,20 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Entity;
|
||||
namespace Wallabag\UserBundle\Entity;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
|
||||
use JMS\Serializer\Annotation\ExclusionPolicy;
|
||||
use JMS\Serializer\Annotation\Expose;
|
||||
use FOS\UserBundle\Model\User as BaseUser;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
|
||||
/**
|
||||
* User.
|
||||
*
|
||||
* @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\UserRepository")
|
||||
* @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
|
||||
* @ORM\Table
|
||||
* @ORM\HasLifecycleCallbacks()
|
||||
* @ExclusionPolicy("all")
|
||||
|
@ -22,7 +24,7 @@ use FOS\UserBundle\Model\User as BaseUser;
|
|||
* @UniqueEntity("email")
|
||||
* @UniqueEntity("username")
|
||||
*/
|
||||
class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
||||
class User extends BaseUser
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
|
@ -56,17 +58,17 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
protected $updatedAt;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Entry", mappedBy="user", cascade={"remove"})
|
||||
* @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Entry", mappedBy="user", cascade={"remove"})
|
||||
*/
|
||||
protected $entries;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="Config", mappedBy="user")
|
||||
* @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user")
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Tag", mappedBy="user", cascade={"remove"})
|
||||
* @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Tag", mappedBy="user", cascade={"remove"})
|
||||
*/
|
||||
protected $tags;
|
||||
|
||||
|
@ -75,6 +77,7 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
parent::__construct();
|
||||
$this->entries = new ArrayCollection();
|
||||
$this->tags = new ArrayCollection();
|
||||
$this->roles = array('ROLE_USER');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,24 +93,6 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
$this->updatedAt = new \DateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set password.
|
||||
*
|
||||
* @param string $password
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
if (!$password && 0 === strlen($password)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->password = sha1($password.$this->getUsername().$this->getSalt());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name.
|
||||
*
|
||||
|
@ -196,11 +181,11 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
/**
|
||||
* Set config.
|
||||
*
|
||||
* @param \Wallabag\CoreBundle\Entity\Config $config
|
||||
* @param Config $config
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function setConfig(\Wallabag\CoreBundle\Entity\Config $config = null)
|
||||
public function setConfig(Config $config = null)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
|
@ -210,7 +195,7 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
/**
|
||||
* Get config.
|
||||
*
|
||||
* @return \Wallabag\CoreBundle\Entity\Config
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Repository;
|
||||
namespace Wallabag\UserBundle\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
0
src/Wallabag/UserBundle/Resources/config/services.yml
Normal file
0
src/Wallabag/UserBundle/Resources/config/services.yml
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{% trans %}create an account{% endtrans %}{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
{% block messages %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans %}create an account{% endtrans %}</h2>
|
||||
{% include "FOSUserBundle:Registration:register_content.html.twig" %}
|
||||
</fieldset>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,37 @@
|
|||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
{{ form_widget(form._token) }}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<span><p>{{ flashMessage }}</p></span>
|
||||
{% endfor %}
|
||||
|
||||
<div class="row">
|
||||
{{ form_errors(form.email) }}
|
||||
{{ form_label(form.email) }}
|
||||
{{ form_widget(form.email) }}
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{{ form_errors(form.username) }}
|
||||
{{ form_label(form.username) }}
|
||||
{{ form_widget(form.username) }}
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{{ form_errors(form.plainPassword.first) }}
|
||||
{{ form_label(form.plainPassword.first) }}
|
||||
{{ form_widget(form.plainPassword.first) }}
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{{ form_errors(form.plainPassword.second) }}
|
||||
{{ form_label(form.plainPassword.second) }}
|
||||
{{ form_widget(form.plainPassword.second) }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mts txtcenter">
|
||||
<button type="submit">{{ 'registration.submit'|trans({}, 'FOSUserBundle') }}</button>
|
||||
<a href="{{ path('fos_user_security_login') }}" class="button">{% trans %}Login{% endtrans %}</a>
|
||||
</div>
|
|
@ -0,0 +1,20 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{% trans %}Forgot password{% endtrans %}{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
{% block messages %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ path('fos_user_resetting_send_email') }}" method="post" name="forgotPasswordform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans %}Forgot password{% endtrans %}</h2>
|
||||
{% include "FOSUserBundle:Resetting:request_content.html.twig" %}
|
||||
</fieldset>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
|||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
{% trans %}Enter your email address below and we'll send you password reset instructions.{% endtrans %}
|
||||
|
||||
{% if invalid_username is defined %}
|
||||
<p>{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}) }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<label for="username">{{ 'resetting.request.username'|trans }}</label>
|
||||
<input type="text" id="username" name="username" required="required" />
|
||||
</div>
|
||||
|
||||
<div class="row mts txtcenter">
|
||||
<button type="submit">{{ 'resetting.request.submit'|trans }}</button>
|
||||
<a href="{{ path('fos_user_security_login') }}" class="button">{% trans %}Login{% endtrans %}</a>
|
||||
</div>
|
|
@ -1,14 +1,7 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
{% extends "FOSUserBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{% trans %}login to your wallabag{% endtrans %}{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
{% block messages %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ path('login_check') }}" method="post" name="loginform">
|
||||
{% block fos_user_content %}
|
||||
<form action="{{ path('fos_user_security_check') }}" method="post" name="loginform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans %}Login to wallabag{% endtrans %}</h2>
|
||||
{% if error %}
|
||||
|
@ -32,7 +25,8 @@
|
|||
<div class="row mts txtcenter">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
|
||||
<button type="submit">Login</button>
|
||||
<a href="{{ path('forgot_password') }}" class="small">Forgot your password?</a>
|
||||
<a href="{{ path('fos_user_registration_register') }}" class="button">{% trans %}Register{% endtrans %}</a>
|
||||
<a href="{{ path('fos_user_resetting_request') }}" class="small">Forgot your password?</a>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
|
@ -0,0 +1,16 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}Welcome on wallabag!{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
{% block messages %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% block fos_user_content %}
|
||||
{% endblock fos_user_content %}
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
|||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
<form action="{{ path('fos_user_change_password') }}" {{ form_enctype(form) }} method="POST" class="fos_user_change_password">
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
{{ form_widget(form) }}
|
||||
<div>
|
||||
<input type="submit" value="{{ 'change_password.submit'|trans }}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,11 @@
|
|||
{% extends "FOSUserBundle::layout.html.twig" %}
|
||||
|
||||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
{% block fos_user_content %}
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
<p>{{ 'registration.check_email'|trans({'%email%': user.email}) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock fos_user_content %}
|
|
@ -0,0 +1,17 @@
|
|||
{% extends "FOSUserBundle::layout.html.twig" %}
|
||||
|
||||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
{% block fos_user_content %}
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
<p>{{ 'registration.confirmed'|trans({'%username%': user.username}) }}</p>
|
||||
{% if targetUrl %}
|
||||
<p><a href="{{ targetUrl }}">{{ 'registration.back'|trans }}</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-action center">
|
||||
<a href="{{ path('homepage') }}" class="waves-effect waves-light btn"><i class="material-icons left"></i> {% trans %}Go to your account{% endtrans %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock fos_user_content %}
|
|
@ -0,0 +1,45 @@
|
|||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register">
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
|
||||
{{ form_widget(form._token) }}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<span class="black-text"><p>{{ flashMessage }}</p></span>
|
||||
{% endfor %}
|
||||
|
||||
<div class="input-field col s12">
|
||||
{{ form_errors(form.email) }}
|
||||
{{ form_label(form.email) }}
|
||||
{{ form_widget(form.email) }}
|
||||
</div>
|
||||
|
||||
<div class="input-field col s12">
|
||||
{{ form_errors(form.username) }}
|
||||
{{ form_label(form.username) }}
|
||||
{{ form_widget(form.username) }}
|
||||
</div>
|
||||
|
||||
<div class="input-field col s12">
|
||||
{{ form_errors(form.plainPassword.first) }}
|
||||
{{ form_label(form.plainPassword.first) }}
|
||||
{{ form_widget(form.plainPassword.first) }}
|
||||
</div>
|
||||
|
||||
<div class="input-field col s12">
|
||||
{{ form_errors(form.plainPassword.second) }}
|
||||
{{ form_label(form.plainPassword.second) }}
|
||||
{{ form_widget(form.plainPassword.second) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action center">
|
||||
<a href="{{ path('fos_user_security_login') }}" class="waves-effect waves-light grey btn"><i class="material-icons left"></i> {% trans %}Login{% endtrans %}</a>
|
||||
<button class="btn waves-effect waves-light" type="submit" name="send">
|
||||
{{ 'registration.submit'|trans({}, 'FOSUserBundle') }}
|
||||
<i class="mdi-content-send right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,11 @@
|
|||
{% extends "FOSUserBundle::layout.html.twig" %}
|
||||
|
||||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
{% block fos_user_content %}
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
{{ 'resetting.check_email'|trans({'%email%': email}) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock fos_user_content %}
|
|
@ -0,0 +1,11 @@
|
|||
{% extends "FOSUserBundle::layout.html.twig" %}
|
||||
|
||||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
{% block fos_user_content %}
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
{{ 'resetting.password_already_requested'|trans }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock fos_user_content %}
|
|
@ -0,0 +1,26 @@
|
|||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
<form action="{{ path('fos_user_resetting_send_email') }}" method="POST" class="fos_user_resetting_request">
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
<p>{% trans %}Enter your email address below and we'll send you password reset instructions.{% endtrans %}</p>
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<span class="black-text"><p>{{ flashMessage }}</p></span>
|
||||
{% endfor %}
|
||||
|
||||
{% if invalid_username is defined %}
|
||||
<p>{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}) }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="input-field col s12">
|
||||
<label for="username">{{ 'resetting.request.username'|trans }}</label>
|
||||
<input type="text" id="username" name="username" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action center">
|
||||
<a href="{{ path('fos_user_security_login') }}" class="waves-effect waves-light grey btn"><i class="material-icons left"></i> {% trans %}Login{% endtrans %}</a>
|
||||
<button class="btn waves-effect waves-light" type="submit" name="send">
|
||||
{{ 'resetting.request.submit'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,15 @@
|
|||
{% trans_default_domain 'FOSUserBundle' %}
|
||||
|
||||
<form action="{{ path('fos_user_resetting_reset', {'token': token}) }}" {{ form_enctype(form) }} method="POST" class="fos_user_resetting_reset">
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
{{ form_widget(form) }}
|
||||
</div>
|
||||
<div class="card-action center">
|
||||
<button class="btn waves-effect waves-light" type="submit" name="send">
|
||||
{{ 'resetting.reset.submit'|trans }}
|
||||
<i class="mdi-content-send right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,46 @@
|
|||
{% extends "FOSUserBundle::layout.html.twig" %}
|
||||
|
||||
{% block fos_user_content %}
|
||||
<form action="{{ path('fos_user_security_check') }}" method="post" name="loginform">
|
||||
<div class="card-content">
|
||||
|
||||
{% if error %}
|
||||
<span class="black-text">{{ error.message }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<span class="black-text"><p>{{ flashMessage }}</p></span>
|
||||
{% endfor %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="input-field col s12">
|
||||
<label for="username">{% trans %}Username{% endtrans %}</label>
|
||||
<input type="text" id="username" name="_username" value="{{ last_username }}" />
|
||||
</div>
|
||||
|
||||
<div class="input-field col s12">
|
||||
<label for="password">{% trans %}Password{% endtrans %}</label>
|
||||
<input type="password" id="password" name="_password" />
|
||||
</div>
|
||||
|
||||
<div class="input-field col s12">
|
||||
<input type="checkbox" id="remember_me" name="_remember_me" checked />
|
||||
<label for="remember_me">{% trans %}Keep me logged in{% endtrans %}</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action center">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
|
||||
<a href="{{ path('fos_user_registration_register') }}" class="waves-effect waves-light grey btn"><i class="material-icons left"></i> {% trans %}Register{% endtrans %}</a>
|
||||
<button class="btn waves-effect waves-light" type="submit" name="send">
|
||||
{% trans %}Login{% endtrans %}
|
||||
<i class="mdi-content-send right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="center">
|
||||
<a href="{{ path('fos_user_resetting_request') }}">{% trans %}Forgot your password?{% endtrans %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock fos_user_content %}
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}Welcome on wallabag!{% endblock %}
|
||||
|
||||
{% block body_class %}login{% endblock %}
|
||||
|
||||
{% block menu %}{% endblock %}
|
||||
{% block messages %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main class="valign-wrapper">
|
||||
<div class="valign row">
|
||||
<div class="card sw">
|
||||
<div class="center"><img src="{{ asset('themes/material/img/logo-other_themes.png') }}" alt="wallabag logo" /></div>
|
||||
{% block fos_user_content %}
|
||||
{% endblock fos_user_content %}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{% endblock %}
|
13
src/Wallabag/UserBundle/WallabagUserBundle.php
Normal file
13
src/Wallabag/UserBundle/WallabagUserBundle.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\UserBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class WallabagUserBundle extends Bundle
|
||||
{
|
||||
public function getParent()
|
||||
{
|
||||
return 'FOSUserBundle';
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue