]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #1436 from wallabag/v2-register
authorJeremy Benoist <j0k3r@users.noreply.github.com>
Tue, 6 Oct 2015 07:19:06 +0000 (09:19 +0200)
committerJeremy Benoist <j0k3r@users.noreply.github.com>
Tue, 6 Oct 2015 07:19:06 +0000 (09:19 +0200)
Public registration & oAuth2 \o/

82 files changed:
app/AppKernel.php
app/config/config.yml
app/config/config_prod.yml
app/config/routing.yml
app/config/security.yml
app/config/services.yml
composer.json
composer.lock
config/deploy.rb
config/deploy/staging.rb
src/Wallabag/ApiBundle/Controller/WallabagRestController.php
src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php [deleted file]
src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php
src/Wallabag/ApiBundle/Entity/AccessToken.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Entity/AuthCode.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Entity/Client.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Entity/RefreshToken.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Resources/config/services.yml [deleted file]
src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php [deleted file]
src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php [deleted file]
src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php [deleted file]
src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php
src/Wallabag/ApiBundle/WallabagApiBundle.php
src/Wallabag/CoreBundle/Command/InstallCommand.php
src/Wallabag/CoreBundle/Controller/ConfigController.php
src/Wallabag/CoreBundle/Controller/RssController.php
src/Wallabag/CoreBundle/Controller/SecurityController.php [deleted file]
src/Wallabag/CoreBundle/Entity/Config.php
src/Wallabag/CoreBundle/Entity/Entry.php
src/Wallabag/CoreBundle/Entity/Tag.php
src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Filter/EntryFilterType.php
src/Wallabag/CoreBundle/Form/Type/ForgotPasswordType.php [deleted file]
src/Wallabag/CoreBundle/Form/Type/NewUserType.php
src/Wallabag/CoreBundle/Form/Type/ResetPasswordType.php [deleted file]
src/Wallabag/CoreBundle/Form/Type/UserInformationType.php
src/Wallabag/CoreBundle/Helper/DetectActiveTheme.php
src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php
src/Wallabag/CoreBundle/Resources/config/services.yml
src/Wallabag/CoreBundle/Resources/views/base.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/forgotPassword.html.twig [deleted file]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/reset.html.twig [deleted file]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css
src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png
src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php [deleted file]
src/Wallabag/CoreBundle/Security/Authentication/Provider/WallabagAuthenticationProvider.php [deleted file]
src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php [deleted file]
src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php
src/Wallabag/CoreBundle/Tests/Controller/RssControllerTest.php
src/Wallabag/CoreBundle/Tests/Controller/SecurityControllerTest.php [deleted file]
src/Wallabag/CoreBundle/Tests/EventListener/RegistrationConfirmedListenerTest.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Tests/Helper/ContentProxyTest.php
src/Wallabag/CoreBundle/Tests/ParamConverter/UsernameRssTokenConverterTest.php
src/Wallabag/UserBundle/Controller/ResettingController.php [new file with mode: 0644]
src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php [moved from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php with 81% similarity]
src/Wallabag/UserBundle/Entity/User.php [moved from src/Wallabag/CoreBundle/Entity/User.php with 75% similarity]
src/Wallabag/UserBundle/Repository/UserRepository.php [moved from src/Wallabag/CoreBundle/Repository/UserRepository.php with 94% similarity]
src/Wallabag/UserBundle/Resources/config/services.yml [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register_content.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/checkEmail.html.twig [moved from src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/checkEmail.html.twig with 100% similarity]
src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request_content.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/baggy/Security/login.html.twig [moved from src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/login.html.twig with 72% similarity]
src/Wallabag/UserBundle/Resources/views/themes/baggy/layout.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/ChangePassword/changePassword_content.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Registration/checkEmail.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Registration/confirmed.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Registration/register_content.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/checkEmail.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/passwordAlreadyRequested.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/request_content.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/reset_content.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/Security/login.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/Resources/views/themes/material/layout.html.twig [new file with mode: 0644]
src/Wallabag/UserBundle/WallabagUserBundle.php [new file with mode: 0644]

index 08e14b8f755742465b2ccfeec8714ff7d1c8b56f..6315fcde9aa5b0f3be46aa66aa057ad03504e4de 100644 (file)
@@ -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'))) {
index f623ab237ca9de664b9045648a4c1b7627226264..0d893ecfbbcacad5d8bb3b44929a5cc7c5979f71 100644 (file)
@@ -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
index c45f0fa664fc354cfef929a6567f87af5f370bfa..342837a03137f7f2d10763f5ce9003b8d9154108 100644 (file)
@@ -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"
index e8bf08a570a7314866a2bf25baa08bfe75c7975d..af3e32b180178821a0451182690c5f735af3d717 100644 (file)
@@ -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"
index 9884665621055d82950cb0d4a3000fbee18cb5f6..576cfd25d7f7d41094f6c64004bd0c1ca93b143e 100644 (file)
@@ -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 }
index 965bc3195e68d69924753ef7929a85b15526d30d..ff6a582bb36bfee7b006168eaa5889badde0d69d 100644 (file)
@@ -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:
index babe9356da90e8a482165c19eab5cceea4d014a9..22cb277c4913cbec3cdf0504b632067208a94dc0 100644 (file)
@@ -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",
index 370d8ddd9d93b6fd4486159b916dce33db96c31f..606c3678d2dd9ad5ba151f3c51f23e5b507a9694 100644 (file)
@@ -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",
             ],
             "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",
             "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": ""
             },
             "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": ""
             },
             "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": ""
             },
         },
         {
             "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"
             },
             "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",
             "keywords": [
                 "framework"
             ],
-            "time": "2015-09-25 11:16:52"
+            "time": "2015-09-08 14:26:39"
         },
         {
             "name": "tecnickcom/tcpdf",
     "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,
index be18ce5af36850bc781b9550b834b64c529b6aed..c2562965bf665aa208ec69e6be33811d0da28457 100644 (file)
@@ -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
 
index d67d7247d335c00ed14e21486560a91a3609d886..ccd05b4d99b67bf758e372c771cb2f84d849982b 100644 (file)
@@ -1,2 +1,2 @@
 set :branch, 'v2'
-set :deploy_to, '/var/www/'
+set :deploy_to, '/var/www/v2.wallabag.org/web/'
index 349229f384524fd7c4bd03b6b13c52886ec48409..1fee56ad14693c812e8b0896a0693faf8dd41d14 100644 (file)
@@ -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());
         }
     }
 
diff --git a/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php b/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php
deleted file mode 100644 (file)
index 402eb86..0000000
+++ /dev/null
@@ -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)
-    {
-    }
-}
index c5cc204e029e984f894dd868159aac3d1fd630ec..cde43aedba37484cbc4f1078002700c31e485d69 100644 (file)
@@ -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()
diff --git a/src/Wallabag/ApiBundle/Entity/AccessToken.php b/src/Wallabag/ApiBundle/Entity/AccessToken.php
new file mode 100644 (file)
index 0000000..b1f4e7d
--- /dev/null
@@ -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;
+}
diff --git a/src/Wallabag/ApiBundle/Entity/AuthCode.php b/src/Wallabag/ApiBundle/Entity/AuthCode.php
new file mode 100644 (file)
index 0000000..8139815
--- /dev/null
@@ -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;
+}
diff --git a/src/Wallabag/ApiBundle/Entity/Client.php b/src/Wallabag/ApiBundle/Entity/Client.php
new file mode 100644 (file)
index 0000000..d449870
--- /dev/null
@@ -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();
+    }
+}
diff --git a/src/Wallabag/ApiBundle/Entity/RefreshToken.php b/src/Wallabag/ApiBundle/Entity/RefreshToken.php
new file mode 100644 (file)
index 0000000..be2c1d2
--- /dev/null
@@ -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;
+}
diff --git a/src/Wallabag/ApiBundle/Resources/config/services.yml b/src/Wallabag/ApiBundle/Resources/config/services.yml
deleted file mode 100644 (file)
index 6854a44..0000000
+++ /dev/null
@@ -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']
diff --git a/src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php b/src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php
deleted file mode 100644 (file)
index 9bf8b37..0000000
+++ /dev/null
@@ -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;
-    }
-}
diff --git a/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php b/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php
deleted file mode 100644 (file)
index e6d3022..0000000
+++ /dev/null
@@ -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 '';
-    }
-}
diff --git a/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php b/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php
deleted file mode 100644 (file)
index 2fcbe01..0000000
+++ /dev/null
@@ -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;
-        }
-    }
-}
diff --git a/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php b/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php
new file mode 100644 (file)
index 0000000..119889b
--- /dev/null
@@ -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;
+    }
+}
index 7ae54b576d577014bb3f5348235986973fc2b439..bc7ef4895a9fb8dbb81b76b0fe9619a474088138 100644 (file)
@@ -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');
-
-        $client->request('GET', '/api/entries', array(), array(), $headers);
+        $this->client->request('GET', '/api/entries');
 
-        $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->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');
-
-        $client->request('GET', '/api/entries', array('archive' => 1), array(), $headers);
+        $this->client->request('GET', '/api/entries', array('archive' => 1));
 
-        $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->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');
-
-        $client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
+        $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json');
 
-        $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');
-
-        $client->request('GET', '/api/tags.json', array(), array(), $headers);
+        $this->client->request('GET', '/api/tags.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->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');
-
-        $client->request('DELETE', '/api/tags/'.$tag['id'].'.json', array(), array(), $headers);
+        $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.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('label', $content);
         $this->assertEquals($tag['label'], $content['label']);
index 2484f277971bcc68fd5f04d5c5de604c818f448a..19d887aba8c72b530b1bba3ee804541c5d1e5d87 100644 (file)
@@ -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());
-    }
 }
index 1bd76ae36ec9db535b68ce33926d09228a886eec..6ebbd93c0e2d9cd04787b1ee9f62c9d808cd3749 100644 (file)
@@ -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);
 
index 5affdee894c66cd2c9afa342f685266b228e4734..ecfecc66daa1084fc71838c7684c6eb7e30f7b0e 100644 (file)
@@ -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'));
index 6121f36142ab730b503933f657c9a1700e7fabf2..023a6228eab246815ea46c184b378fa00981658d 100644 (file)
@@ -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
      */
diff --git a/src/Wallabag/CoreBundle/Controller/SecurityController.php b/src/Wallabag/CoreBundle/Controller/SecurityController.php
deleted file mode 100644 (file)
index f0a7ab6..0000000
+++ /dev/null
@@ -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;
-    }
-}
index 025d94efb605ee9ff1be2e1f86cadacb536d2d87..2390bfe17fbc89d9de8aff5305337a0e1589dd37 100644 (file)
@@ -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()
     {
index 9e81ba125de0a1cd7dc489daed78330eb97f052b..4fd74001b3efc076388f183fe794fea6180fba04 100644 (file)
@@ -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();
index 97c4579f70e8c1a607817a28ca5985912a2c8b3d..5b571823f707f11659f7da8c92707ff839d60917 100644 (file)
@@ -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();
diff --git a/src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php b/src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php
new file mode 100644 (file)
index 0000000..68c25f1
--- /dev/null
@@ -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();
+    }
+}
index 2e6d6ff765c8efb279c206a33f1da2b2b1119904..32de21ca8ab97efa04acd4cd185caa351753ebc7 100644 (file)
@@ -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
 {
diff --git a/src/Wallabag/CoreBundle/Form/Type/ForgotPasswordType.php b/src/Wallabag/CoreBundle/Form/Type/ForgotPasswordType.php
deleted file mode 100644 (file)
index 9e95eb4..0000000
+++ /dev/null
@@ -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
-            );
-        }
-    }
-}
index 985cb55b229a4a35dd6b3cfa8739ae8731048487..8aabc8bbbc40ecffdaabc6543e7a0928678329a9 100644 (file)
@@ -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',
         ));
     }
 
diff --git a/src/Wallabag/CoreBundle/Form/Type/ResetPasswordType.php b/src/Wallabag/CoreBundle/Form/Type/ResetPasswordType.php
deleted file mode 100644 (file)
index 38f1a10..0000000
+++ /dev/null
@@ -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';
-    }
-}
index e3196d9cc868def3cd4f633f705b1182e8041e05..84f020131908fb8038da4cd3a05a72aad9d0476d 100644 (file)
@@ -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',
         ));
     }
 
index 446629db2196ad5a76f460e2b5b45cd6e85c6ef8..679186c08415f3b9cd54c35edeafe1ea68ec5490 100644 (file)
@@ -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.
index 2771cf116ca64d7be5e70a68410cfec847ad8e50..f7faa2c131f58104f00b679810caccd90bb0d825 100644 (file)
@@ -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;
         }
 
index 3beb5d0ef86a56a3af267481f4481720df515973..c38787ded9040dac07844a2f5c6b5224209814d9 100644 (file)
@@ -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 }
index 152c5c28746dbb03c01625257057d5accc4cd316..c94c004414300314994562936ea8502ef614d554 100644 (file)
@@ -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>
index c90bb2e3b97db79667d4f6fe6c46d9caddc8d63c..64305b1631b85301c5a15ea048a29c1793e6adac 100644 (file)
         {{ 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) }}>
 
         <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>
 
         </fieldset>
 
         {{ form_rest(form.new_user) }}
+        {% endif %}
     </form>
 {% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/forgotPassword.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/forgotPassword.html.twig
deleted file mode 100644 (file)
index 4476ea7..0000000
+++ /dev/null
@@ -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 %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/reset.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/reset.html.twig
deleted file mode 100644 (file)
index fda88af..0000000
+++ /dev/null
@@ -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 %}
index 3d573eaa74f68a6ec8ff3098d9b16440aca15771..de4ed2e78e199527986a5a9c27d6a966ab1fcbcb 100644 (file)
@@ -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 %}
 
index 0ff21f223f4f1cff467c7cbcb07c6b3afb93b19a..0d8e9f2411e56b483a3f28486fc7e213fffc1c12 100644 (file)
@@ -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>
 
                         </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) }}
 
                             <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>
 
 
                         </form>
                     </div>
+                    {% endif %}
                 </div>
 
             </div>
index 4eb6d2b8c396d392298b27026ec73916d78eefe7..b0da42ce50d633a6f00cfef8fd81ed872344097d 100644 (file)
                             {% 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>
index 10dede8ae427531ca9e22c7bce4bc544100b3efe..36e276f96549f278bd5ec0a797b16eb5c806b1eb 100644 (file)
@@ -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>
index a5742905b124c74eff2d00393c9f3d5533cf2462..1fe4a53364fef6452eb59221fd274ad55ebacdab 100755 (executable)
@@ -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;
 }
index 32543a449079cba30d6b6d673f950a63fbcd06a1..c90aa46f857f029fc89b4080879451bf9d290f68 100755 (executable)
Binary files a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png and b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png differ
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php b/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php
deleted file mode 100644 (file)
index 98b4e86..0000000
+++ /dev/null
@@ -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));
-    }
-}
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Provider/WallabagAuthenticationProvider.php b/src/Wallabag/CoreBundle/Security/Authentication/Provider/WallabagAuthenticationProvider.php
deleted file mode 100644 (file)
index cf3cb05..0000000
+++ /dev/null
@@ -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;
-        }
-    }
-}
diff --git a/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php b/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php
deleted file mode 100644 (file)
index 5206277..0000000
+++ /dev/null
@@ -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);
-        }
-    }
-}
index 3407fc5e05ceec8f821b44b1ec616ca8c122b2e0..3da5e8b73de1b9458d10482ca63042ca4b008187 100644 (file)
@@ -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) {
index b7c162a77e0219b62ad1950d7d1fc3cfb5cd0ee8..45a74c43d071638744629b511fea943dff619eea 100644 (file)
@@ -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();
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/SecurityControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/SecurityControllerTest.php
deleted file mode 100644 (file)
index 759ef01..0000000
+++ /dev/null
@@ -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'));
-    }
-}
diff --git a/src/Wallabag/CoreBundle/Tests/EventListener/RegistrationConfirmedListenerTest.php b/src/Wallabag/CoreBundle/Tests/EventListener/RegistrationConfirmedListenerTest.php
new file mode 100644 (file)
index 0000000..df94fad
--- /dev/null
@@ -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
+        );
+    }
+}
index 0d33838941b067b4e049d4ffc99c2efcedaf9777..1d0d40628deef126cba9553e1bd069d3a2e88c6b 100644 (file)
@@ -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
index ebb550b57aae0aa3b0b6561a470639b8ad7df7ba..e28dc4bae527a7c724d2f1b89715ecd367bc9504 100644 (file)
@@ -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'));
 
diff --git a/src/Wallabag/UserBundle/Controller/ResettingController.php b/src/Wallabag/UserBundle/Controller/ResettingController.php
new file mode 100644 (file)
index 0000000..8aa1e23
--- /dev/null
@@ -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(),
+        ));
+    }
+}
similarity index 81%
rename from src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
rename to src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php
index 4ef53329c36b648b7f7a1f55d70c5b494b6877dc..d48855da76f0f43f6dd03622d2fdbd0d2cf0096e 100644 (file)
@@ -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);
similarity index 75%
rename from src/Wallabag/CoreBundle/Entity/User.php
rename to src/Wallabag/UserBundle/Entity/User.php
index a6002352376f8557a39e5f93ec5e08885c158ed8..8f02e070e8b10ab295a33d45441c3e1e7fcb3e96 100644 (file)
@@ -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()
     {
similarity index 94%
rename from src/Wallabag/CoreBundle/Repository/UserRepository.php
rename to src/Wallabag/UserBundle/Repository/UserRepository.php
index 968d0b49791e436e5d537d7ef3d1f892d1569684..c020f3ca9478a6418ec1e4bc6732610a5999fe7b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-namespace Wallabag\CoreBundle\Repository;
+namespace Wallabag\UserBundle\Repository;
 
 use Doctrine\ORM\EntityRepository;
 
diff --git a/src/Wallabag/UserBundle/Resources/config/services.yml b/src/Wallabag/UserBundle/Resources/config/services.yml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register.html.twig
new file mode 100644 (file)
index 0000000..e5c1876
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register_content.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register_content.html.twig
new file mode 100644 (file)
index 0000000..41f9400
--- /dev/null
@@ -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>
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request.html.twig
new file mode 100644 (file)
index 0000000..10094e8
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request_content.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request_content.html.twig
new file mode 100644 (file)
index 0000000..1f8da8d
--- /dev/null
@@ -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>
similarity index 72%
rename from src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/login.html.twig
rename to src/Wallabag/UserBundle/Resources/views/themes/baggy/Security/login.html.twig
index 5437d20c4aca12f2769ef0f8aa78fcec29152184..d52c3662934ca3ba70652d02892cf557c4234782 100644 (file)
@@ -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>
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/baggy/layout.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/layout.html.twig
new file mode 100644 (file)
index 0000000..ff5b658
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/ChangePassword/changePassword_content.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/ChangePassword/changePassword_content.html.twig
new file mode 100644 (file)
index 0000000..e7b7318
--- /dev/null
@@ -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>
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/checkEmail.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/checkEmail.html.twig
new file mode 100644 (file)
index 0000000..5093727
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/confirmed.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/confirmed.html.twig
new file mode 100644 (file)
index 0000000..c6d4d3d
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/register_content.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/register_content.html.twig
new file mode 100644 (file)
index 0000000..865a24a
--- /dev/null
@@ -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>
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/checkEmail.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/checkEmail.html.twig
new file mode 100644 (file)
index 0000000..66cbdc2
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/passwordAlreadyRequested.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/passwordAlreadyRequested.html.twig
new file mode 100644 (file)
index 0000000..0eec430
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/request_content.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/request_content.html.twig
new file mode 100644 (file)
index 0000000..e871d7b
--- /dev/null
@@ -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>
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/reset_content.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/reset_content.html.twig
new file mode 100644 (file)
index 0000000..f7e061d
--- /dev/null
@@ -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>
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/Security/login.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/Security/login.html.twig
new file mode 100644 (file)
index 0000000..6bf99bf
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/material/layout.html.twig
new file mode 100644 (file)
index 0000000..a69e68c
--- /dev/null
@@ -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 %}
diff --git a/src/Wallabag/UserBundle/WallabagUserBundle.php b/src/Wallabag/UserBundle/WallabagUserBundle.php
new file mode 100644 (file)
index 0000000..d9180b3
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+namespace Wallabag\UserBundle;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+class WallabagUserBundle extends Bundle
+{
+    public function getParent()
+    {
+        return 'FOSUserBundle';
+    }
+}