diff options
author | Jeremy Benoist <j0k3r@users.noreply.github.com> | 2015-10-06 09:19:06 +0200 |
---|---|---|
committer | Jeremy Benoist <j0k3r@users.noreply.github.com> | 2015-10-06 09:19:06 +0200 |
commit | 16dabc326311f084d671be188c7941bbb3c341c9 (patch) | |
tree | 3210a7688ea2bfa1bff5fd0422b52adf570edcdc /src/Wallabag | |
parent | fdef5f460524215d806e244e5546865f4b8e01df (diff) | |
parent | 8263e71192989dc0fd28a41ac22f9c5b32eb11c4 (diff) | |
download | wallabag-16dabc326311f084d671be188c7941bbb3c341c9.tar.gz wallabag-16dabc326311f084d671be188c7941bbb3c341c9.tar.zst wallabag-16dabc326311f084d671be188c7941bbb3c341c9.zip |
Merge pull request #1436 from wallabag/v2-register
Public registration & oAuth2 \o/
Diffstat (limited to 'src/Wallabag')
72 files changed, 964 insertions, 1295 deletions
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 349229f3..1fee56ad 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ApiBundle\Controller; | 3 | namespace Wallabag\ApiBundle\Controller; |
4 | 4 | ||
5 | use FOS\RestBundle\Controller\FOSRestController; | ||
5 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | 6 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||
7 | use Symfony\Component\HttpFoundation\Request; | 7 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\HttpFoundation\Response; | 8 | use Symfony\Component\HttpFoundation\Response; |
9 | use Wallabag\CoreBundle\Entity\Entry; | 9 | use Wallabag\CoreBundle\Entity\Entry; |
@@ -11,7 +11,7 @@ use Wallabag\CoreBundle\Entity\Tag; | |||
11 | use Hateoas\Configuration\Route; | 11 | use Hateoas\Configuration\Route; |
12 | use Hateoas\Representation\Factory\PagerfantaFactory; | 12 | use Hateoas\Representation\Factory\PagerfantaFactory; |
13 | 13 | ||
14 | class WallabagRestController extends Controller | 14 | class WallabagRestController extends FOSRestController |
15 | { | 15 | { |
16 | /** | 16 | /** |
17 | * @param Entry $entry | 17 | * @param Entry $entry |
@@ -38,29 +38,11 @@ class WallabagRestController extends Controller | |||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
41 | /** | 41 | private function validateAuthentication() |
42 | * Retrieve salt for a giver user. | ||
43 | * | ||
44 | * @ApiDoc( | ||
45 | * parameters={ | ||
46 | * {"name"="username", "dataType"="string", "required"=true, "description"="username"} | ||
47 | * } | ||
48 | * ) | ||
49 | * | ||
50 | * @return array | ||
51 | */ | ||
52 | public function getSaltAction($username) | ||
53 | { | 42 | { |
54 | $user = $this | 43 | if (false === $this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) { |
55 | ->getDoctrine() | 44 | throw new AccessDeniedException(); |
56 | ->getRepository('WallabagCoreBundle:User') | ||
57 | ->findOneByUsername($username); | ||
58 | |||
59 | if (is_null($user)) { | ||
60 | throw $this->createNotFoundException(); | ||
61 | } | 45 | } |
62 | |||
63 | return array($user->getSalt() ?: null); | ||
64 | } | 46 | } |
65 | 47 | ||
66 | /** | 48 | /** |
@@ -82,6 +64,8 @@ class WallabagRestController extends Controller | |||
82 | */ | 64 | */ |
83 | public function getEntriesAction(Request $request) | 65 | public function getEntriesAction(Request $request) |
84 | { | 66 | { |
67 | $this->validateAuthentication(); | ||
68 | |||
85 | $isArchived = $request->query->get('archive'); | 69 | $isArchived = $request->query->get('archive'); |
86 | $isStarred = $request->query->get('star'); | 70 | $isStarred = $request->query->get('star'); |
87 | $sort = $request->query->get('sort', 'created'); | 71 | $sort = $request->query->get('sort', 'created'); |
@@ -122,7 +106,8 @@ class WallabagRestController extends Controller | |||
122 | */ | 106 | */ |
123 | public function getEntryAction(Entry $entry) | 107 | public function getEntryAction(Entry $entry) |
124 | { | 108 | { |
125 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 109 | $this->validateAuthentication(); |
110 | $this->validateUserAccess($entry->getUser()->getId()); | ||
126 | 111 | ||
127 | $json = $this->get('serializer')->serialize($entry, 'json'); | 112 | $json = $this->get('serializer')->serialize($entry, 'json'); |
128 | 113 | ||
@@ -144,6 +129,8 @@ class WallabagRestController extends Controller | |||
144 | */ | 129 | */ |
145 | public function postEntriesAction(Request $request) | 130 | public function postEntriesAction(Request $request) |
146 | { | 131 | { |
132 | $this->validateAuthentication(); | ||
133 | |||
147 | $url = $request->request->get('url'); | 134 | $url = $request->request->get('url'); |
148 | 135 | ||
149 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( | 136 | $entry = $this->get('wallabag_core.content_proxy')->updateEntry( |
@@ -184,7 +171,8 @@ class WallabagRestController extends Controller | |||
184 | */ | 171 | */ |
185 | public function patchEntriesAction(Entry $entry, Request $request) | 172 | public function patchEntriesAction(Entry $entry, Request $request) |
186 | { | 173 | { |
187 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 174 | $this->validateAuthentication(); |
175 | $this->validateUserAccess($entry->getUser()->getId()); | ||
188 | 176 | ||
189 | $title = $request->request->get('title'); | 177 | $title = $request->request->get('title'); |
190 | $isArchived = $request->request->get('is_archived'); | 178 | $isArchived = $request->request->get('is_archived'); |
@@ -228,7 +216,8 @@ class WallabagRestController extends Controller | |||
228 | */ | 216 | */ |
229 | public function deleteEntriesAction(Entry $entry) | 217 | public function deleteEntriesAction(Entry $entry) |
230 | { | 218 | { |
231 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 219 | $this->validateAuthentication(); |
220 | $this->validateUserAccess($entry->getUser()->getId()); | ||
232 | 221 | ||
233 | $em = $this->getDoctrine()->getManager(); | 222 | $em = $this->getDoctrine()->getManager(); |
234 | $em->remove($entry); | 223 | $em->remove($entry); |
@@ -250,7 +239,8 @@ class WallabagRestController extends Controller | |||
250 | */ | 239 | */ |
251 | public function getEntriesTagsAction(Entry $entry) | 240 | public function getEntriesTagsAction(Entry $entry) |
252 | { | 241 | { |
253 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 242 | $this->validateAuthentication(); |
243 | $this->validateUserAccess($entry->getUser()->getId()); | ||
254 | 244 | ||
255 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); | 245 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); |
256 | 246 | ||
@@ -271,7 +261,8 @@ class WallabagRestController extends Controller | |||
271 | */ | 261 | */ |
272 | public function postEntriesTagsAction(Request $request, Entry $entry) | 262 | public function postEntriesTagsAction(Request $request, Entry $entry) |
273 | { | 263 | { |
274 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 264 | $this->validateAuthentication(); |
265 | $this->validateUserAccess($entry->getUser()->getId()); | ||
275 | 266 | ||
276 | $tags = $request->request->get('tags', ''); | 267 | $tags = $request->request->get('tags', ''); |
277 | if (!empty($tags)) { | 268 | if (!empty($tags)) { |
@@ -299,7 +290,8 @@ class WallabagRestController extends Controller | |||
299 | */ | 290 | */ |
300 | public function deleteEntriesTagsAction(Entry $entry, Tag $tag) | 291 | public function deleteEntriesTagsAction(Entry $entry, Tag $tag) |
301 | { | 292 | { |
302 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 293 | $this->validateAuthentication(); |
294 | $this->validateUserAccess($entry->getUser()->getId()); | ||
303 | 295 | ||
304 | $entry->removeTag($tag); | 296 | $entry->removeTag($tag); |
305 | $em = $this->getDoctrine()->getManager(); | 297 | $em = $this->getDoctrine()->getManager(); |
@@ -318,6 +310,7 @@ class WallabagRestController extends Controller | |||
318 | */ | 310 | */ |
319 | public function getTagsAction() | 311 | public function getTagsAction() |
320 | { | 312 | { |
313 | $this->validateAuthentication(); | ||
321 | $json = $this->get('serializer')->serialize($this->getUser()->getTags(), 'json'); | 314 | $json = $this->get('serializer')->serialize($this->getUser()->getTags(), 'json'); |
322 | 315 | ||
323 | return $this->renderJsonResponse($json); | 316 | return $this->renderJsonResponse($json); |
@@ -334,7 +327,8 @@ class WallabagRestController extends Controller | |||
334 | */ | 327 | */ |
335 | public function deleteTagAction(Tag $tag) | 328 | public function deleteTagAction(Tag $tag) |
336 | { | 329 | { |
337 | $this->validateUserAccess($tag->getUser()->getId(), $this->getUser()->getId()); | 330 | $this->validateAuthentication(); |
331 | $this->validateUserAccess($tag->getUser()->getId()); | ||
338 | 332 | ||
339 | $em = $this->getDoctrine()->getManager(); | 333 | $em = $this->getDoctrine()->getManager(); |
340 | $em->remove($tag); | 334 | $em->remove($tag); |
@@ -350,12 +344,12 @@ class WallabagRestController extends Controller | |||
350 | * If not, throw exception. It means a user try to access information from an other user. | 344 | * If not, throw exception. It means a user try to access information from an other user. |
351 | * | 345 | * |
352 | * @param int $requestUserId User id from the requested source | 346 | * @param int $requestUserId User id from the requested source |
353 | * @param int $currentUserId User id from the retrieved source | ||
354 | */ | 347 | */ |
355 | private function validateUserAccess($requestUserId, $currentUserId) | 348 | private function validateUserAccess($requestUserId) |
356 | { | 349 | { |
357 | if ($requestUserId != $currentUserId) { | 350 | $user = $this->get('security.context')->getToken()->getUser(); |
358 | throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$currentUserId); | 351 | if ($requestUserId != $user->getId()) { |
352 | throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId()); | ||
359 | } | 353 | } |
360 | } | 354 | } |
361 | 355 | ||
diff --git a/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php b/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php deleted file mode 100644 index 402eb869..00000000 --- a/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\DependencyInjection\Security\Factory; | ||
4 | |||
5 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
6 | use Symfony\Component\DependencyInjection\Reference; | ||
7 | use Symfony\Component\DependencyInjection\DefinitionDecorator; | ||
8 | use Symfony\Component\Config\Definition\Builder\NodeDefinition; | ||
9 | use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; | ||
10 | |||
11 | class WsseFactory implements SecurityFactoryInterface | ||
12 | { | ||
13 | public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) | ||
14 | { | ||
15 | $providerId = 'security.authentication.provider.wsse.'.$id; | ||
16 | $container | ||
17 | ->setDefinition($providerId, new DefinitionDecorator('wsse.security.authentication.provider')) | ||
18 | ->replaceArgument(0, new Reference($userProvider)) | ||
19 | ; | ||
20 | |||
21 | $listenerId = 'security.authentication.listener.wsse.'.$id; | ||
22 | $listener = $container->setDefinition($listenerId, new DefinitionDecorator('wsse.security.authentication.listener')); | ||
23 | |||
24 | return array($providerId, $listenerId, $defaultEntryPoint); | ||
25 | } | ||
26 | |||
27 | public function getPosition() | ||
28 | { | ||
29 | return 'pre_auth'; | ||
30 | } | ||
31 | |||
32 | public function getKey() | ||
33 | { | ||
34 | return 'wsse'; | ||
35 | } | ||
36 | |||
37 | public function addConfiguration(NodeDefinition $node) | ||
38 | { | ||
39 | } | ||
40 | } | ||
diff --git a/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php b/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php index c5cc204e..cde43aed 100644 --- a/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php +++ b/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php | |||
@@ -3,9 +3,7 @@ | |||
3 | namespace Wallabag\ApiBundle\DependencyInjection; | 3 | namespace Wallabag\ApiBundle\DependencyInjection; |
4 | 4 | ||
5 | use Symfony\Component\DependencyInjection\ContainerBuilder; | 5 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
6 | use Symfony\Component\Config\FileLocator; | ||
7 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; | 6 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; |
8 | use Symfony\Component\DependencyInjection\Loader; | ||
9 | 7 | ||
10 | class WallabagApiExtension extends Extension | 8 | class WallabagApiExtension extends Extension |
11 | { | 9 | { |
@@ -13,9 +11,6 @@ class WallabagApiExtension extends Extension | |||
13 | { | 11 | { |
14 | $configuration = new Configuration(); | 12 | $configuration = new Configuration(); |
15 | $config = $this->processConfiguration($configuration, $configs); | 13 | $config = $this->processConfiguration($configuration, $configs); |
16 | |||
17 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | ||
18 | $loader->load('services.yml'); | ||
19 | } | 14 | } |
20 | 15 | ||
21 | public function getAlias() | 16 | public function getAlias() |
diff --git a/src/Wallabag/ApiBundle/Entity/AccessToken.php b/src/Wallabag/ApiBundle/Entity/AccessToken.php new file mode 100644 index 00000000..b1f4e7de --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/AccessToken.php | |||
@@ -0,0 +1,31 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_access_tokens") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class AccessToken extends BaseAccessToken | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | /** | ||
22 | * @ORM\ManyToOne(targetEntity="Client") | ||
23 | * @ORM\JoinColumn(nullable=false) | ||
24 | */ | ||
25 | protected $client; | ||
26 | |||
27 | /** | ||
28 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") | ||
29 | */ | ||
30 | protected $user; | ||
31 | } | ||
diff --git a/src/Wallabag/ApiBundle/Entity/AuthCode.php b/src/Wallabag/ApiBundle/Entity/AuthCode.php new file mode 100644 index 00000000..81398158 --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/AuthCode.php | |||
@@ -0,0 +1,31 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_auth_codes") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class AuthCode extends BaseAuthCode | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | /** | ||
22 | * @ORM\ManyToOne(targetEntity="Client") | ||
23 | * @ORM\JoinColumn(nullable=false) | ||
24 | */ | ||
25 | protected $client; | ||
26 | |||
27 | /** | ||
28 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") | ||
29 | */ | ||
30 | protected $user; | ||
31 | } | ||
diff --git a/src/Wallabag/ApiBundle/Entity/Client.php b/src/Wallabag/ApiBundle/Entity/Client.php new file mode 100644 index 00000000..d449870a --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/Client.php | |||
@@ -0,0 +1,25 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\Client as BaseClient; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_clients") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class Client extends BaseClient | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | public function __construct() | ||
22 | { | ||
23 | parent::__construct(); | ||
24 | } | ||
25 | } | ||
diff --git a/src/Wallabag/ApiBundle/Entity/RefreshToken.php b/src/Wallabag/ApiBundle/Entity/RefreshToken.php new file mode 100644 index 00000000..be2c1d2e --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/RefreshToken.php | |||
@@ -0,0 +1,31 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_refresh_tokens") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class RefreshToken extends BaseRefreshToken | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | /** | ||
22 | * @ORM\ManyToOne(targetEntity="Client") | ||
23 | * @ORM\JoinColumn(nullable=false) | ||
24 | */ | ||
25 | protected $client; | ||
26 | |||
27 | /** | ||
28 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User") | ||
29 | */ | ||
30 | protected $user; | ||
31 | } | ||
diff --git a/src/Wallabag/ApiBundle/Resources/config/services.yml b/src/Wallabag/ApiBundle/Resources/config/services.yml deleted file mode 100644 index 6854a444..00000000 --- a/src/Wallabag/ApiBundle/Resources/config/services.yml +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | services: | ||
2 | wsse.security.authentication.provider: | ||
3 | class: Wallabag\ApiBundle\Security\Authentication\Provider\WsseProvider | ||
4 | public: false | ||
5 | arguments: ['', '%kernel.cache_dir%/security/nonces'] | ||
6 | |||
7 | wsse.security.authentication.listener: | ||
8 | class: Wallabag\ApiBundle\Security\Firewall\WsseListener | ||
9 | public: false | ||
10 | tags: | ||
11 | - { name: monolog.logger, channel: wsse } | ||
12 | 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 index 9bf8b377..00000000 --- a/src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Security\Authentication\Provider; | ||
4 | |||
5 | use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; | ||
6 | use Symfony\Component\Security\Core\User\UserProviderInterface; | ||
7 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
8 | use Symfony\Component\Security\Core\Exception\NonceExpiredException; | ||
9 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
10 | use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken; | ||
11 | |||
12 | class WsseProvider implements AuthenticationProviderInterface | ||
13 | { | ||
14 | private $userProvider; | ||
15 | private $cacheDir; | ||
16 | |||
17 | public function __construct(UserProviderInterface $userProvider, $cacheDir) | ||
18 | { | ||
19 | $this->userProvider = $userProvider; | ||
20 | $this->cacheDir = $cacheDir; | ||
21 | |||
22 | // If cache directory does not exist we create it | ||
23 | if (!is_dir($this->cacheDir)) { | ||
24 | mkdir($this->cacheDir, 0777, true); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | public function authenticate(TokenInterface $token) | ||
29 | { | ||
30 | $user = $this->userProvider->loadUserByUsername($token->getUsername()); | ||
31 | |||
32 | if (!$user) { | ||
33 | throw new AuthenticationException('Bad credentials. Did you forgot your username?'); | ||
34 | } | ||
35 | |||
36 | if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) { | ||
37 | $authenticatedToken = new WsseUserToken($user->getRoles()); | ||
38 | $authenticatedToken->setUser($user); | ||
39 | |||
40 | return $authenticatedToken; | ||
41 | } | ||
42 | |||
43 | throw new AuthenticationException('The WSSE authentication failed.'); | ||
44 | } | ||
45 | |||
46 | protected function validateDigest($digest, $nonce, $created, $secret) | ||
47 | { | ||
48 | // Check created time is not in the future | ||
49 | if (strtotime($created) > time()) { | ||
50 | throw new AuthenticationException('Back to the future...'); | ||
51 | } | ||
52 | |||
53 | // Expire timestamp after 5 minutes | ||
54 | if (time() - strtotime($created) > 300) { | ||
55 | throw new AuthenticationException('Too late for this timestamp... Watch your watch.'); | ||
56 | } | ||
57 | |||
58 | // Validate nonce is unique within 5 minutes | ||
59 | if (file_exists($this->cacheDir.'/'.$nonce) && file_get_contents($this->cacheDir.'/'.$nonce) + 300 > time()) { | ||
60 | throw new NonceExpiredException('Previously used nonce detected'); | ||
61 | } | ||
62 | |||
63 | file_put_contents($this->cacheDir.'/'.$nonce, time()); | ||
64 | |||
65 | // Validate Secret | ||
66 | $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true)); | ||
67 | |||
68 | if ($digest !== $expected) { | ||
69 | throw new AuthenticationException('Bad credentials ! Digest is not as expected.'); | ||
70 | } | ||
71 | |||
72 | return $digest === $expected; | ||
73 | } | ||
74 | |||
75 | public function supports(TokenInterface $token) | ||
76 | { | ||
77 | return $token instanceof WsseUserToken; | ||
78 | } | ||
79 | } | ||
diff --git a/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php b/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php deleted file mode 100644 index e6d30224..00000000 --- a/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Security\Authentication\Token; | ||
4 | |||
5 | use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; | ||
6 | |||
7 | class WsseUserToken extends AbstractToken | ||
8 | { | ||
9 | public $created; | ||
10 | public $digest; | ||
11 | public $nonce; | ||
12 | |||
13 | public function __construct(array $roles = array()) | ||
14 | { | ||
15 | parent::__construct($roles); | ||
16 | |||
17 | $this->setAuthenticated(count($roles) > 0); | ||
18 | } | ||
19 | |||
20 | public function getCredentials() | ||
21 | { | ||
22 | return ''; | ||
23 | } | ||
24 | } | ||
diff --git a/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php b/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php deleted file mode 100644 index 2fcbe014..00000000 --- a/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php +++ /dev/null | |||
@@ -1,62 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Security\Firewall; | ||
4 | |||
5 | use Symfony\Component\HttpFoundation\Response; | ||
6 | use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
7 | use Symfony\Component\Security\Http\Firewall\ListenerInterface; | ||
8 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
9 | use Symfony\Component\Security\Core\SecurityContextInterface; | ||
10 | use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; | ||
11 | use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken; | ||
12 | use Psr\Log\LoggerInterface; | ||
13 | |||
14 | class WsseListener implements ListenerInterface | ||
15 | { | ||
16 | protected $securityContext; | ||
17 | protected $authenticationManager; | ||
18 | protected $logger; | ||
19 | |||
20 | public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger) | ||
21 | { | ||
22 | $this->securityContext = $securityContext; | ||
23 | $this->authenticationManager = $authenticationManager; | ||
24 | $this->logger = $logger; | ||
25 | } | ||
26 | |||
27 | public function handle(GetResponseEvent $event) | ||
28 | { | ||
29 | $request = $event->getRequest(); | ||
30 | |||
31 | $wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/'; | ||
32 | if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) { | ||
33 | return; | ||
34 | } | ||
35 | |||
36 | $token = new WsseUserToken(); | ||
37 | $token->setUser($matches[1]); | ||
38 | |||
39 | $token->digest = $matches[2]; | ||
40 | $token->nonce = $matches[3]; | ||
41 | $token->created = $matches[4]; | ||
42 | |||
43 | try { | ||
44 | $authToken = $this->authenticationManager->authenticate($token); | ||
45 | |||
46 | $this->securityContext->setToken($authToken); | ||
47 | |||
48 | return; | ||
49 | } catch (AuthenticationException $failed) { | ||
50 | $failedMessage = 'WSSE Login failed for '.$token->getUsername().'. Why ? '.$failed->getMessage(); | ||
51 | $this->logger->err($failedMessage); | ||
52 | |||
53 | // Deny authentication with a '403 Forbidden' HTTP response | ||
54 | $response = new Response(); | ||
55 | $response->setStatusCode(403); | ||
56 | $response->setContent($failedMessage); | ||
57 | $event->setResponse($response); | ||
58 | |||
59 | return; | ||
60 | } | ||
61 | } | ||
62 | } | ||
diff --git a/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php b/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php new file mode 100644 index 00000000..119889b3 --- /dev/null +++ b/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php | |||
@@ -0,0 +1,46 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Tests; | ||
4 | |||
5 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; | ||
6 | use Symfony\Component\BrowserKit\Cookie; | ||
7 | |||
8 | abstract class AbstractControllerTest extends WebTestCase | ||
9 | { | ||
10 | /** | ||
11 | * @var Client | ||
12 | */ | ||
13 | protected $client = null; | ||
14 | |||
15 | public function setUp() | ||
16 | { | ||
17 | $this->client = $this->createAuthorizedClient(); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * @return Client | ||
22 | */ | ||
23 | protected function createAuthorizedClient() | ||
24 | { | ||
25 | $client = static::createClient(); | ||
26 | $container = $client->getContainer(); | ||
27 | |||
28 | $session = $container->get('session'); | ||
29 | /** @var $userManager \FOS\UserBundle\Doctrine\UserManager */ | ||
30 | $userManager = $container->get('fos_user.user_manager'); | ||
31 | /** @var $loginManager \FOS\UserBundle\Security\LoginManager */ | ||
32 | $loginManager = $container->get('fos_user.security.login_manager'); | ||
33 | $firewallName = $container->getParameter('fos_user.firewall_name'); | ||
34 | |||
35 | $user = $userManager->findUserBy(array('username' => 'admin')); | ||
36 | $loginManager->loginUser($firewallName, $user); | ||
37 | |||
38 | // save the login token into the session and put it in a cookie | ||
39 | $container->get('session')->set('_security_'.$firewallName, | ||
40 | serialize($container->get('security.context')->getToken())); | ||
41 | $container->get('session')->save(); | ||
42 | $client->getCookieJar()->set(new Cookie($session->getName(), $session->getId())); | ||
43 | |||
44 | return $client; | ||
45 | } | ||
46 | } | ||
diff --git a/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php b/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php index 7ae54b57..bc7ef489 100644 --- a/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php +++ b/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php | |||
@@ -2,99 +2,15 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ApiBundle\Tests\Controller; | 3 | namespace Wallabag\ApiBundle\Tests\Controller; |
4 | 4 | ||
5 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; | 5 | use Wallabag\ApiBundle\Tests\AbstractControllerTest; |
6 | 6 | ||
7 | class WallabagRestControllerTest extends WebTestCase | 7 | class WallabagRestControllerTest extends AbstractControllerTest |
8 | { | 8 | { |
9 | protected static $salt; | 9 | protected static $salt; |
10 | 10 | ||
11 | /** | ||
12 | * Grab the salt once and store it to be available for all tests. | ||
13 | */ | ||
14 | public static function setUpBeforeClass() | ||
15 | { | ||
16 | $client = self::createClient(); | ||
17 | |||
18 | $user = $client->getContainer() | ||
19 | ->get('doctrine.orm.entity_manager') | ||
20 | ->getRepository('WallabagCoreBundle:User') | ||
21 | ->findOneByUsername('admin'); | ||
22 | |||
23 | self::$salt = $user->getSalt(); | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * Generate HTTP headers for authenticate user on API. | ||
28 | * | ||
29 | * @param string $username | ||
30 | * @param string $password | ||
31 | * | ||
32 | * @return array | ||
33 | */ | ||
34 | private function generateHeaders($username, $password) | ||
35 | { | ||
36 | $encryptedPassword = sha1($password.$username.self::$salt); | ||
37 | $nonce = substr(md5(uniqid('nonce_', true)), 0, 16); | ||
38 | |||
39 | $now = new \DateTime('now', new \DateTimeZone('UTC')); | ||
40 | $created = (string) $now->format('Y-m-d\TH:i:s\Z'); | ||
41 | $digest = base64_encode(sha1(base64_decode($nonce).$created.$encryptedPassword, true)); | ||
42 | |||
43 | return array( | ||
44 | 'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"', | ||
45 | 'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="'.$username.'", PasswordDigest="'.$digest.'", Nonce="'.$nonce.'", Created="'.$created.'"', | ||
46 | ); | ||
47 | } | ||
48 | |||
49 | public function testGetSalt() | ||
50 | { | ||
51 | $client = $this->createClient(); | ||
52 | $client->request('GET', '/api/salts/admin.json'); | ||
53 | |||
54 | $user = $client->getContainer() | ||
55 | ->get('doctrine.orm.entity_manager') | ||
56 | ->getRepository('WallabagCoreBundle:User') | ||
57 | ->findOneByUsername('admin'); | ||
58 | |||
59 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||
60 | |||
61 | $content = json_decode($client->getResponse()->getContent(), true); | ||
62 | |||
63 | $this->assertArrayHasKey(0, $content); | ||
64 | $this->assertEquals($user->getSalt(), $content[0]); | ||
65 | |||
66 | $client->request('GET', '/api/salts/notfound.json'); | ||
67 | $this->assertEquals(404, $client->getResponse()->getStatusCode()); | ||
68 | } | ||
69 | |||
70 | public function testWithBadHeaders() | ||
71 | { | ||
72 | $client = $this->createClient(); | ||
73 | |||
74 | $entry = $client->getContainer() | ||
75 | ->get('doctrine.orm.entity_manager') | ||
76 | ->getRepository('WallabagCoreBundle:Entry') | ||
77 | ->findOneByIsArchived(false); | ||
78 | |||
79 | if (!$entry) { | ||
80 | $this->markTestSkipped('No content found in db.'); | ||
81 | } | ||
82 | |||
83 | $badHeaders = array( | ||
84 | 'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"', | ||
85 | 'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="admin", PasswordDigest="Wr0ngDig3st", Nonce="n0Nc3", Created="2015-01-01T13:37:00Z"', | ||
86 | ); | ||
87 | |||
88 | $client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $badHeaders); | ||
89 | $this->assertEquals(403, $client->getResponse()->getStatusCode()); | ||
90 | } | ||
91 | |||
92 | public function testGetOneEntry() | 11 | public function testGetOneEntry() |
93 | { | 12 | { |
94 | $client = $this->createClient(); | 13 | $entry = $this->client->getContainer() |
95 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
96 | |||
97 | $entry = $client->getContainer() | ||
98 | ->get('doctrine.orm.entity_manager') | 14 | ->get('doctrine.orm.entity_manager') |
99 | ->getRepository('WallabagCoreBundle:Entry') | 15 | ->getRepository('WallabagCoreBundle:Entry') |
100 | ->findOneBy(array('user' => 1, 'isArchived' => false)); | 16 | ->findOneBy(array('user' => 1, 'isArchived' => false)); |
@@ -103,18 +19,17 @@ class WallabagRestControllerTest extends WebTestCase | |||
103 | $this->markTestSkipped('No content found in db.'); | 19 | $this->markTestSkipped('No content found in db.'); |
104 | } | 20 | } |
105 | 21 | ||
106 | $client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | 22 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); |
23 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
107 | 24 | ||
108 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 25 | $content = json_decode($this->client->getResponse()->getContent(), true); |
109 | |||
110 | $content = json_decode($client->getResponse()->getContent(), true); | ||
111 | 26 | ||
112 | $this->assertEquals($entry->getTitle(), $content['title']); | 27 | $this->assertEquals($entry->getTitle(), $content['title']); |
113 | $this->assertEquals($entry->getUrl(), $content['url']); | 28 | $this->assertEquals($entry->getUrl(), $content['url']); |
114 | $this->assertCount(count($entry->getTags()), $content['tags']); | 29 | $this->assertCount(count($entry->getTags()), $content['tags']); |
115 | 30 | ||
116 | $this->assertTrue( | 31 | $this->assertTrue( |
117 | $client->getResponse()->headers->contains( | 32 | $this->client->getResponse()->headers->contains( |
118 | 'Content-Type', | 33 | 'Content-Type', |
119 | 'application/json' | 34 | 'application/json' |
120 | ) | 35 | ) |
@@ -123,10 +38,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
123 | 38 | ||
124 | public function testGetOneEntryWrongUser() | 39 | public function testGetOneEntryWrongUser() |
125 | { | 40 | { |
126 | $client = $this->createClient(); | 41 | $entry = $this->client->getContainer() |
127 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
128 | |||
129 | $entry = $client->getContainer() | ||
130 | ->get('doctrine.orm.entity_manager') | 42 | ->get('doctrine.orm.entity_manager') |
131 | ->getRepository('WallabagCoreBundle:Entry') | 43 | ->getRepository('WallabagCoreBundle:Entry') |
132 | ->findOneBy(array('user' => 2, 'isArchived' => false)); | 44 | ->findOneBy(array('user' => 2, 'isArchived' => false)); |
@@ -135,21 +47,18 @@ class WallabagRestControllerTest extends WebTestCase | |||
135 | $this->markTestSkipped('No content found in db.'); | 47 | $this->markTestSkipped('No content found in db.'); |
136 | } | 48 | } |
137 | 49 | ||
138 | $client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | 50 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); |
139 | 51 | ||
140 | $this->assertEquals(403, $client->getResponse()->getStatusCode()); | 52 | $this->assertEquals(403, $this->client->getResponse()->getStatusCode()); |
141 | } | 53 | } |
142 | 54 | ||
143 | public function testGetEntries() | 55 | public function testGetEntries() |
144 | { | 56 | { |
145 | $client = $this->createClient(); | 57 | $this->client->request('GET', '/api/entries'); |
146 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
147 | |||
148 | $client->request('GET', '/api/entries', array(), array(), $headers); | ||
149 | 58 | ||
150 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 59 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
151 | 60 | ||
152 | $content = json_decode($client->getResponse()->getContent(), true); | 61 | $content = json_decode($this->client->getResponse()->getContent(), true); |
153 | 62 | ||
154 | $this->assertGreaterThanOrEqual(1, count($content)); | 63 | $this->assertGreaterThanOrEqual(1, count($content)); |
155 | $this->assertNotEmpty($content['_embedded']['items']); | 64 | $this->assertNotEmpty($content['_embedded']['items']); |
@@ -158,7 +67,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
158 | $this->assertGreaterThanOrEqual(1, $content['pages']); | 67 | $this->assertGreaterThanOrEqual(1, $content['pages']); |
159 | 68 | ||
160 | $this->assertTrue( | 69 | $this->assertTrue( |
161 | $client->getResponse()->headers->contains( | 70 | $this->client->getResponse()->headers->contains( |
162 | 'Content-Type', | 71 | 'Content-Type', |
163 | 'application/json' | 72 | 'application/json' |
164 | ) | 73 | ) |
@@ -167,14 +76,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
167 | 76 | ||
168 | public function testGetStarredEntries() | 77 | public function testGetStarredEntries() |
169 | { | 78 | { |
170 | $client = $this->createClient(); | 79 | $this->client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated')); |
171 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
172 | 80 | ||
173 | $client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'), array(), $headers); | 81 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
174 | 82 | ||
175 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 83 | $content = json_decode($this->client->getResponse()->getContent(), true); |
176 | |||
177 | $content = json_decode($client->getResponse()->getContent(), true); | ||
178 | 84 | ||
179 | $this->assertGreaterThanOrEqual(1, count($content)); | 85 | $this->assertGreaterThanOrEqual(1, count($content)); |
180 | $this->assertNotEmpty($content['_embedded']['items']); | 86 | $this->assertNotEmpty($content['_embedded']['items']); |
@@ -183,7 +89,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
183 | $this->assertGreaterThanOrEqual(1, $content['pages']); | 89 | $this->assertGreaterThanOrEqual(1, $content['pages']); |
184 | 90 | ||
185 | $this->assertTrue( | 91 | $this->assertTrue( |
186 | $client->getResponse()->headers->contains( | 92 | $this->client->getResponse()->headers->contains( |
187 | 'Content-Type', | 93 | 'Content-Type', |
188 | 'application/json' | 94 | 'application/json' |
189 | ) | 95 | ) |
@@ -192,14 +98,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
192 | 98 | ||
193 | public function testGetArchiveEntries() | 99 | public function testGetArchiveEntries() |
194 | { | 100 | { |
195 | $client = $this->createClient(); | 101 | $this->client->request('GET', '/api/entries', array('archive' => 1)); |
196 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
197 | |||
198 | $client->request('GET', '/api/entries', array('archive' => 1), array(), $headers); | ||
199 | 102 | ||
200 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 103 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
201 | 104 | ||
202 | $content = json_decode($client->getResponse()->getContent(), true); | 105 | $content = json_decode($this->client->getResponse()->getContent(), true); |
203 | 106 | ||
204 | $this->assertGreaterThanOrEqual(1, count($content)); | 107 | $this->assertGreaterThanOrEqual(1, count($content)); |
205 | $this->assertNotEmpty($content['_embedded']['items']); | 108 | $this->assertNotEmpty($content['_embedded']['items']); |
@@ -208,7 +111,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
208 | $this->assertGreaterThanOrEqual(1, $content['pages']); | 111 | $this->assertGreaterThanOrEqual(1, $content['pages']); |
209 | 112 | ||
210 | $this->assertTrue( | 113 | $this->assertTrue( |
211 | $client->getResponse()->headers->contains( | 114 | $this->client->getResponse()->headers->contains( |
212 | 'Content-Type', | 115 | 'Content-Type', |
213 | 'application/json' | 116 | 'application/json' |
214 | ) | 117 | ) |
@@ -217,10 +120,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
217 | 120 | ||
218 | public function testDeleteEntry() | 121 | public function testDeleteEntry() |
219 | { | 122 | { |
220 | $client = $this->createClient(); | 123 | $entry = $this->client->getContainer() |
221 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
222 | |||
223 | $entry = $client->getContainer() | ||
224 | ->get('doctrine.orm.entity_manager') | 124 | ->get('doctrine.orm.entity_manager') |
225 | ->getRepository('WallabagCoreBundle:Entry') | 125 | ->getRepository('WallabagCoreBundle:Entry') |
226 | ->findOneByUser(1); | 126 | ->findOneByUser(1); |
@@ -229,36 +129,31 @@ class WallabagRestControllerTest extends WebTestCase | |||
229 | $this->markTestSkipped('No content found in db.'); | 129 | $this->markTestSkipped('No content found in db.'); |
230 | } | 130 | } |
231 | 131 | ||
232 | $client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | 132 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); |
233 | 133 | ||
234 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 134 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
235 | 135 | ||
236 | $content = json_decode($client->getResponse()->getContent(), true); | 136 | $content = json_decode($this->client->getResponse()->getContent(), true); |
237 | 137 | ||
238 | $this->assertEquals($entry->getTitle(), $content['title']); | 138 | $this->assertEquals($entry->getTitle(), $content['title']); |
239 | $this->assertEquals($entry->getUrl(), $content['url']); | 139 | $this->assertEquals($entry->getUrl(), $content['url']); |
240 | 140 | ||
241 | // We'll try to delete this entry again | 141 | // We'll try to delete this entry again |
242 | $headers = $this->generateHeaders('admin', 'mypassword'); | 142 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); |
243 | |||
244 | $client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | ||
245 | 143 | ||
246 | $this->assertEquals(404, $client->getResponse()->getStatusCode()); | 144 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); |
247 | } | 145 | } |
248 | 146 | ||
249 | public function testPostEntry() | 147 | public function testPostEntry() |
250 | { | 148 | { |
251 | $client = $this->createClient(); | 149 | $this->client->request('POST', '/api/entries.json', array( |
252 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
253 | |||
254 | $client->request('POST', '/api/entries.json', array( | ||
255 | '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', | 150 | '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', |
256 | 'tags' => 'google', | 151 | 'tags' => 'google', |
257 | ), array(), $headers); | 152 | )); |
258 | 153 | ||
259 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 154 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
260 | 155 | ||
261 | $content = json_decode($client->getResponse()->getContent(), true); | 156 | $content = json_decode($this->client->getResponse()->getContent(), true); |
262 | 157 | ||
263 | $this->assertGreaterThan(0, $content['id']); | 158 | $this->assertGreaterThan(0, $content['id']); |
264 | $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']); | 159 | $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 | |||
269 | 164 | ||
270 | public function testPatchEntry() | 165 | public function testPatchEntry() |
271 | { | 166 | { |
272 | $client = $this->createClient(); | 167 | $entry = $this->client->getContainer() |
273 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
274 | |||
275 | $entry = $client->getContainer() | ||
276 | ->get('doctrine.orm.entity_manager') | 168 | ->get('doctrine.orm.entity_manager') |
277 | ->getRepository('WallabagCoreBundle:Entry') | 169 | ->getRepository('WallabagCoreBundle:Entry') |
278 | ->findOneByUser(1); | 170 | ->findOneByUser(1); |
@@ -284,16 +176,16 @@ class WallabagRestControllerTest extends WebTestCase | |||
284 | // hydrate the tags relations | 176 | // hydrate the tags relations |
285 | $nbTags = count($entry->getTags()); | 177 | $nbTags = count($entry->getTags()); |
286 | 178 | ||
287 | $client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array( | 179 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array( |
288 | 'title' => 'New awesome title', | 180 | 'title' => 'New awesome title', |
289 | 'tags' => 'new tag '.uniqid(), | 181 | 'tags' => 'new tag '.uniqid(), |
290 | 'star' => true, | 182 | 'star' => true, |
291 | 'archive' => false, | 183 | 'archive' => false, |
292 | ), array(), $headers); | 184 | )); |
293 | 185 | ||
294 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 186 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
295 | 187 | ||
296 | $content = json_decode($client->getResponse()->getContent(), true); | 188 | $content = json_decode($this->client->getResponse()->getContent(), true); |
297 | 189 | ||
298 | $this->assertEquals($entry->getId(), $content['id']); | 190 | $this->assertEquals($entry->getId(), $content['id']); |
299 | $this->assertEquals($entry->getUrl(), $content['url']); | 191 | $this->assertEquals($entry->getUrl(), $content['url']); |
@@ -303,10 +195,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
303 | 195 | ||
304 | public function testGetTagsEntry() | 196 | public function testGetTagsEntry() |
305 | { | 197 | { |
306 | $client = $this->createClient(); | 198 | $entry = $this->client->getContainer() |
307 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
308 | |||
309 | $entry = $client->getContainer() | ||
310 | ->get('doctrine.orm.entity_manager') | 199 | ->get('doctrine.orm.entity_manager') |
311 | ->getRepository('WallabagCoreBundle:Entry') | 200 | ->getRepository('WallabagCoreBundle:Entry') |
312 | ->findOneWithTags(1); | 201 | ->findOneWithTags(1); |
@@ -322,17 +211,14 @@ class WallabagRestControllerTest extends WebTestCase | |||
322 | $tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel()); | 211 | $tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel()); |
323 | } | 212 | } |
324 | 213 | ||
325 | $client->request('GET', '/api/entries/'.$entry->getId().'/tags', array(), array(), $headers); | 214 | $this->client->request('GET', '/api/entries/'.$entry->getId().'/tags'); |
326 | 215 | ||
327 | $this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $client->getResponse()->getContent()); | 216 | $this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $this->client->getResponse()->getContent()); |
328 | } | 217 | } |
329 | 218 | ||
330 | public function testPostTagsOnEntry() | 219 | public function testPostTagsOnEntry() |
331 | { | 220 | { |
332 | $client = $this->createClient(); | 221 | $entry = $this->client->getContainer() |
333 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
334 | |||
335 | $entry = $client->getContainer() | ||
336 | ->get('doctrine.orm.entity_manager') | 222 | ->get('doctrine.orm.entity_manager') |
337 | ->getRepository('WallabagCoreBundle:Entry') | 223 | ->getRepository('WallabagCoreBundle:Entry') |
338 | ->findOneByUser(1); | 224 | ->findOneByUser(1); |
@@ -345,16 +231,16 @@ class WallabagRestControllerTest extends WebTestCase | |||
345 | 231 | ||
346 | $newTags = 'tag1,tag2,tag3'; | 232 | $newTags = 'tag1,tag2,tag3'; |
347 | 233 | ||
348 | $client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags), array(), $headers); | 234 | $this->client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags)); |
349 | 235 | ||
350 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 236 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
351 | 237 | ||
352 | $content = json_decode($client->getResponse()->getContent(), true); | 238 | $content = json_decode($this->client->getResponse()->getContent(), true); |
353 | 239 | ||
354 | $this->assertArrayHasKey('tags', $content); | 240 | $this->assertArrayHasKey('tags', $content); |
355 | $this->assertEquals($nbTags + 3, count($content['tags'])); | 241 | $this->assertEquals($nbTags + 3, count($content['tags'])); |
356 | 242 | ||
357 | $entryDB = $client->getContainer() | 243 | $entryDB = $this->client->getContainer() |
358 | ->get('doctrine.orm.entity_manager') | 244 | ->get('doctrine.orm.entity_manager') |
359 | ->getRepository('WallabagCoreBundle:Entry') | 245 | ->getRepository('WallabagCoreBundle:Entry') |
360 | ->find($entry->getId()); | 246 | ->find($entry->getId()); |
@@ -369,15 +255,13 @@ class WallabagRestControllerTest extends WebTestCase | |||
369 | } | 255 | } |
370 | } | 256 | } |
371 | 257 | ||
372 | public function testDeleteOneTagEntrie() | 258 | public function testDeleteOneTagEntry() |
373 | { | 259 | { |
374 | $client = $this->createClient(); | 260 | $entry = $this->client->getContainer() |
375 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
376 | |||
377 | $entry = $client->getContainer() | ||
378 | ->get('doctrine.orm.entity_manager') | 261 | ->get('doctrine.orm.entity_manager') |
379 | ->getRepository('WallabagCoreBundle:Entry') | 262 | ->getRepository('WallabagCoreBundle:Entry') |
380 | ->findOneByUser(1); | 263 | ->findOneWithTags(1); |
264 | $entry = $entry[0]; | ||
381 | 265 | ||
382 | if (!$entry) { | 266 | if (!$entry) { |
383 | $this->markTestSkipped('No content found in db.'); | 267 | $this->markTestSkipped('No content found in db.'); |
@@ -387,11 +271,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
387 | $nbTags = count($entry->getTags()); | 271 | $nbTags = count($entry->getTags()); |
388 | $tag = $entry->getTags()[0]; | 272 | $tag = $entry->getTags()[0]; |
389 | 273 | ||
390 | $client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json', array(), array(), $headers); | 274 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json'); |
391 | 275 | ||
392 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 276 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
393 | 277 | ||
394 | $content = json_decode($client->getResponse()->getContent(), true); | 278 | $content = json_decode($this->client->getResponse()->getContent(), true); |
395 | 279 | ||
396 | $this->assertArrayHasKey('tags', $content); | 280 | $this->assertArrayHasKey('tags', $content); |
397 | $this->assertEquals($nbTags - 1, count($content['tags'])); | 281 | $this->assertEquals($nbTags - 1, count($content['tags'])); |
@@ -399,14 +283,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
399 | 283 | ||
400 | public function testGetUserTags() | 284 | public function testGetUserTags() |
401 | { | 285 | { |
402 | $client = $this->createClient(); | 286 | $this->client->request('GET', '/api/tags.json'); |
403 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
404 | |||
405 | $client->request('GET', '/api/tags.json', array(), array(), $headers); | ||
406 | 287 | ||
407 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 288 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
408 | 289 | ||
409 | $content = json_decode($client->getResponse()->getContent(), true); | 290 | $content = json_decode($this->client->getResponse()->getContent(), true); |
410 | 291 | ||
411 | $this->assertGreaterThan(0, $content); | 292 | $this->assertGreaterThan(0, $content); |
412 | $this->assertArrayHasKey('id', $content[0]); | 293 | $this->assertArrayHasKey('id', $content[0]); |
@@ -420,14 +301,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
420 | */ | 301 | */ |
421 | public function testDeleteUserTag($tag) | 302 | public function testDeleteUserTag($tag) |
422 | { | 303 | { |
423 | $client = $this->createClient(); | 304 | $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json'); |
424 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
425 | |||
426 | $client->request('DELETE', '/api/tags/'.$tag['id'].'.json', array(), array(), $headers); | ||
427 | 305 | ||
428 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 306 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
429 | 307 | ||
430 | $content = json_decode($client->getResponse()->getContent(), true); | 308 | $content = json_decode($this->client->getResponse()->getContent(), true); |
431 | 309 | ||
432 | $this->assertArrayHasKey('label', $content); | 310 | $this->assertArrayHasKey('label', $content); |
433 | $this->assertEquals($tag['label'], $content['label']); | 311 | $this->assertEquals($tag['label'], $content['label']); |
diff --git a/src/Wallabag/ApiBundle/WallabagApiBundle.php b/src/Wallabag/ApiBundle/WallabagApiBundle.php index 2484f277..19d887ab 100644 --- a/src/Wallabag/ApiBundle/WallabagApiBundle.php +++ b/src/Wallabag/ApiBundle/WallabagApiBundle.php | |||
@@ -3,16 +3,7 @@ | |||
3 | namespace Wallabag\ApiBundle; | 3 | namespace Wallabag\ApiBundle; |
4 | 4 | ||
5 | use Symfony\Component\HttpKernel\Bundle\Bundle; | 5 | use Symfony\Component\HttpKernel\Bundle\Bundle; |
6 | use Wallabag\ApiBundle\DependencyInjection\Security\Factory\WsseFactory; | ||
7 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
8 | 6 | ||
9 | class WallabagApiBundle extends Bundle | 7 | class WallabagApiBundle extends Bundle |
10 | { | 8 | { |
11 | public function build(ContainerBuilder $container) | ||
12 | { | ||
13 | parent::build($container); | ||
14 | |||
15 | $extension = $container->getExtension('security'); | ||
16 | $extension->addSecurityListenerFactory(new WsseFactory()); | ||
17 | } | ||
18 | } | 9 | } |
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index 1bd76ae3..6ebbd93c 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php | |||
@@ -8,7 +8,7 @@ use Symfony\Component\Console\Input\InputOption; | |||
8 | use Symfony\Component\Console\Input\ArrayInput; | 8 | use Symfony\Component\Console\Input\ArrayInput; |
9 | use Symfony\Component\Console\Output\OutputInterface; | 9 | use Symfony\Component\Console\Output\OutputInterface; |
10 | use Symfony\Component\Console\Output\NullOutput; | 10 | use Symfony\Component\Console\Output\NullOutput; |
11 | use Wallabag\CoreBundle\Entity\User; | 11 | use Wallabag\UserBundle\Entity\User; |
12 | use Wallabag\CoreBundle\Entity\Config; | 12 | use Wallabag\CoreBundle\Entity\Config; |
13 | 13 | ||
14 | class InstallCommand extends ContainerAwareCommand | 14 | class InstallCommand extends ContainerAwareCommand |
@@ -188,9 +188,10 @@ class InstallCommand extends ContainerAwareCommand | |||
188 | 188 | ||
189 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); | 189 | $em = $this->getContainer()->get('doctrine.orm.entity_manager'); |
190 | 190 | ||
191 | $user = new User(); | 191 | $userManager = $this->getContainer()->get('fos_user.user_manager'); |
192 | $user = $userManager->createUser(); | ||
192 | $user->setUsername($dialog->ask($this->defaultOutput, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag')); | 193 | $user->setUsername($dialog->ask($this->defaultOutput, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag')); |
193 | $user->setPassword($dialog->ask($this->defaultOutput, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag')); | 194 | $user->setPlainPassword($dialog->ask($this->defaultOutput, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag')); |
194 | $user->setEmail($dialog->ask($this->defaultOutput, '<question>Email:</question>', '')); | 195 | $user->setEmail($dialog->ask($this->defaultOutput, '<question>Email:</question>', '')); |
195 | $user->setEnabled(true); | 196 | $user->setEnabled(true); |
196 | 197 | ||
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index 5affdee8..ecfecc66 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php | |||
@@ -7,7 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |||
7 | use Symfony\Component\HttpFoundation\Request; | 7 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\HttpFoundation\JsonResponse; | 8 | use Symfony\Component\HttpFoundation\JsonResponse; |
9 | use Wallabag\CoreBundle\Entity\Config; | 9 | use Wallabag\CoreBundle\Entity\Config; |
10 | use Wallabag\CoreBundle\Entity\User; | 10 | use Wallabag\UserBundle\Entity\User; |
11 | use Wallabag\CoreBundle\Form\Type\ChangePasswordType; | 11 | use Wallabag\CoreBundle\Form\Type\ChangePasswordType; |
12 | use Wallabag\CoreBundle\Form\Type\UserInformationType; | 12 | use Wallabag\CoreBundle\Form\Type\UserInformationType; |
13 | use Wallabag\CoreBundle\Form\Type\NewUserType; | 13 | use Wallabag\CoreBundle\Form\Type\NewUserType; |
@@ -25,6 +25,7 @@ class ConfigController extends Controller | |||
25 | { | 25 | { |
26 | $em = $this->getDoctrine()->getManager(); | 26 | $em = $this->getDoctrine()->getManager(); |
27 | $config = $this->getConfig(); | 27 | $config = $this->getConfig(); |
28 | $userManager = $this->container->get('fos_user.user_manager'); | ||
28 | $user = $this->getUser(); | 29 | $user = $this->getUser(); |
29 | 30 | ||
30 | // handle basic config detail (this form is defined as a service) | 31 | // handle basic config detail (this form is defined as a service) |
@@ -52,9 +53,8 @@ class ConfigController extends Controller | |||
52 | $pwdForm->handleRequest($request); | 53 | $pwdForm->handleRequest($request); |
53 | 54 | ||
54 | if ($pwdForm->isValid()) { | 55 | if ($pwdForm->isValid()) { |
55 | $user->setPassword($pwdForm->get('new_password')->getData()); | 56 | $user->setPlainPassword($pwdForm->get('new_password')->getData()); |
56 | $em->persist($user); | 57 | $userManager->updateUser($user, true); |
57 | $em->flush(); | ||
58 | 58 | ||
59 | $this->get('session')->getFlashBag()->add( | 59 | $this->get('session')->getFlashBag()->add( |
60 | 'notice', | 60 | 'notice', |
@@ -69,8 +69,7 @@ class ConfigController extends Controller | |||
69 | $userForm->handleRequest($request); | 69 | $userForm->handleRequest($request); |
70 | 70 | ||
71 | if ($userForm->isValid()) { | 71 | if ($userForm->isValid()) { |
72 | $em->persist($user); | 72 | $userManager->updateUser($user, true); |
73 | $em->flush(); | ||
74 | 73 | ||
75 | $this->get('session')->getFlashBag()->add( | 74 | $this->get('session')->getFlashBag()->add( |
76 | 'notice', | 75 | 'notice', |
@@ -97,14 +96,14 @@ class ConfigController extends Controller | |||
97 | } | 96 | } |
98 | 97 | ||
99 | // handle adding new user | 98 | // handle adding new user |
100 | $newUser = new User(); | 99 | $newUser = $userManager->createUser(); |
101 | // enable created user by default | 100 | // enable created user by default |
102 | $newUser->setEnabled(true); | 101 | $newUser->setEnabled(true); |
103 | $newUserForm = $this->createForm(new NewUserType(), $newUser, array('validation_groups' => array('Profile'))); | 102 | $newUserForm = $this->createForm(new NewUserType(), $newUser, array('validation_groups' => array('Profile'))); |
104 | $newUserForm->handleRequest($request); | 103 | $newUserForm->handleRequest($request); |
105 | 104 | ||
106 | if ($newUserForm->isValid()) { | 105 | if ($newUserForm->isValid() && $this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) { |
107 | $em->persist($newUser); | 106 | $userManager->updateUser($newUser, true); |
108 | 107 | ||
109 | $config = new Config($newUser); | 108 | $config = new Config($newUser); |
110 | $config->setTheme($this->container->getParameter('theme')); | 109 | $config->setTheme($this->container->getParameter('theme')); |
diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/RssController.php index 6121f361..023a6228 100644 --- a/src/Wallabag/CoreBundle/Controller/RssController.php +++ b/src/Wallabag/CoreBundle/Controller/RssController.php | |||
@@ -5,7 +5,7 @@ namespace Wallabag\CoreBundle\Controller; | |||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
6 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 6 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
7 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 7 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
8 | use Wallabag\CoreBundle\Entity\User; | 8 | use Wallabag\UserBundle\Entity\User; |
9 | use Wallabag\CoreBundle\Entity\Entry; | 9 | use Wallabag\CoreBundle\Entity\Entry; |
10 | use Pagerfanta\Adapter\DoctrineORMAdapter; | 10 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
11 | use Pagerfanta\Pagerfanta; | 11 | use Pagerfanta\Pagerfanta; |
@@ -16,7 +16,7 @@ class RssController extends Controller | |||
16 | * Shows unread entries for current user. | 16 | * Shows unread entries for current user. |
17 | * | 17 | * |
18 | * @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"}) | 18 | * @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"}) |
19 | * @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter") | 19 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") |
20 | * | 20 | * |
21 | * @return \Symfony\Component\HttpFoundation\Response | 21 | * @return \Symfony\Component\HttpFoundation\Response |
22 | */ | 22 | */ |
@@ -29,7 +29,7 @@ class RssController extends Controller | |||
29 | * Shows read entries for current user. | 29 | * Shows read entries for current user. |
30 | * | 30 | * |
31 | * @Route("/{username}/{token}/archive.xml", name="archive_rss") | 31 | * @Route("/{username}/{token}/archive.xml", name="archive_rss") |
32 | * @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter") | 32 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") |
33 | * | 33 | * |
34 | * @return \Symfony\Component\HttpFoundation\Response | 34 | * @return \Symfony\Component\HttpFoundation\Response |
35 | */ | 35 | */ |
@@ -42,7 +42,7 @@ class RssController extends Controller | |||
42 | * Shows starred entries for current user. | 42 | * Shows starred entries for current user. |
43 | * | 43 | * |
44 | * @Route("/{username}/{token}/starred.xml", name="starred_rss") | 44 | * @Route("/{username}/{token}/starred.xml", name="starred_rss") |
45 | * @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter") | 45 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") |
46 | * | 46 | * |
47 | * @return \Symfony\Component\HttpFoundation\Response | 47 | * @return \Symfony\Component\HttpFoundation\Response |
48 | */ | 48 | */ |
diff --git a/src/Wallabag/CoreBundle/Controller/SecurityController.php b/src/Wallabag/CoreBundle/Controller/SecurityController.php deleted file mode 100644 index f0a7ab6d..00000000 --- a/src/Wallabag/CoreBundle/Controller/SecurityController.php +++ /dev/null | |||
@@ -1,153 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Controller; | ||
4 | |||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | ||
7 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||
8 | use Symfony\Component\HttpFoundation\Request; | ||
9 | use Symfony\Component\Security\Core\SecurityContext; | ||
10 | use Wallabag\CoreBundle\Form\Type\ResetPasswordType; | ||
11 | |||
12 | class SecurityController extends Controller | ||
13 | { | ||
14 | public function loginAction(Request $request) | ||
15 | { | ||
16 | $session = $request->getSession(); | ||
17 | // get the login error if there is one | ||
18 | if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) { | ||
19 | $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR); | ||
20 | } else { | ||
21 | $error = $session->get(SecurityContext::AUTHENTICATION_ERROR); | ||
22 | $session->remove(SecurityContext::AUTHENTICATION_ERROR); | ||
23 | } | ||
24 | |||
25 | return $this->render('WallabagCoreBundle:Security:login.html.twig', array( | ||
26 | // last username entered by the user | ||
27 | 'last_username' => $session->get(SecurityContext::LAST_USERNAME), | ||
28 | 'error' => $error, | ||
29 | )); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * Request forgot password: show form. | ||
34 | * | ||
35 | * @Route("/forgot-password", name="forgot_password") | ||
36 | * | ||
37 | * @Method({"GET", "POST"}) | ||
38 | */ | ||
39 | public function forgotPasswordAction(Request $request) | ||
40 | { | ||
41 | $form = $this->createForm('forgot_password'); | ||
42 | $form->handleRequest($request); | ||
43 | |||
44 | if ($form->isValid()) { | ||
45 | $user = $this->getDoctrine()->getRepository('WallabagCoreBundle:User')->findOneByEmail($form->get('email')->getData()); | ||
46 | |||
47 | // generate "hard" token | ||
48 | $user->setConfirmationToken(rtrim(strtr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), '+/', '-_'), '=')); | ||
49 | $user->setPasswordRequestedAt(new \DateTime()); | ||
50 | |||
51 | $em = $this->getDoctrine()->getManager(); | ||
52 | $em->persist($user); | ||
53 | $em->flush(); | ||
54 | |||
55 | $message = \Swift_Message::newInstance() | ||
56 | ->setSubject('Reset Password') | ||
57 | ->setFrom($this->container->getParameter('from_email')) | ||
58 | ->setTo($user->getEmail()) | ||
59 | ->setBody($this->renderView('WallabagCoreBundle:Mail:forgotPassword.txt.twig', array( | ||
60 | 'username' => $user->getUsername(), | ||
61 | 'confirmationUrl' => $this->generateUrl('forgot_password_reset', array('token' => $user->getConfirmationToken()), true), | ||
62 | ))) | ||
63 | ; | ||
64 | $this->get('mailer')->send($message); | ||
65 | |||
66 | return $this->redirect($this->generateUrl('forgot_password_check_email', | ||
67 | array('email' => $this->getObfuscatedEmail($user->getEmail())) | ||
68 | )); | ||
69 | } | ||
70 | |||
71 | return $this->render('WallabagCoreBundle:Security:forgotPassword.html.twig', array( | ||
72 | 'form' => $form->createView(), | ||
73 | )); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Tell the user to check his email provider. | ||
78 | * | ||
79 | * @Route("/forgot-password/check-email", name="forgot_password_check_email") | ||
80 | * | ||
81 | * @Method({"GET"}) | ||
82 | */ | ||
83 | public function checkEmailAction(Request $request) | ||
84 | { | ||
85 | $email = $request->query->get('email'); | ||
86 | |||
87 | if (empty($email)) { | ||
88 | // the user does not come from the forgotPassword action | ||
89 | return $this->redirect($this->generateUrl('forgot_password')); | ||
90 | } | ||
91 | |||
92 | return $this->render('WallabagCoreBundle:Security:checkEmail.html.twig', array( | ||
93 | 'email' => $email, | ||
94 | )); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * Reset user password. | ||
99 | * | ||
100 | * @Route("/forgot-password/{token}", name="forgot_password_reset") | ||
101 | * | ||
102 | * @Method({"GET", "POST"}) | ||
103 | */ | ||
104 | public function resetAction(Request $request, $token) | ||
105 | { | ||
106 | $user = $this->getDoctrine()->getRepository('WallabagCoreBundle:User')->findOneByConfirmationToken($token); | ||
107 | |||
108 | if (null === $user) { | ||
109 | throw $this->createNotFoundException(sprintf('No user found with token "%s"', $token)); | ||
110 | } | ||
111 | |||
112 | $form = $this->createForm(new ResetPasswordType()); | ||
113 | $form->handleRequest($request); | ||
114 | |||
115 | if ($form->isValid()) { | ||
116 | $user->setPassword($form->get('new_password')->getData()); | ||
117 | |||
118 | $em = $this->getDoctrine()->getManager(); | ||
119 | $em->persist($user); | ||
120 | $em->flush(); | ||
121 | |||
122 | $this->get('session')->getFlashBag()->add( | ||
123 | 'notice', | ||
124 | 'The password has been reset successfully' | ||
125 | ); | ||
126 | |||
127 | return $this->redirect($this->generateUrl('login')); | ||
128 | } | ||
129 | |||
130 | return $this->render('WallabagCoreBundle:Security:reset.html.twig', array( | ||
131 | 'token' => $token, | ||
132 | 'form' => $form->createView(), | ||
133 | )); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * Get the truncated email displayed when requesting the resetting. | ||
138 | * | ||
139 | * Keeping only the part following @ in the address. | ||
140 | * | ||
141 | * @param string $email | ||
142 | * | ||
143 | * @return string | ||
144 | */ | ||
145 | protected function getObfuscatedEmail($email) | ||
146 | { | ||
147 | if (false !== $pos = strpos($email, '@')) { | ||
148 | $email = '...'.substr($email, $pos); | ||
149 | } | ||
150 | |||
151 | return $email; | ||
152 | } | ||
153 | } | ||
diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php index 025d94ef..2390bfe1 100644 --- a/src/Wallabag/CoreBundle/Entity/Config.php +++ b/src/Wallabag/CoreBundle/Entity/Config.php | |||
@@ -72,14 +72,14 @@ class Config | |||
72 | private $rssLimit; | 72 | private $rssLimit; |
73 | 73 | ||
74 | /** | 74 | /** |
75 | * @ORM\OneToOne(targetEntity="User", inversedBy="config") | 75 | * @ORM\OneToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="config") |
76 | */ | 76 | */ |
77 | private $user; | 77 | private $user; |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * @param User $user | 80 | * @param User $user |
81 | */ | 81 | */ |
82 | public function __construct(User $user) | 82 | public function __construct(\Wallabag\UserBundle\Entity\User $user) |
83 | { | 83 | { |
84 | $this->user = $user; | 84 | $this->user = $user; |
85 | } | 85 | } |
@@ -169,11 +169,11 @@ class Config | |||
169 | /** | 169 | /** |
170 | * Set user. | 170 | * Set user. |
171 | * | 171 | * |
172 | * @param \Wallabag\CoreBundle\Entity\User $user | 172 | * @param User $user |
173 | * | 173 | * |
174 | * @return Config | 174 | * @return Config |
175 | */ | 175 | */ |
176 | public function setUser(\Wallabag\CoreBundle\Entity\User $user = null) | 176 | public function setUser(User $user = null) |
177 | { | 177 | { |
178 | $this->user = $user; | 178 | $this->user = $user; |
179 | 179 | ||
@@ -183,7 +183,7 @@ class Config | |||
183 | /** | 183 | /** |
184 | * Get user. | 184 | * Get user. |
185 | * | 185 | * |
186 | * @return \Wallabag\CoreBundle\Entity\User | 186 | * @return User |
187 | */ | 187 | */ |
188 | public function getUser() | 188 | public function getUser() |
189 | { | 189 | { |
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php index 9e81ba12..4fd74001 100644 --- a/src/Wallabag/CoreBundle/Entity/Entry.php +++ b/src/Wallabag/CoreBundle/Entity/Entry.php | |||
@@ -7,6 +7,7 @@ use Doctrine\ORM\Mapping as ORM; | |||
7 | use Symfony\Component\Validator\Constraints as Assert; | 7 | use Symfony\Component\Validator\Constraints as Assert; |
8 | use Hateoas\Configuration\Annotation as Hateoas; | 8 | use Hateoas\Configuration\Annotation as Hateoas; |
9 | use JMS\Serializer\Annotation\XmlRoot; | 9 | use JMS\Serializer\Annotation\XmlRoot; |
10 | use Wallabag\UserBundle\Entity\User; | ||
10 | 11 | ||
11 | /** | 12 | /** |
12 | * Entry. | 13 | * Entry. |
@@ -129,7 +130,7 @@ class Entry | |||
129 | private $isPublic; | 130 | private $isPublic; |
130 | 131 | ||
131 | /** | 132 | /** |
132 | * @ORM\ManyToOne(targetEntity="User", inversedBy="entries") | 133 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="entries") |
133 | */ | 134 | */ |
134 | private $user; | 135 | private $user; |
135 | 136 | ||
@@ -142,7 +143,7 @@ class Entry | |||
142 | /* | 143 | /* |
143 | * @param User $user | 144 | * @param User $user |
144 | */ | 145 | */ |
145 | public function __construct(User $user) | 146 | public function __construct(\Wallabag\UserBundle\Entity\User $user) |
146 | { | 147 | { |
147 | $this->user = $user; | 148 | $this->user = $user; |
148 | $this->tags = new ArrayCollection(); | 149 | $this->tags = new ArrayCollection(); |
diff --git a/src/Wallabag/CoreBundle/Entity/Tag.php b/src/Wallabag/CoreBundle/Entity/Tag.php index 97c4579f..5b571823 100644 --- a/src/Wallabag/CoreBundle/Entity/Tag.php +++ b/src/Wallabag/CoreBundle/Entity/Tag.php | |||
@@ -42,11 +42,11 @@ class Tag | |||
42 | private $entries; | 42 | private $entries; |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * @ORM\ManyToOne(targetEntity="User", inversedBy="tags") | 45 | * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="tags") |
46 | */ | 46 | */ |
47 | private $user; | 47 | private $user; |
48 | 48 | ||
49 | public function __construct(User $user) | 49 | public function __construct(\Wallabag\UserBundle\Entity\User $user) |
50 | { | 50 | { |
51 | $this->user = $user; | 51 | $this->user = $user; |
52 | $this->entries = new ArrayCollection(); | 52 | $this->entries = new ArrayCollection(); |
diff --git a/src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php b/src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php new file mode 100644 index 00000000..68c25f1f --- /dev/null +++ b/src/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListener.php | |||
@@ -0,0 +1,50 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\EventListener; | ||
4 | |||
5 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
6 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
7 | use Doctrine\ORM\EntityManager; | ||
8 | use FOS\UserBundle\Event\FilterUserResponseEvent; | ||
9 | use FOS\UserBundle\FOSUserEvents; | ||
10 | use Wallabag\CoreBundle\Entity\Config; | ||
11 | |||
12 | class RegistrationConfirmedListener implements EventSubscriberInterface | ||
13 | { | ||
14 | private $em; | ||
15 | private $theme; | ||
16 | private $itemsOnPage; | ||
17 | private $rssLimit; | ||
18 | private $language; | ||
19 | |||
20 | public function __construct(EntityManager $em, $theme, $itemsOnPage, $rssLimit, $language) | ||
21 | { | ||
22 | $this->em = $em; | ||
23 | $this->theme = $theme; | ||
24 | $this->itemsOnPage = $itemsOnPage; | ||
25 | $this->rssLimit = $rssLimit; | ||
26 | $this->language = $language; | ||
27 | } | ||
28 | |||
29 | public static function getSubscribedEvents() | ||
30 | { | ||
31 | return array( | ||
32 | FOSUserEvents::REGISTRATION_CONFIRMED => 'authenticate', | ||
33 | ); | ||
34 | } | ||
35 | |||
36 | public function authenticate(FilterUserResponseEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null) | ||
37 | { | ||
38 | if (!$event->getUser()->isEnabled()) { | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | $config = new Config($event->getUser()); | ||
43 | $config->setTheme($this->theme); | ||
44 | $config->setItemsPerPage($this->itemsOnPage); | ||
45 | $config->setRssLimit($this->rssLimit); | ||
46 | $config->setLanguage($this->language); | ||
47 | $this->em->persist($config); | ||
48 | $this->em->flush(); | ||
49 | } | ||
50 | } | ||
diff --git a/src/Wallabag/CoreBundle/Filter/EntryFilterType.php b/src/Wallabag/CoreBundle/Filter/EntryFilterType.php index 2e6d6ff7..32de21ca 100644 --- a/src/Wallabag/CoreBundle/Filter/EntryFilterType.php +++ b/src/Wallabag/CoreBundle/Filter/EntryFilterType.php | |||
@@ -7,7 +7,7 @@ use Symfony\Component\Form\FormBuilderInterface; | |||
7 | use Symfony\Component\OptionsResolver\OptionsResolver; | 7 | use Symfony\Component\OptionsResolver\OptionsResolver; |
8 | use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface; | 8 | use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface; |
9 | use Doctrine\ORM\EntityRepository; | 9 | use Doctrine\ORM\EntityRepository; |
10 | use Wallabag\CoreBundle\Entity\User; | 10 | use Wallabag\UserBundle\Entity\User; |
11 | 11 | ||
12 | class EntryFilterType extends AbstractType | 12 | class EntryFilterType extends AbstractType |
13 | { | 13 | { |
diff --git a/src/Wallabag/CoreBundle/Form/Type/ForgotPasswordType.php b/src/Wallabag/CoreBundle/Form/Type/ForgotPasswordType.php deleted file mode 100644 index 9e95eb47..00000000 --- a/src/Wallabag/CoreBundle/Form/Type/ForgotPasswordType.php +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Form\Type; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\FormBuilderInterface; | ||
7 | use Symfony\Component\Validator\Constraints; | ||
8 | use Symfony\Component\Validator\ExecutionContextInterface; | ||
9 | use Doctrine\Bundle\DoctrineBundle\Registry; | ||
10 | |||
11 | class ForgotPasswordType extends AbstractType | ||
12 | { | ||
13 | private $doctrine = null; | ||
14 | |||
15 | public function __construct(Registry $doctrine) | ||
16 | { | ||
17 | $this->doctrine = $doctrine; | ||
18 | } | ||
19 | |||
20 | public function buildForm(FormBuilderInterface $builder, array $options) | ||
21 | { | ||
22 | $builder | ||
23 | ->add('email', 'email', array( | ||
24 | 'required' => true, | ||
25 | 'constraints' => array( | ||
26 | new Constraints\Email(), | ||
27 | new Constraints\NotBlank(), | ||
28 | new Constraints\Callback(array(array($this, 'validateEmail'))), | ||
29 | ), | ||
30 | )) | ||
31 | ; | ||
32 | } | ||
33 | |||
34 | public function getName() | ||
35 | { | ||
36 | return 'forgot_password'; | ||
37 | } | ||
38 | |||
39 | public function validateEmail($email, ExecutionContextInterface $context) | ||
40 | { | ||
41 | $user = $this->doctrine | ||
42 | ->getRepository('WallabagCoreBundle:User') | ||
43 | ->findOneByEmail($email); | ||
44 | |||
45 | if (!$user) { | ||
46 | $context->addViolationAt( | ||
47 | 'email', | ||
48 | 'No user found with this email', | ||
49 | array(), | ||
50 | |||
51 | ); | ||
52 | } | ||
53 | } | ||
54 | } | ||
diff --git a/src/Wallabag/CoreBundle/Form/Type/NewUserType.php b/src/Wallabag/CoreBundle/Form/Type/NewUserType.php index 985cb55b..8aabc8bb 100644 --- a/src/Wallabag/CoreBundle/Form/Type/NewUserType.php +++ b/src/Wallabag/CoreBundle/Form/Type/NewUserType.php | |||
@@ -13,7 +13,8 @@ class NewUserType extends AbstractType | |||
13 | { | 13 | { |
14 | $builder | 14 | $builder |
15 | ->add('username', 'text', array('required' => true)) | 15 | ->add('username', 'text', array('required' => true)) |
16 | ->add('password', 'password', array( | 16 | ->add('plainPassword', 'repeated', array( |
17 | 'type' => 'password', | ||
17 | 'constraints' => array( | 18 | 'constraints' => array( |
18 | new Constraints\Length(array( | 19 | new Constraints\Length(array( |
19 | 'min' => 8, | 20 | 'min' => 8, |
@@ -30,7 +31,7 @@ class NewUserType extends AbstractType | |||
30 | public function configureOptions(OptionsResolver $resolver) | 31 | public function configureOptions(OptionsResolver $resolver) |
31 | { | 32 | { |
32 | $resolver->setDefaults(array( | 33 | $resolver->setDefaults(array( |
33 | 'data_class' => 'Wallabag\CoreBundle\Entity\User', | 34 | 'data_class' => 'Wallabag\UserBundle\Entity\User', |
34 | )); | 35 | )); |
35 | } | 36 | } |
36 | 37 | ||
diff --git a/src/Wallabag/CoreBundle/Form/Type/ResetPasswordType.php b/src/Wallabag/CoreBundle/Form/Type/ResetPasswordType.php deleted file mode 100644 index 38f1a105..00000000 --- a/src/Wallabag/CoreBundle/Form/Type/ResetPasswordType.php +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Form\Type; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\FormBuilderInterface; | ||
7 | use Symfony\Component\Validator\Constraints; | ||
8 | |||
9 | class ResetPasswordType extends AbstractType | ||
10 | { | ||
11 | public function buildForm(FormBuilderInterface $builder, array $options) | ||
12 | { | ||
13 | $builder | ||
14 | ->add('new_password', 'repeated', array( | ||
15 | 'type' => 'password', | ||
16 | 'invalid_message' => 'The password fields must match.', | ||
17 | 'required' => true, | ||
18 | 'first_options' => array('label' => 'New password'), | ||
19 | 'second_options' => array('label' => 'Repeat new password'), | ||
20 | 'constraints' => array( | ||
21 | new Constraints\Length(array( | ||
22 | 'min' => 8, | ||
23 | 'minMessage' => 'Password should by at least 8 chars long', | ||
24 | )), | ||
25 | new Constraints\NotBlank(), | ||
26 | ), | ||
27 | )) | ||
28 | ; | ||
29 | } | ||
30 | |||
31 | public function getName() | ||
32 | { | ||
33 | return 'change_passwd'; | ||
34 | } | ||
35 | } | ||
diff --git a/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php b/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php index e3196d9c..84f02013 100644 --- a/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php +++ b/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php | |||
@@ -27,7 +27,7 @@ class UserInformationType extends AbstractType | |||
27 | public function configureOptions(OptionsResolver $resolver) | 27 | public function configureOptions(OptionsResolver $resolver) |
28 | { | 28 | { |
29 | $resolver->setDefaults(array( | 29 | $resolver->setDefaults(array( |
30 | 'data_class' => 'Wallabag\CoreBundle\Entity\User', | 30 | 'data_class' => 'Wallabag\UserBundle\Entity\User', |
31 | )); | 31 | )); |
32 | } | 32 | } |
33 | 33 | ||
diff --git a/src/Wallabag/CoreBundle/Helper/DetectActiveTheme.php b/src/Wallabag/CoreBundle/Helper/DetectActiveTheme.php index 446629db..679186c0 100644 --- a/src/Wallabag/CoreBundle/Helper/DetectActiveTheme.php +++ b/src/Wallabag/CoreBundle/Helper/DetectActiveTheme.php | |||
@@ -4,7 +4,7 @@ namespace Wallabag\CoreBundle\Helper; | |||
4 | 4 | ||
5 | use Liip\ThemeBundle\Helper\DeviceDetectionInterface; | 5 | use Liip\ThemeBundle\Helper\DeviceDetectionInterface; |
6 | use Symfony\Component\Security\Core\SecurityContextInterface; | 6 | use Symfony\Component\Security\Core\SecurityContextInterface; |
7 | use Wallabag\CoreBundle\Entity\User; | 7 | use Wallabag\UserBundle\Entity\User; |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * This class intend to detect the active theme for the logged in user. | 10 | * This class intend to detect the active theme for the logged in user. |
diff --git a/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php b/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php index 2771cf11..f7faa2c1 100644 --- a/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php +++ b/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php | |||
@@ -7,7 +7,7 @@ use Doctrine\Common\Persistence\ManagerRegistry; | |||
7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
8 | use Symfony\Component\HttpFoundation\Request; | 8 | use Symfony\Component\HttpFoundation\Request; |
9 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | 9 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
10 | use Wallabag\CoreBundle\Entity\User; | 10 | use Wallabag\UserBundle\Entity\User; |
11 | 11 | ||
12 | /** | 12 | /** |
13 | * ParamConverter used in the RSS controller to retrieve the right user according to | 13 | * ParamConverter used in the RSS controller to retrieve the right user according to |
@@ -49,7 +49,7 @@ class UsernameRssTokenConverter implements ParamConverterInterface | |||
49 | $em = $this->registry->getManagerForClass($configuration->getClass()); | 49 | $em = $this->registry->getManagerForClass($configuration->getClass()); |
50 | 50 | ||
51 | // Check, if class name is what we need | 51 | // Check, if class name is what we need |
52 | if ('Wallabag\CoreBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) { | 52 | if ('Wallabag\UserBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) { |
53 | return false; | 53 | return false; |
54 | } | 54 | } |
55 | 55 | ||
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index 3beb5d0e..c38787de 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml | |||
@@ -13,6 +13,11 @@ services: | |||
13 | tags: | 13 | tags: |
14 | - { name: form.type, alias: config } | 14 | - { name: form.type, alias: config } |
15 | 15 | ||
16 | wallabag_core.form.registration: | ||
17 | class: Wallabag\CoreBundle\Form\Type\RegistrationType | ||
18 | tags: | ||
19 | - { name: form.type, alias: wallabag_user_registration } | ||
20 | |||
16 | wallabag_core.form.type.forgot_password: | 21 | wallabag_core.form.type.forgot_password: |
17 | class: Wallabag\CoreBundle\Form\Type\ForgotPasswordType | 22 | class: Wallabag\CoreBundle\Form\Type\ForgotPasswordType |
18 | arguments: | 23 | arguments: |
@@ -29,7 +34,8 @@ services: | |||
29 | 34 | ||
30 | wallabag_core.doctrine.prefixed_naming_strategy: | 35 | wallabag_core.doctrine.prefixed_naming_strategy: |
31 | class: Wallabag\CoreBundle\Doctrine\Mapping\PrefixedNamingStrategy | 36 | class: Wallabag\CoreBundle\Doctrine\Mapping\PrefixedNamingStrategy |
32 | arguments: [%database_table_prefix%] | 37 | arguments: |
38 | - %database_table_prefix% | ||
33 | 39 | ||
34 | wallabag_core.graby: | 40 | wallabag_core.graby: |
35 | class: Graby\Graby | 41 | class: Graby\Graby |
@@ -40,3 +46,14 @@ services: | |||
40 | class: Wallabag\CoreBundle\Helper\ContentProxy | 46 | class: Wallabag\CoreBundle\Helper\ContentProxy |
41 | arguments: | 47 | arguments: |
42 | - @wallabag_core.graby | 48 | - @wallabag_core.graby |
49 | |||
50 | wallabag_core.registration_confirmed: | ||
51 | class: Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener | ||
52 | arguments: | ||
53 | - @doctrine.orm.entity_manager | ||
54 | - %theme% | ||
55 | - %items_on_page% | ||
56 | - %rss_limit% | ||
57 | - %language% | ||
58 | tags: | ||
59 | - { name: kernel.event_subscriber } | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/base.html.twig b/src/Wallabag/CoreBundle/Resources/views/base.html.twig index 152c5c28..c94c0044 100644 --- a/src/Wallabag/CoreBundle/Resources/views/base.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/base.html.twig | |||
@@ -45,7 +45,7 @@ | |||
45 | <script src="{{ asset('themes/_global/js/bookmarklet.js') }}"></script> | 45 | <script src="{{ asset('themes/_global/js/bookmarklet.js') }}"></script> |
46 | {% endblock %} | 46 | {% endblock %} |
47 | 47 | ||
48 | <title>{% block title %}{% endblock %} - wallabag</title> | 48 | <title>{% block title %}{% endblock %}</title> |
49 | {% endblock %} | 49 | {% endblock %} |
50 | </head> | 50 | </head> |
51 | 51 | ||
@@ -60,7 +60,7 @@ | |||
60 | 60 | ||
61 | {% block messages %}{% endblock %} | 61 | {% block messages %}{% endblock %} |
62 | 62 | ||
63 | <div id="content" class="w600p"> | 63 | <div id="content"> |
64 | {% block content %}{% endblock %} | 64 | {% block content %}{% endblock %} |
65 | </div> | 65 | </div> |
66 | </main> | 66 | </main> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig index c90bb2e3..64305b16 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig | |||
@@ -135,6 +135,7 @@ | |||
135 | {{ form_rest(form.pwd) }} | 135 | {{ form_rest(form.pwd) }} |
136 | </form> | 136 | </form> |
137 | 137 | ||
138 | {% if is_granted('ROLE_SUPER_ADMIN') %} | ||
138 | <h2>{% trans %}Add a user{% endtrans %}</h2> | 139 | <h2>{% trans %}Add a user{% endtrans %}</h2> |
139 | 140 | ||
140 | <form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}> | 141 | <form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}> |
@@ -150,9 +151,17 @@ | |||
150 | 151 | ||
151 | <fieldset class="w500p inline"> | 152 | <fieldset class="w500p inline"> |
152 | <div class="row"> | 153 | <div class="row"> |
153 | {{ form_label(form.new_user.password) }} | 154 | {{ form_label(form.new_user.plainPassword.first) }} |
154 | {{ form_errors(form.new_user.password) }} | 155 | {{ form_errors(form.new_user.plainPassword.first) }} |
155 | {{ form_widget(form.new_user.password) }} | 156 | {{ form_widget(form.new_user.plainPassword.first) }} |
157 | </div> | ||
158 | </fieldset> | ||
159 | |||
160 | <fieldset class="w500p inline"> | ||
161 | <div class="row"> | ||
162 | {{ form_label(form.new_user.plainPassword.second) }} | ||
163 | {{ form_errors(form.new_user.plainPassword.second) }} | ||
164 | {{ form_widget(form.new_user.plainPassword.second) }} | ||
156 | </div> | 165 | </div> |
157 | </fieldset> | 166 | </fieldset> |
158 | 167 | ||
@@ -165,5 +174,6 @@ | |||
165 | </fieldset> | 174 | </fieldset> |
166 | 175 | ||
167 | {{ form_rest(form.new_user) }} | 176 | {{ form_rest(form.new_user) }} |
177 | {% endif %} | ||
168 | </form> | 178 | </form> |
169 | {% endblock %} | 179 | {% 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 index 4476ea7b..00000000 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/forgotPassword.html.twig +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}{% trans %}Forgot password{% endtrans %}{% endblock %} | ||
4 | |||
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | |||
9 | {% block content %} | ||
10 | <form action="{{ path('forgot_password') }}" method="post" name="forgotPasswordform"> | ||
11 | <fieldset class="w500p center"> | ||
12 | <h2 class="mbs txtcenter">{% trans %}Forgot password{% endtrans %}</h2> | ||
13 | |||
14 | {{ form_errors(form) }} | ||
15 | |||
16 | <p>Enter your email address below and we'll send you password reset instructions.</p> | ||
17 | |||
18 | <div class="row"> | ||
19 | {{ form_label(form.email) }} | ||
20 | {{ form_errors(form.email) }} | ||
21 | {{ form_widget(form.email) }} | ||
22 | </div> | ||
23 | |||
24 | <div class="row mts txtcenter"> | ||
25 | <button type="submit">Send me reset instructions</button> | ||
26 | </div> | ||
27 | </fieldset> | ||
28 | |||
29 | {{ form_rest(form) }} | ||
30 | </form> | ||
31 | {% 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 index fda88af2..00000000 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/reset.html.twig +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}{% trans %}Change password{% endtrans %}{% endblock %} | ||
4 | |||
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | |||
9 | {% block content %} | ||
10 | <form action="{{ path('forgot_password_reset', {'token': token}) }}" method="post" name="loginform"> | ||
11 | <fieldset class="w500p center"> | ||
12 | <h2 class="mbs txtcenter">{% trans %}Change password{% endtrans %}</h2> | ||
13 | |||
14 | {{ form_errors(form) }} | ||
15 | |||
16 | <div class="row"> | ||
17 | {{ form_label(form.new_password.first) }} | ||
18 | {{ form_errors(form.new_password.first) }} | ||
19 | {{ form_widget(form.new_password.first) }} | ||
20 | </div> | ||
21 | |||
22 | <div class="row"> | ||
23 | {{ form_label(form.new_password.second) }} | ||
24 | {{ form_errors(form.new_password.second) }} | ||
25 | {{ form_widget(form.new_password.second) }} | ||
26 | </div> | ||
27 | |||
28 | <div class="row mts txtcenter"> | ||
29 | <button type="submit">Change password</button> | ||
30 | </div> | ||
31 | </fieldset> | ||
32 | |||
33 | {{ form_rest(form) }} | ||
34 | </form> | ||
35 | {% endblock %} | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig index 3d573eaa..de4ed2e7 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig | |||
@@ -52,7 +52,7 @@ | |||
52 | </li> | 52 | </li> |
53 | <li><a href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li> | 53 | <li><a href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li> |
54 | <li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li> | 54 | <li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li> |
55 | <li><a class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li> | 55 | <li><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li> |
56 | </ul> | 56 | </ul> |
57 | {% endblock %} | 57 | {% endblock %} |
58 | 58 | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig index 0ff21f22..0d8e9f24 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig | |||
@@ -15,7 +15,9 @@ | |||
15 | <li class="tab col s3"><a href="#set2">{% trans %}RSS{% endtrans %}</a></li> | 15 | <li class="tab col s3"><a href="#set2">{% trans %}RSS{% endtrans %}</a></li> |
16 | <li class="tab col s3"><a href="#set3">{% trans %}User information{% endtrans %}</a></li> | 16 | <li class="tab col s3"><a href="#set3">{% trans %}User information{% endtrans %}</a></li> |
17 | <li class="tab col s3"><a href="#set4">{% trans %}Password{% endtrans %}</a></li> | 17 | <li class="tab col s3"><a href="#set4">{% trans %}Password{% endtrans %}</a></li> |
18 | {% if is_granted('ROLE_SUPER_ADMIN') %} | ||
18 | <li class="tab col s3"><a href="#set5">{% trans %}Add a user{% endtrans %}</a></li> | 19 | <li class="tab col s3"><a href="#set5">{% trans %}Add a user{% endtrans %}</a></li> |
20 | {% endif %} | ||
19 | </ul> | 21 | </ul> |
20 | </div> | 22 | </div> |
21 | 23 | ||
@@ -175,7 +177,7 @@ | |||
175 | </form> | 177 | </form> |
176 | </div> | 178 | </div> |
177 | 179 | ||
178 | 180 | {% if is_granted('ROLE_SUPER_ADMIN') %} | |
179 | <div id="set5" class="col s12"> | 181 | <div id="set5" class="col s12"> |
180 | <form action="{{ path('config') }}#set5" method="post" {{ form_enctype(form.new_user) }}> | 182 | <form action="{{ path('config') }}#set5" method="post" {{ form_enctype(form.new_user) }}> |
181 | {{ form_errors(form.new_user) }} | 183 | {{ form_errors(form.new_user) }} |
@@ -190,9 +192,17 @@ | |||
190 | 192 | ||
191 | <div class="row"> | 193 | <div class="row"> |
192 | <div class="input-field col s12"> | 194 | <div class="input-field col s12"> |
193 | {{ form_label(form.new_user.password) }} | 195 | {{ form_label(form.new_user.plainPassword.first) }} |
194 | {{ form_errors(form.new_user.password) }} | 196 | {{ form_errors(form.new_user.plainPassword.first) }} |
195 | {{ form_widget(form.new_user.password) }} | 197 | {{ form_widget(form.new_user.plainPassword.first) }} |
198 | </div> | ||
199 | </div> | ||
200 | |||
201 | <div class="row"> | ||
202 | <div class="input-field col s12"> | ||
203 | {{ form_label(form.new_user.plainPassword.second) }} | ||
204 | {{ form_errors(form.new_user.plainPassword.second) }} | ||
205 | {{ form_widget(form.new_user.plainPassword.second) }} | ||
196 | </div> | 206 | </div> |
197 | </div> | 207 | </div> |
198 | 208 | ||
@@ -211,6 +221,7 @@ | |||
211 | 221 | ||
212 | </form> | 222 | </form> |
213 | </div> | 223 | </div> |
224 | {% endif %} | ||
214 | </div> | 225 | </div> |
215 | 226 | ||
216 | </div> | 227 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig index 4eb6d2b8..b0da42ce 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig | |||
@@ -49,11 +49,12 @@ | |||
49 | {% trans %}Login{% endtrans %} | 49 | {% trans %}Login{% endtrans %} |
50 | <i class="mdi-content-send right"></i> | 50 | <i class="mdi-content-send right"></i> |
51 | </button> | 51 | </button> |
52 | <a href="{{ path('fos_user_registration_register') }}">{% trans %}Register{% endtrans %}</a> | ||
52 | </div> | 53 | </div> |
53 | </form> | 54 | </form> |
54 | </div> | 55 | </div> |
55 | <div class="center"> | 56 | <div class="center"> |
56 | <a href="{{ path('forgot_password') }}">{% trans %}Forgot your password?{% endtrans %}</a> | 57 | <a href="{{ path('fos_user_resetting_request') }}">{% trans %}Forgot your password?{% endtrans %}</a> |
57 | </div> | 58 | </div> |
58 | </div> | 59 | </div> |
59 | </main> | 60 | </main> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig index 10dede8a..36e276f9 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig | |||
@@ -46,8 +46,7 @@ | |||
46 | <li class="bold border-bottom {% if currentRoute == 'tags' %}active{% endif %}"><a class="waves-effect" href="{{ path('tag') }}">{% trans %}tags{% endtrans %}</a></li> | 46 | <li class="bold border-bottom {% if currentRoute == 'tags' %}active{% endif %}"><a class="waves-effect" href="{{ path('tag') }}">{% trans %}tags{% endtrans %}</a></li> |
47 | <li class="bold {% if currentRoute == 'config' %}active{% endif %}"><a class="waves-effect" href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li> | 47 | <li class="bold {% if currentRoute == 'config' %}active{% endif %}"><a class="waves-effect" href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li> |
48 | <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"><a class="waves-effect" href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li> | 48 | <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"><a class="waves-effect" href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li> |
49 | <li class="bold border-bottom {% if currentRoute == 'about' %}active{% endif %}"><a class="waves-effect" href="{{ path('about') }}">{% trans %}About{% endtrans %}</a></li> | 49 | <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> |
50 | <li class="bold"><a class="waves-effect" class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li> | ||
51 | </ul> | 50 | </ul> |
52 | <div class="nav-wrapper nav-panels"> | 51 | <div class="nav-wrapper nav-panels"> |
53 | <a href="#" data-activates="slide-out" class="nav-panel-menu button-collapse"><i class="mdi-navigation-menu"></i></a> | 52 | <a href="#" data-activates="slide-out" class="nav-panel-menu button-collapse"><i class="mdi-navigation-menu"></i></a> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css index a5742905..1fe4a533 100755 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/css/main.css | |||
@@ -24,6 +24,10 @@ body { | |||
24 | background: #f0f0f0; | 24 | background: #f0f0f0; |
25 | } | 25 | } |
26 | 26 | ||
27 | body.login main { | ||
28 | padding: 0; | ||
29 | } | ||
30 | |||
27 | #warning_message { | 31 | #warning_message { |
28 | position: fixed; | 32 | position: fixed; |
29 | background-color: #ff6347; | 33 | background-color: #ff6347; |
@@ -250,9 +254,14 @@ main ul.row { | |||
250 | } | 254 | } |
251 | 255 | ||
252 | .card .card-action a { | 256 | .card .card-action a { |
257 | color: #ffffff; | ||
253 | margin: 0; | 258 | margin: 0; |
254 | } | 259 | } |
255 | 260 | ||
261 | .card .card-action a:hover { | ||
262 | color: #ffffff; | ||
263 | } | ||
264 | |||
256 | .settings .div_tabs { | 265 | .settings .div_tabs { |
257 | padding-bottom: 15px; | 266 | padding-bottom: 15px; |
258 | } | 267 | } |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png index 32543a44..c90aa46f 100755 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/img/logo-other_themes.png | |||
Binary files 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 index 98b4e86b..00000000 --- a/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Security\Authentication\Encoder; | ||
4 | |||
5 | use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder; | ||
6 | use Symfony\Component\Security\Core\Exception\BadCredentialsException; | ||
7 | |||
8 | /** | ||
9 | * This override just add en extra variable (username) to be able to salt the password | ||
10 | * the way Wallabag v1 does. It will avoid to break compatibility with Wallabag v1. | ||
11 | */ | ||
12 | class WallabagPasswordEncoder extends BasePasswordEncoder | ||
13 | { | ||
14 | private $algorithm; | ||
15 | private $encodeHashAsBase64; | ||
16 | private $iterations; | ||
17 | private $username = null; | ||
18 | |||
19 | /** | ||
20 | * Constructor. | ||
21 | * | ||
22 | * @param string $algorithm The digest algorithm to use | ||
23 | * @param bool $encodeHashAsBase64 Whether to base64 encode the password hash | ||
24 | * @param int $iterations The number of iterations to use to stretch the password hash | ||
25 | */ | ||
26 | public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000) | ||
27 | { | ||
28 | $this->algorithm = $algorithm; | ||
29 | $this->encodeHashAsBase64 = $encodeHashAsBase64; | ||
30 | $this->iterations = $iterations; | ||
31 | } | ||
32 | |||
33 | public function setUsername($username) | ||
34 | { | ||
35 | $this->username = $username; | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * {@inheritdoc} | ||
40 | */ | ||
41 | public function encodePassword($raw, $salt) | ||
42 | { | ||
43 | if ($this->isPasswordTooLong($raw)) { | ||
44 | throw new BadCredentialsException('Invalid password.'); | ||
45 | } | ||
46 | |||
47 | if (!in_array($this->algorithm, hash_algos(), true)) { | ||
48 | throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm)); | ||
49 | } | ||
50 | |||
51 | $salted = $this->mergePasswordAndSalt($raw, $salt); | ||
52 | $digest = hash($this->algorithm, $salted, true); | ||
53 | |||
54 | // "stretch" hash | ||
55 | for ($i = 1; $i < $this->iterations; ++$i) { | ||
56 | $digest = hash($this->algorithm, $digest.$salted, true); | ||
57 | } | ||
58 | |||
59 | return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * {@inheritdoc} | ||
64 | * | ||
65 | * We inject the username inside the salted password | ||
66 | */ | ||
67 | protected function mergePasswordAndSalt($password, $salt) | ||
68 | { | ||
69 | if (null === $this->username) { | ||
70 | throw new \LogicException('We can not check the password without a username.'); | ||
71 | } | ||
72 | |||
73 | if (empty($salt)) { | ||
74 | return $password; | ||
75 | } | ||
76 | |||
77 | return $password.$this->username.$salt; | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * {@inheritdoc} | ||
82 | */ | ||
83 | public function isPasswordValid($encoded, $raw, $salt) | ||
84 | { | ||
85 | return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt)); | ||
86 | } | ||
87 | } | ||
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Provider/WallabagAuthenticationProvider.php b/src/Wallabag/CoreBundle/Security/Authentication/Provider/WallabagAuthenticationProvider.php deleted file mode 100644 index cf3cb051..00000000 --- a/src/Wallabag/CoreBundle/Security/Authentication/Provider/WallabagAuthenticationProvider.php +++ /dev/null | |||
@@ -1,89 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Security\Authentication\Provider; | ||
4 | |||
5 | use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; | ||
6 | use Symfony\Component\Security\Core\User\UserProviderInterface; | ||
7 | use Symfony\Component\Security\Core\User\UserCheckerInterface; | ||
8 | use Symfony\Component\Security\Core\User\UserInterface; | ||
9 | use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; | ||
10 | use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; | ||
11 | use Symfony\Component\Security\Core\Exception\BadCredentialsException; | ||
12 | use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; | ||
13 | use Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider; | ||
14 | |||
15 | class WallabagAuthenticationProvider extends UserAuthenticationProvider | ||
16 | { | ||
17 | private $encoderFactory; | ||
18 | private $userProvider; | ||
19 | |||
20 | /** | ||
21 | * Constructor. | ||
22 | * | ||
23 | * @param UserProviderInterface $userProvider An UserProviderInterface instance | ||
24 | * @param UserCheckerInterface $userChecker An UserCheckerInterface instance | ||
25 | * @param string $providerKey The provider key | ||
26 | * @param EncoderFactoryInterface $encoderFactory An EncoderFactoryInterface instance | ||
27 | * @param bool $hideUserNotFoundExceptions Whether to hide user not found exception or not | ||
28 | */ | ||
29 | public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true) | ||
30 | { | ||
31 | parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions); | ||
32 | |||
33 | $this->encoderFactory = $encoderFactory; | ||
34 | $this->userProvider = $userProvider; | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * {@inheritdoc} | ||
39 | */ | ||
40 | protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token) | ||
41 | { | ||
42 | $currentUser = $token->getUser(); | ||
43 | if ($currentUser instanceof UserInterface) { | ||
44 | if ($currentUser->getPassword() !== $user->getPassword()) { | ||
45 | throw new BadCredentialsException('The credentials were changed from another session.'); | ||
46 | } | ||
47 | } else { | ||
48 | if ('' === ($presentedPassword = $token->getCredentials())) { | ||
49 | throw new BadCredentialsException('The presented password cannot be empty.'); | ||
50 | } | ||
51 | |||
52 | // give username, it's used to hash the password | ||
53 | $encoder = $this->encoderFactory->getEncoder($user); | ||
54 | $encoder->setUsername($user->getUsername()); | ||
55 | |||
56 | if (!$encoder->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) { | ||
57 | throw new BadCredentialsException('The presented password is invalid.'); | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * {@inheritdoc} | ||
64 | */ | ||
65 | protected function retrieveUser($username, UsernamePasswordToken $token) | ||
66 | { | ||
67 | $user = $token->getUser(); | ||
68 | if ($user instanceof UserInterface) { | ||
69 | return $user; | ||
70 | } | ||
71 | |||
72 | try { | ||
73 | $user = $this->userProvider->loadUserByUsername($username); | ||
74 | |||
75 | if (!$user instanceof UserInterface) { | ||
76 | throw new AuthenticationServiceException('The user provider must return a UserInterface object.'); | ||
77 | } | ||
78 | |||
79 | return $user; | ||
80 | } catch (UsernameNotFoundException $notFound) { | ||
81 | $notFound->setUsername($username); | ||
82 | throw $notFound; | ||
83 | } catch (\Exception $repositoryProblem) { | ||
84 | $ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem); | ||
85 | $ex->setToken($token); | ||
86 | throw $ex; | ||
87 | } | ||
88 | } | ||
89 | } | ||
diff --git a/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php b/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php deleted file mode 100644 index 52062773..00000000 --- a/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Security\Validator; | ||
4 | |||
5 | use Symfony\Component\Security\Core\User\UserInterface; | ||
6 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||
7 | use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; | ||
8 | use Symfony\Component\Validator\Constraint; | ||
9 | use Symfony\Component\Validator\ConstraintValidator; | ||
10 | use Symfony\Component\Validator\Exception\ConstraintDefinitionException; | ||
11 | use Symfony\Component\Validator\Exception\UnexpectedTypeException; | ||
12 | use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; | ||
13 | |||
14 | /** | ||
15 | * @see Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator | ||
16 | */ | ||
17 | class WallabagUserPasswordValidator extends ConstraintValidator | ||
18 | { | ||
19 | private $securityContext; | ||
20 | private $encoderFactory; | ||
21 | |||
22 | public function __construct(TokenStorageInterface $tokenStorage, EncoderFactoryInterface $encoderFactory) | ||
23 | { | ||
24 | $this->tokenStorage = $tokenStorage; | ||
25 | $this->encoderFactory = $encoderFactory; | ||
26 | } | ||
27 | |||
28 | /** | ||
29 | * {@inheritdoc} | ||
30 | */ | ||
31 | public function validate($password, Constraint $constraint) | ||
32 | { | ||
33 | if (!$constraint instanceof UserPassword) { | ||
34 | throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword'); | ||
35 | } | ||
36 | |||
37 | $user = $this->tokenStorage->getToken()->getUser(); | ||
38 | |||
39 | if (!$user instanceof UserInterface) { | ||
40 | throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.'); | ||
41 | } | ||
42 | |||
43 | // give username, it's used to hash the password | ||
44 | $encoder = $this->encoderFactory->getEncoder($user); | ||
45 | $encoder->setUsername($user->getUsername()); | ||
46 | |||
47 | if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { | ||
48 | $this->context->addViolation($constraint->message); | ||
49 | } | ||
50 | } | ||
51 | } | ||
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php index 3407fc5e..3da5e8b7 100644 --- a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php +++ b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php | |||
@@ -258,7 +258,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
258 | array( | 258 | array( |
259 | array( | 259 | array( |
260 | 'new_user[username]' => '', | 260 | 'new_user[username]' => '', |
261 | 'new_user[password]' => '', | 261 | 'new_user[plainPassword][first]' => '', |
262 | 'new_user[plainPassword][second]' => '', | ||
262 | 'new_user[email]' => '', | 263 | 'new_user[email]' => '', |
263 | ), | 264 | ), |
264 | 'Please enter a username', | 265 | 'Please enter a username', |
@@ -266,7 +267,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
266 | array( | 267 | array( |
267 | array( | 268 | array( |
268 | 'new_user[username]' => 'a', | 269 | 'new_user[username]' => 'a', |
269 | 'new_user[password]' => 'mypassword', | 270 | 'new_user[plainPassword][first]' => 'mypassword', |
271 | 'new_user[plainPassword][second]' => 'mypassword', | ||
270 | 'new_user[email]' => '', | 272 | 'new_user[email]' => '', |
271 | ), | 273 | ), |
272 | 'The username is too short', | 274 | 'The username is too short', |
@@ -274,7 +276,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
274 | array( | 276 | array( |
275 | array( | 277 | array( |
276 | 'new_user[username]' => 'wallace', | 278 | 'new_user[username]' => 'wallace', |
277 | 'new_user[password]' => 'mypassword', | 279 | 'new_user[plainPassword][first]' => 'mypassword', |
280 | 'new_user[plainPassword][second]' => 'mypassword', | ||
278 | 'new_user[email]' => 'test', | 281 | 'new_user[email]' => 'test', |
279 | ), | 282 | ), |
280 | 'The email is not valid', | 283 | 'The email is not valid', |
@@ -282,11 +285,21 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
282 | array( | 285 | array( |
283 | array( | 286 | array( |
284 | 'new_user[username]' => 'admin', | 287 | 'new_user[username]' => 'admin', |
285 | 'new_user[password]' => 'wallacewallace', | 288 | 'new_user[plainPassword][first]' => 'wallacewallace', |
289 | 'new_user[plainPassword][second]' => 'wallacewallace', | ||
286 | 'new_user[email]' => 'wallace@wallace.me', | 290 | 'new_user[email]' => 'wallace@wallace.me', |
287 | ), | 291 | ), |
288 | 'The username is already used', | 292 | 'The username is already used', |
289 | ), | 293 | ), |
294 | array( | ||
295 | array( | ||
296 | 'new_user[username]' => 'wallace', | ||
297 | 'new_user[plainPassword][first]' => 'mypassword1', | ||
298 | 'new_user[plainPassword][second]' => 'mypassword2', | ||
299 | 'new_user[email]' => 'wallace@wallace.me', | ||
300 | ), | ||
301 | 'This value is not valid', | ||
302 | ), | ||
290 | ); | 303 | ); |
291 | } | 304 | } |
292 | 305 | ||
@@ -325,7 +338,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
325 | 338 | ||
326 | $data = array( | 339 | $data = array( |
327 | 'new_user[username]' => 'wallace', | 340 | 'new_user[username]' => 'wallace', |
328 | 'new_user[password]' => 'wallace1', | 341 | 'new_user[plainPassword][first]' => 'wallace1', |
342 | 'new_user[plainPassword][second]' => 'wallace1', | ||
329 | 'new_user[email]' => 'wallace@wallace.me', | 343 | 'new_user[email]' => 'wallace@wallace.me', |
330 | ); | 344 | ); |
331 | 345 | ||
@@ -340,7 +354,7 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
340 | 354 | ||
341 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | 355 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); |
342 | $user = $em | 356 | $user = $em |
343 | ->getRepository('WallabagCoreBundle:User') | 357 | ->getRepository('WallabagUserBundle:User') |
344 | ->findOneByUsername('wallace'); | 358 | ->findOneByUsername('wallace'); |
345 | 359 | ||
346 | $this->assertTrue(false !== $user); | 360 | $this->assertTrue(false !== $user); |
@@ -355,7 +369,7 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
355 | // reset the token | 369 | // reset the token |
356 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | 370 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); |
357 | $user = $em | 371 | $user = $em |
358 | ->getRepository('WallabagCoreBundle:User') | 372 | ->getRepository('WallabagUserBundle:User') |
359 | ->findOneByUsername('admin'); | 373 | ->findOneByUsername('admin'); |
360 | 374 | ||
361 | if (!$user) { | 375 | if (!$user) { |
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/RssControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/RssControllerTest.php index b7c162a7..45a74c43 100644 --- a/src/Wallabag/CoreBundle/Tests/Controller/RssControllerTest.php +++ b/src/Wallabag/CoreBundle/Tests/Controller/RssControllerTest.php | |||
@@ -64,7 +64,7 @@ class RssControllerTest extends WallabagCoreTestCase | |||
64 | $client = $this->getClient(); | 64 | $client = $this->getClient(); |
65 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | 65 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); |
66 | $user = $em | 66 | $user = $em |
67 | ->getRepository('WallabagCoreBundle:User') | 67 | ->getRepository('WallabagUserBundle:User') |
68 | ->findOneByUsername('admin'); | 68 | ->findOneByUsername('admin'); |
69 | 69 | ||
70 | $config = $user->getConfig(); | 70 | $config = $user->getConfig(); |
@@ -85,7 +85,7 @@ class RssControllerTest extends WallabagCoreTestCase | |||
85 | $client = $this->getClient(); | 85 | $client = $this->getClient(); |
86 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | 86 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); |
87 | $user = $em | 87 | $user = $em |
88 | ->getRepository('WallabagCoreBundle:User') | 88 | ->getRepository('WallabagUserBundle:User') |
89 | ->findOneByUsername('admin'); | 89 | ->findOneByUsername('admin'); |
90 | 90 | ||
91 | $config = $user->getConfig(); | 91 | $config = $user->getConfig(); |
@@ -107,7 +107,7 @@ class RssControllerTest extends WallabagCoreTestCase | |||
107 | $client = $this->getClient(); | 107 | $client = $this->getClient(); |
108 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | 108 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); |
109 | $user = $em | 109 | $user = $em |
110 | ->getRepository('WallabagCoreBundle:User') | 110 | ->getRepository('WallabagUserBundle:User') |
111 | ->findOneByUsername('admin'); | 111 | ->findOneByUsername('admin'); |
112 | 112 | ||
113 | $config = $user->getConfig(); | 113 | $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 index 759ef01b..00000000 --- a/src/Wallabag/CoreBundle/Tests/Controller/SecurityControllerTest.php +++ /dev/null | |||
@@ -1,201 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Tests\Controller; | ||
4 | |||
5 | use Symfony\Component\Filesystem\Filesystem; | ||
6 | use Symfony\Component\Finder\Finder; | ||
7 | use Wallabag\CoreBundle\Tests\WallabagCoreTestCase; | ||
8 | |||
9 | class SecurityControllerTest extends WallabagCoreTestCase | ||
10 | { | ||
11 | public function testLogin() | ||
12 | { | ||
13 | $client = $this->getClient(); | ||
14 | |||
15 | $crawler = $client->request('GET', '/new'); | ||
16 | |||
17 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
18 | $this->assertContains('login', $client->getResponse()->headers->get('location')); | ||
19 | } | ||
20 | |||
21 | public function testLoginFail() | ||
22 | { | ||
23 | $client = $this->getClient(); | ||
24 | |||
25 | $crawler = $client->request('GET', '/login'); | ||
26 | |||
27 | $form = $crawler->filter('button[type=submit]')->form(); | ||
28 | $data = array( | ||
29 | '_username' => 'admin', | ||
30 | '_password' => 'admin', | ||
31 | ); | ||
32 | |||
33 | $client->submit($form, $data); | ||
34 | |||
35 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
36 | $this->assertContains('login', $client->getResponse()->headers->get('location')); | ||
37 | |||
38 | $crawler = $client->followRedirect(); | ||
39 | |||
40 | $this->assertContains('Bad credentials', $client->getResponse()->getContent()); | ||
41 | } | ||
42 | |||
43 | public function testRedirectionAfterLogin() | ||
44 | { | ||
45 | $client = $this->getClient(); | ||
46 | $client->followRedirects(); | ||
47 | |||
48 | $crawler = $client->request('GET', '/config'); | ||
49 | |||
50 | $form = $crawler->filter('button[type=submit]')->form(); | ||
51 | |||
52 | $data = array( | ||
53 | '_username' => 'admin', | ||
54 | '_password' => 'mypassword', | ||
55 | ); | ||
56 | |||
57 | $client->submit($form, $data); | ||
58 | |||
59 | $this->assertContains('RSS', $client->getResponse()->getContent()); | ||
60 | } | ||
61 | |||
62 | public function testForgotPassword() | ||
63 | { | ||
64 | $client = $this->getClient(); | ||
65 | |||
66 | $crawler = $client->request('GET', '/forgot-password'); | ||
67 | |||
68 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||
69 | |||
70 | $this->assertContains('Forgot password', $client->getResponse()->getContent()); | ||
71 | |||
72 | $form = $crawler->filter('button[type=submit]'); | ||
73 | |||
74 | $this->assertCount(1, $form); | ||
75 | |||
76 | return array( | ||
77 | 'form' => $form->form(), | ||
78 | 'client' => $client, | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * @depends testForgotPassword | ||
84 | */ | ||
85 | public function testSubmitForgotPasswordFail($parameters) | ||
86 | { | ||
87 | $form = $parameters['form']; | ||
88 | $client = $parameters['client']; | ||
89 | |||
90 | $data = array( | ||
91 | 'forgot_password[email]' => 'material', | ||
92 | ); | ||
93 | |||
94 | $client->submit($form, $data); | ||
95 | |||
96 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||
97 | $this->assertContains('No user found with this email', $client->getResponse()->getContent()); | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * @depends testForgotPassword | ||
102 | * | ||
103 | * Instead of using collector which slow down the test suite | ||
104 | * http://symfony.com/doc/current/cookbook/email/testing.html | ||
105 | * | ||
106 | * Use a different way where Swift store email as file | ||
107 | */ | ||
108 | public function testSubmitForgotPassword($parameters) | ||
109 | { | ||
110 | $form = $parameters['form']; | ||
111 | $client = $parameters['client']; | ||
112 | |||
113 | $spoolDir = $client->getKernel()->getContainer()->getParameter('swiftmailer.spool.default.file.path'); | ||
114 | |||
115 | // cleanup pool dir | ||
116 | $filesystem = new Filesystem(); | ||
117 | $filesystem->remove($spoolDir); | ||
118 | |||
119 | // to use `getCollector` since `collect: false` in config_test.yml | ||
120 | $client->enableProfiler(); | ||
121 | |||
122 | $data = array( | ||
123 | 'forgot_password[email]' => 'bobby@wallabag.org', | ||
124 | ); | ||
125 | |||
126 | $client->submit($form, $data); | ||
127 | |||
128 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
129 | |||
130 | $crawler = $client->followRedirect(); | ||
131 | |||
132 | $this->assertContains('An email has been sent to', $client->getResponse()->getContent()); | ||
133 | |||
134 | // find every files (ie: emails) inside the spool dir except hidden files | ||
135 | $finder = new Finder(); | ||
136 | $finder | ||
137 | ->in($spoolDir) | ||
138 | ->ignoreDotFiles(true) | ||
139 | ->files(); | ||
140 | |||
141 | $this->assertCount(1, $finder, 'Only one email has been sent'); | ||
142 | |||
143 | foreach ($finder as $file) { | ||
144 | $message = unserialize(file_get_contents($file)); | ||
145 | |||
146 | $this->assertInstanceOf('Swift_Message', $message); | ||
147 | $this->assertEquals('Reset Password', $message->getSubject()); | ||
148 | $this->assertEquals('no-reply@wallabag.org', key($message->getFrom())); | ||
149 | $this->assertEquals('bobby@wallabag.org', key($message->getTo())); | ||
150 | $this->assertContains( | ||
151 | 'To reset your password - please visit', | ||
152 | $message->getBody() | ||
153 | ); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | public function testReset() | ||
158 | { | ||
159 | $client = $this->getClient(); | ||
160 | $user = $client->getContainer() | ||
161 | ->get('doctrine.orm.entity_manager') | ||
162 | ->getRepository('WallabagCoreBundle:User') | ||
163 | ->findOneByEmail('bobby@wallabag.org'); | ||
164 | |||
165 | $crawler = $client->request('GET', '/forgot-password/'.$user->getConfirmationToken()); | ||
166 | |||
167 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||
168 | $this->assertCount(2, $crawler->filter('input[type=password]')); | ||
169 | $this->assertCount(1, $form = $crawler->filter('button[type=submit]')); | ||
170 | $this->assertCount(1, $form); | ||
171 | |||
172 | $data = array( | ||
173 | 'change_passwd[new_password][first]' => 'mypassword', | ||
174 | 'change_passwd[new_password][second]' => 'mypassword', | ||
175 | ); | ||
176 | |||
177 | $client->submit($form->form(), $data); | ||
178 | |||
179 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
180 | $this->assertContains('login', $client->getResponse()->headers->get('location')); | ||
181 | } | ||
182 | |||
183 | public function testResetBadToken() | ||
184 | { | ||
185 | $client = $this->getClient(); | ||
186 | |||
187 | $client->request('GET', '/forgot-password/UIZOAU29UE902IEPZO'); | ||
188 | |||
189 | $this->assertEquals(404, $client->getResponse()->getStatusCode()); | ||
190 | } | ||
191 | |||
192 | public function testCheckEmailWithoutEmail() | ||
193 | { | ||
194 | $client = $this->getClient(); | ||
195 | |||
196 | $client->request('GET', '/forgot-password/check-email'); | ||
197 | |||
198 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
199 | $this->assertContains('forgot-password', $client->getResponse()->headers->get('location')); | ||
200 | } | ||
201 | } | ||
diff --git a/src/Wallabag/CoreBundle/Tests/EventListener/RegistrationConfirmedListenerTest.php b/src/Wallabag/CoreBundle/Tests/EventListener/RegistrationConfirmedListenerTest.php new file mode 100644 index 00000000..df94fad2 --- /dev/null +++ b/src/Wallabag/CoreBundle/Tests/EventListener/RegistrationConfirmedListenerTest.php | |||
@@ -0,0 +1,92 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Tests\EventListener; | ||
4 | |||
5 | use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | ||
6 | use Symfony\Component\EventDispatcher\EventDispatcher; | ||
7 | use Symfony\Component\HttpFoundation\Request; | ||
8 | use Symfony\Component\HttpFoundation\Response; | ||
9 | use FOS\UserBundle\FOSUserEvents; | ||
10 | use FOS\UserBundle\Event\FilterUserResponseEvent; | ||
11 | use Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener; | ||
12 | use Wallabag\CoreBundle\Entity\Config; | ||
13 | use Wallabag\UserBundle\Entity\User; | ||
14 | |||
15 | class RegistrationConfirmedListenerTest extends KernelTestCase | ||
16 | { | ||
17 | private $em; | ||
18 | private $listener; | ||
19 | private $dispatcher; | ||
20 | private $request; | ||
21 | private $response; | ||
22 | |||
23 | protected function setUp() | ||
24 | { | ||
25 | $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager') | ||
26 | ->disableOriginalConstructor() | ||
27 | ->getMock(); | ||
28 | |||
29 | $this->listener = new RegistrationConfirmedListener( | ||
30 | $this->em, | ||
31 | 'baggy', | ||
32 | 20, | ||
33 | 50, | ||
34 | 'fr' | ||
35 | ); | ||
36 | |||
37 | $this->dispatcher = new EventDispatcher(); | ||
38 | $this->dispatcher->addSubscriber($this->listener); | ||
39 | |||
40 | $this->request = Request::create('/'); | ||
41 | $this->response = Response::create(); | ||
42 | } | ||
43 | |||
44 | public function testWithInvalidUser() | ||
45 | { | ||
46 | $user = new User(); | ||
47 | $user->setEnabled(false); | ||
48 | |||
49 | $event = new FilterUserResponseEvent( | ||
50 | $user, | ||
51 | $this->request, | ||
52 | $this->response | ||
53 | ); | ||
54 | |||
55 | $this->em->expects($this->never())->method('persist'); | ||
56 | $this->em->expects($this->never())->method('flush'); | ||
57 | |||
58 | $this->dispatcher->dispatch( | ||
59 | FOSUserEvents::REGISTRATION_CONFIRMED, | ||
60 | $event | ||
61 | ); | ||
62 | } | ||
63 | |||
64 | public function testWithValidUser() | ||
65 | { | ||
66 | $user = new User(); | ||
67 | $user->setEnabled(true); | ||
68 | |||
69 | $event = new FilterUserResponseEvent( | ||
70 | $user, | ||
71 | $this->request, | ||
72 | $this->response | ||
73 | ); | ||
74 | |||
75 | $config = new Config($user); | ||
76 | $config->setTheme('baggy'); | ||
77 | $config->setItemsPerPage(20); | ||
78 | $config->setRssLimit(50); | ||
79 | $config->setLanguage('fr'); | ||
80 | |||
81 | $this->em->expects($this->once()) | ||
82 | ->method('persist') | ||
83 | ->will($this->returnValue($config)); | ||
84 | $this->em->expects($this->once()) | ||
85 | ->method('flush'); | ||
86 | |||
87 | $this->dispatcher->dispatch( | ||
88 | FOSUserEvents::REGISTRATION_CONFIRMED, | ||
89 | $event | ||
90 | ); | ||
91 | } | ||
92 | } | ||
diff --git a/src/Wallabag/CoreBundle/Tests/Helper/ContentProxyTest.php b/src/Wallabag/CoreBundle/Tests/Helper/ContentProxyTest.php index 0d338389..1d0d4062 100644 --- a/src/Wallabag/CoreBundle/Tests/Helper/ContentProxyTest.php +++ b/src/Wallabag/CoreBundle/Tests/Helper/ContentProxyTest.php | |||
@@ -4,7 +4,7 @@ namespace Wallabag\CoreBundle\Tests\Helper; | |||
4 | 4 | ||
5 | use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | 5 | use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; |
6 | use Wallabag\CoreBundle\Entity\Entry; | 6 | use Wallabag\CoreBundle\Entity\Entry; |
7 | use Wallabag\CoreBundle\Entity\User; | 7 | use Wallabag\UserBundle\Entity\User; |
8 | use Wallabag\CoreBundle\Helper\ContentProxy; | 8 | use Wallabag\CoreBundle\Helper\ContentProxy; |
9 | 9 | ||
10 | class ContentProxyTest extends KernelTestCase | 10 | class ContentProxyTest extends KernelTestCase |
diff --git a/src/Wallabag/CoreBundle/Tests/ParamConverter/UsernameRssTokenConverterTest.php b/src/Wallabag/CoreBundle/Tests/ParamConverter/UsernameRssTokenConverterTest.php index ebb550b5..e28dc4ba 100644 --- a/src/Wallabag/CoreBundle/Tests/ParamConverter/UsernameRssTokenConverterTest.php +++ b/src/Wallabag/CoreBundle/Tests/ParamConverter/UsernameRssTokenConverterTest.php | |||
@@ -6,7 +6,7 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
6 | use Wallabag\CoreBundle\ParamConverter\UsernameRssTokenConverter; | 6 | use Wallabag\CoreBundle\ParamConverter\UsernameRssTokenConverter; |
7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
8 | use Symfony\Component\HttpFoundation\Request; | 8 | use Symfony\Component\HttpFoundation\Request; |
9 | use Wallabag\CoreBundle\Entity\User; | 9 | use Wallabag\UserBundle\Entity\User; |
10 | 10 | ||
11 | class UsernameRssTokenConverterTest extends KernelTestCase | 11 | class UsernameRssTokenConverterTest extends KernelTestCase |
12 | { | 12 | { |
@@ -96,7 +96,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
96 | 96 | ||
97 | $meta->expects($this->once()) | 97 | $meta->expects($this->once()) |
98 | ->method('getName') | 98 | ->method('getName') |
99 | ->will($this->returnValue('Wallabag\CoreBundle\Entity\User')); | 99 | ->will($this->returnValue('Wallabag\UserBundle\Entity\User')); |
100 | 100 | ||
101 | $em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager') | 101 | $em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager') |
102 | ->disableOriginalConstructor() | 102 | ->disableOriginalConstructor() |
@@ -104,7 +104,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
104 | 104 | ||
105 | $em->expects($this->once()) | 105 | $em->expects($this->once()) |
106 | ->method('getClassMetadata') | 106 | ->method('getClassMetadata') |
107 | ->with('WallabagCoreBundle:User') | 107 | ->with('WallabagUserBundle:User') |
108 | ->will($this->returnValue($meta)); | 108 | ->will($this->returnValue($meta)); |
109 | 109 | ||
110 | $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') | 110 | $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') |
@@ -117,10 +117,10 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
117 | 117 | ||
118 | $registry->expects($this->once()) | 118 | $registry->expects($this->once()) |
119 | ->method('getManagerForClass') | 119 | ->method('getManagerForClass') |
120 | ->with('WallabagCoreBundle:User') | 120 | ->with('WallabagUserBundle:User') |
121 | ->will($this->returnValue($em)); | 121 | ->will($this->returnValue($em)); |
122 | 122 | ||
123 | $params = new ParamConverter(array('class' => 'WallabagCoreBundle:User')); | 123 | $params = new ParamConverter(array('class' => 'WallabagUserBundle:User')); |
124 | $converter = new UsernameRssTokenConverter($registry); | 124 | $converter = new UsernameRssTokenConverter($registry); |
125 | 125 | ||
126 | $this->assertTrue($converter->supports($params)); | 126 | $this->assertTrue($converter->supports($params)); |
@@ -144,7 +144,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
144 | */ | 144 | */ |
145 | public function testApplyUserNotFound() | 145 | public function testApplyUserNotFound() |
146 | { | 146 | { |
147 | $repo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\UserRepository') | 147 | $repo = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository') |
148 | ->disableOriginalConstructor() | 148 | ->disableOriginalConstructor() |
149 | ->getMock(); | 149 | ->getMock(); |
150 | 150 | ||
@@ -159,7 +159,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
159 | 159 | ||
160 | $em->expects($this->once()) | 160 | $em->expects($this->once()) |
161 | ->method('getRepository') | 161 | ->method('getRepository') |
162 | ->with('WallabagCoreBundle:User') | 162 | ->with('WallabagUserBundle:User') |
163 | ->will($this->returnValue($repo)); | 163 | ->will($this->returnValue($repo)); |
164 | 164 | ||
165 | $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') | 165 | $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') |
@@ -168,10 +168,10 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
168 | 168 | ||
169 | $registry->expects($this->once()) | 169 | $registry->expects($this->once()) |
170 | ->method('getManagerForClass') | 170 | ->method('getManagerForClass') |
171 | ->with('WallabagCoreBundle:User') | 171 | ->with('WallabagUserBundle:User') |
172 | ->will($this->returnValue($em)); | 172 | ->will($this->returnValue($em)); |
173 | 173 | ||
174 | $params = new ParamConverter(array('class' => 'WallabagCoreBundle:User')); | 174 | $params = new ParamConverter(array('class' => 'WallabagUserBundle:User')); |
175 | $converter = new UsernameRssTokenConverter($registry); | 175 | $converter = new UsernameRssTokenConverter($registry); |
176 | $request = new Request(array(), array(), array('username' => 'test', 'token' => 'test')); | 176 | $request = new Request(array(), array(), array('username' => 'test', 'token' => 'test')); |
177 | 177 | ||
@@ -182,7 +182,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
182 | { | 182 | { |
183 | $user = new User(); | 183 | $user = new User(); |
184 | 184 | ||
185 | $repo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\UserRepository') | 185 | $repo = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository') |
186 | ->disableOriginalConstructor() | 186 | ->disableOriginalConstructor() |
187 | ->getMock(); | 187 | ->getMock(); |
188 | 188 | ||
@@ -197,7 +197,7 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
197 | 197 | ||
198 | $em->expects($this->once()) | 198 | $em->expects($this->once()) |
199 | ->method('getRepository') | 199 | ->method('getRepository') |
200 | ->with('WallabagCoreBundle:User') | 200 | ->with('WallabagUserBundle:User') |
201 | ->will($this->returnValue($repo)); | 201 | ->will($this->returnValue($repo)); |
202 | 202 | ||
203 | $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') | 203 | $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') |
@@ -206,10 +206,10 @@ class UsernameRssTokenConverterTest extends KernelTestCase | |||
206 | 206 | ||
207 | $registry->expects($this->once()) | 207 | $registry->expects($this->once()) |
208 | ->method('getManagerForClass') | 208 | ->method('getManagerForClass') |
209 | ->with('WallabagCoreBundle:User') | 209 | ->with('WallabagUserBundle:User') |
210 | ->will($this->returnValue($em)); | 210 | ->will($this->returnValue($em)); |
211 | 211 | ||
212 | $params = new ParamConverter(array('class' => 'WallabagCoreBundle:User', 'name' => 'user')); | 212 | $params = new ParamConverter(array('class' => 'WallabagUserBundle:User', 'name' => 'user')); |
213 | $converter = new UsernameRssTokenConverter($registry); | 213 | $converter = new UsernameRssTokenConverter($registry); |
214 | $request = new Request(array(), array(), array('username' => 'test', 'token' => 'test')); | 214 | $request = new Request(array(), array(), array('username' => 'test', 'token' => 'test')); |
215 | 215 | ||
diff --git a/src/Wallabag/UserBundle/Controller/ResettingController.php b/src/Wallabag/UserBundle/Controller/ResettingController.php new file mode 100644 index 00000000..8aa1e230 --- /dev/null +++ b/src/Wallabag/UserBundle/Controller/ResettingController.php | |||
@@ -0,0 +1,75 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle\Controller; | ||
4 | |||
5 | use FOS\UserBundle\FOSUserEvents; | ||
6 | use FOS\UserBundle\Event\FormEvent; | ||
7 | use FOS\UserBundle\Event\GetResponseUserEvent; | ||
8 | use FOS\UserBundle\Event\FilterUserResponseEvent; | ||
9 | use Symfony\Component\HttpFoundation\Request; | ||
10 | use Symfony\Component\HttpFoundation\RedirectResponse; | ||
11 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | ||
12 | |||
13 | class ResettingController extends \FOS\UserBundle\Controller\ResettingController | ||
14 | { | ||
15 | /** | ||
16 | * Extends ResettingController to change the redirection after success. | ||
17 | * | ||
18 | * @param Request $request | ||
19 | * @param $token | ||
20 | * | ||
21 | * @return null|RedirectResponse|\Symfony\Component\HttpFoundation\Response | ||
22 | */ | ||
23 | public function resetAction(Request $request, $token) | ||
24 | { | ||
25 | /** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */ | ||
26 | $formFactory = $this->get('fos_user.resetting.form.factory'); | ||
27 | /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */ | ||
28 | $userManager = $this->get('fos_user.user_manager'); | ||
29 | /** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */ | ||
30 | $dispatcher = $this->get('event_dispatcher'); | ||
31 | |||
32 | $user = $userManager->findUserByConfirmationToken($token); | ||
33 | |||
34 | if (null === $user) { | ||
35 | throw new NotFoundHttpException(sprintf('The user with "confirmation token" does not exist for value "%s"', $token)); | ||
36 | } | ||
37 | |||
38 | $event = new GetResponseUserEvent($user, $request); | ||
39 | $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_INITIALIZE, $event); | ||
40 | |||
41 | if (null !== $event->getResponse()) { | ||
42 | return $event->getResponse(); | ||
43 | } | ||
44 | |||
45 | $form = $formFactory->createForm(); | ||
46 | $form->setData($user); | ||
47 | |||
48 | $form->handleRequest($request); | ||
49 | |||
50 | if ($form->isValid()) { | ||
51 | $event = new FormEvent($form, $request); | ||
52 | $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event); | ||
53 | |||
54 | $userManager->updateUser($user); | ||
55 | |||
56 | if (null === $response = $event->getResponse()) { | ||
57 | $this->get('session')->getFlashBag()->add( | ||
58 | 'notice', | ||
59 | 'Password updated' | ||
60 | ); | ||
61 | $url = $this->generateUrl('homepage'); | ||
62 | $response = new RedirectResponse($url); | ||
63 | } | ||
64 | |||
65 | $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response)); | ||
66 | |||
67 | return $response; | ||
68 | } | ||
69 | |||
70 | return $this->render('FOSUserBundle:Resetting:reset.html.twig', array( | ||
71 | 'token' => $token, | ||
72 | 'form' => $form->createView(), | ||
73 | )); | ||
74 | } | ||
75 | } | ||
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php b/src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php index 4ef53329..d48855da 100644 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php +++ b/src/Wallabag/UserBundle/DataFixtures/ORM/LoadUserData.php | |||
@@ -1,11 +1,11 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\DataFixtures\ORM; | 3 | namespace Wallabag\UserBundle\DataFixtures\ORM; |
4 | 4 | ||
5 | use Doctrine\Common\DataFixtures\AbstractFixture; | 5 | use Doctrine\Common\DataFixtures\AbstractFixture; |
6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; | 6 | use Doctrine\Common\DataFixtures\OrderedFixtureInterface; |
7 | use Doctrine\Common\Persistence\ObjectManager; | 7 | use Doctrine\Common\Persistence\ObjectManager; |
8 | use Wallabag\CoreBundle\Entity\User; | 8 | use Wallabag\UserBundle\Entity\User; |
9 | 9 | ||
10 | class LoadUserData extends AbstractFixture implements OrderedFixtureInterface | 10 | class LoadUserData extends AbstractFixture implements OrderedFixtureInterface |
11 | { | 11 | { |
@@ -18,8 +18,9 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface | |||
18 | $userAdmin->setName('Big boss'); | 18 | $userAdmin->setName('Big boss'); |
19 | $userAdmin->setEmail('bigboss@wallabag.org'); | 19 | $userAdmin->setEmail('bigboss@wallabag.org'); |
20 | $userAdmin->setUsername('admin'); | 20 | $userAdmin->setUsername('admin'); |
21 | $userAdmin->setPassword('mypassword'); | 21 | $userAdmin->setPlainPassword('mypassword'); |
22 | $userAdmin->setEnabled(true); | 22 | $userAdmin->setEnabled(true); |
23 | $userAdmin->addRole('ROLE_SUPER_ADMIN'); | ||
23 | 24 | ||
24 | $manager->persist($userAdmin); | 25 | $manager->persist($userAdmin); |
25 | 26 | ||
@@ -29,7 +30,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface | |||
29 | $bobUser->setName('Bobby'); | 30 | $bobUser->setName('Bobby'); |
30 | $bobUser->setEmail('bobby@wallabag.org'); | 31 | $bobUser->setEmail('bobby@wallabag.org'); |
31 | $bobUser->setUsername('bob'); | 32 | $bobUser->setUsername('bob'); |
32 | $bobUser->setPassword('mypassword'); | 33 | $bobUser->setPlainPassword('mypassword'); |
33 | $bobUser->setEnabled(true); | 34 | $bobUser->setEnabled(true); |
34 | 35 | ||
35 | $manager->persist($bobUser); | 36 | $manager->persist($bobUser); |
diff --git a/src/Wallabag/CoreBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index a6002352..8f02e070 100644 --- a/src/Wallabag/CoreBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php | |||
@@ -1,20 +1,22 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Entity; | 3 | namespace Wallabag\UserBundle\Entity; |
4 | 4 | ||
5 | use Doctrine\Common\Collections\ArrayCollection; | 5 | use Doctrine\Common\Collections\ArrayCollection; |
6 | use Doctrine\ORM\Mapping as ORM; | 6 | use Doctrine\ORM\Mapping as ORM; |
7 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | 7 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; |
8 | use Symfony\Component\Security\Core\User\UserInterface; | 8 | use Symfony\Component\Security\Core\User\UserInterface; |
9 | use Symfony\Component\Security\Core\User\AdvancedUserInterface; | ||
10 | use JMS\Serializer\Annotation\ExclusionPolicy; | 9 | use JMS\Serializer\Annotation\ExclusionPolicy; |
11 | use JMS\Serializer\Annotation\Expose; | 10 | use JMS\Serializer\Annotation\Expose; |
12 | use FOS\UserBundle\Model\User as BaseUser; | 11 | use FOS\UserBundle\Model\User as BaseUser; |
12 | use Wallabag\CoreBundle\Entity\Config; | ||
13 | use Wallabag\CoreBundle\Entity\Entry; | ||
14 | use Wallabag\CoreBundle\Entity\Tag; | ||
13 | 15 | ||
14 | /** | 16 | /** |
15 | * User. | 17 | * User. |
16 | * | 18 | * |
17 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\UserRepository") | 19 | * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") |
18 | * @ORM\Table | 20 | * @ORM\Table |
19 | * @ORM\HasLifecycleCallbacks() | 21 | * @ORM\HasLifecycleCallbacks() |
20 | * @ExclusionPolicy("all") | 22 | * @ExclusionPolicy("all") |
@@ -22,7 +24,7 @@ use FOS\UserBundle\Model\User as BaseUser; | |||
22 | * @UniqueEntity("email") | 24 | * @UniqueEntity("email") |
23 | * @UniqueEntity("username") | 25 | * @UniqueEntity("username") |
24 | */ | 26 | */ |
25 | class User extends BaseUser implements AdvancedUserInterface, \Serializable | 27 | class User extends BaseUser |
26 | { | 28 | { |
27 | /** | 29 | /** |
28 | * @var int | 30 | * @var int |
@@ -56,17 +58,17 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
56 | protected $updatedAt; | 58 | protected $updatedAt; |
57 | 59 | ||
58 | /** | 60 | /** |
59 | * @ORM\OneToMany(targetEntity="Entry", mappedBy="user", cascade={"remove"}) | 61 | * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Entry", mappedBy="user", cascade={"remove"}) |
60 | */ | 62 | */ |
61 | protected $entries; | 63 | protected $entries; |
62 | 64 | ||
63 | /** | 65 | /** |
64 | * @ORM\OneToOne(targetEntity="Config", mappedBy="user") | 66 | * @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user") |
65 | */ | 67 | */ |
66 | protected $config; | 68 | protected $config; |
67 | 69 | ||
68 | /** | 70 | /** |
69 | * @ORM\OneToMany(targetEntity="Tag", mappedBy="user", cascade={"remove"}) | 71 | * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Tag", mappedBy="user", cascade={"remove"}) |
70 | */ | 72 | */ |
71 | protected $tags; | 73 | protected $tags; |
72 | 74 | ||
@@ -75,6 +77,7 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
75 | parent::__construct(); | 77 | parent::__construct(); |
76 | $this->entries = new ArrayCollection(); | 78 | $this->entries = new ArrayCollection(); |
77 | $this->tags = new ArrayCollection(); | 79 | $this->tags = new ArrayCollection(); |
80 | $this->roles = array('ROLE_USER'); | ||
78 | } | 81 | } |
79 | 82 | ||
80 | /** | 83 | /** |
@@ -91,24 +94,6 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
91 | } | 94 | } |
92 | 95 | ||
93 | /** | 96 | /** |
94 | * Set password. | ||
95 | * | ||
96 | * @param string $password | ||
97 | * | ||
98 | * @return User | ||
99 | */ | ||
100 | public function setPassword($password) | ||
101 | { | ||
102 | if (!$password && 0 === strlen($password)) { | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | $this->password = sha1($password.$this->getUsername().$this->getSalt()); | ||
107 | |||
108 | return $this; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Set name. | 97 | * Set name. |
113 | * | 98 | * |
114 | * @param string $name | 99 | * @param string $name |
@@ -196,11 +181,11 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
196 | /** | 181 | /** |
197 | * Set config. | 182 | * Set config. |
198 | * | 183 | * |
199 | * @param \Wallabag\CoreBundle\Entity\Config $config | 184 | * @param Config $config |
200 | * | 185 | * |
201 | * @return User | 186 | * @return User |
202 | */ | 187 | */ |
203 | public function setConfig(\Wallabag\CoreBundle\Entity\Config $config = null) | 188 | public function setConfig(Config $config = null) |
204 | { | 189 | { |
205 | $this->config = $config; | 190 | $this->config = $config; |
206 | 191 | ||
@@ -210,7 +195,7 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
210 | /** | 195 | /** |
211 | * Get config. | 196 | * Get config. |
212 | * | 197 | * |
213 | * @return \Wallabag\CoreBundle\Entity\Config | 198 | * @return Config |
214 | */ | 199 | */ |
215 | public function getConfig() | 200 | public function getConfig() |
216 | { | 201 | { |
diff --git a/src/Wallabag/CoreBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php index 968d0b49..c020f3ca 100644 --- a/src/Wallabag/CoreBundle/Repository/UserRepository.php +++ b/src/Wallabag/UserBundle/Repository/UserRepository.php | |||
@@ -1,6 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Repository; | 3 | namespace Wallabag\UserBundle\Repository; |
4 | 4 | ||
5 | use Doctrine\ORM\EntityRepository; | 5 | use Doctrine\ORM\EntityRepository; |
6 | 6 | ||
diff --git a/src/Wallabag/UserBundle/Resources/config/services.yml b/src/Wallabag/UserBundle/Resources/config/services.yml new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/config/services.yml | |||
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 index 00000000..e5c1876b --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register.html.twig | |||
@@ -0,0 +1,20 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}{% trans %}create an account{% endtrans %}{% endblock %} | ||
4 | |||
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | {% block messages %}{% endblock %} | ||
9 | |||
10 | {% block content %} | ||
11 | <form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register"> | ||
12 | <fieldset class="w500p center"> | ||
13 | <h2 class="mbs txtcenter">{% trans %}create an account{% endtrans %}</h2> | ||
14 | {% include "FOSUserBundle:Registration:register_content.html.twig" %} | ||
15 | </fieldset> | ||
16 | </form> | ||
17 | {% endblock %} | ||
18 | |||
19 | {% block footer %} | ||
20 | {% 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 index 00000000..41f94006 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Registration/register_content.html.twig | |||
@@ -0,0 +1,37 @@ | |||
1 | {% trans_default_domain 'FOSUserBundle' %} | ||
2 | |||
3 | {{ form_widget(form._token) }} | ||
4 | |||
5 | {% for flashMessage in app.session.flashbag.get('notice') %} | ||
6 | <span><p>{{ flashMessage }}</p></span> | ||
7 | {% endfor %} | ||
8 | |||
9 | <div class="row"> | ||
10 | {{ form_errors(form.email) }} | ||
11 | {{ form_label(form.email) }} | ||
12 | {{ form_widget(form.email) }} | ||
13 | </div> | ||
14 | |||
15 | <div class="row"> | ||
16 | {{ form_errors(form.username) }} | ||
17 | {{ form_label(form.username) }} | ||
18 | {{ form_widget(form.username) }} | ||
19 | </div> | ||
20 | |||
21 | <div class="row"> | ||
22 | {{ form_errors(form.plainPassword.first) }} | ||
23 | {{ form_label(form.plainPassword.first) }} | ||
24 | {{ form_widget(form.plainPassword.first) }} | ||
25 | </div> | ||
26 | |||
27 | <div class="row"> | ||
28 | {{ form_errors(form.plainPassword.second) }} | ||
29 | {{ form_label(form.plainPassword.second) }} | ||
30 | {{ form_widget(form.plainPassword.second) }} | ||
31 | </div> | ||
32 | |||
33 | |||
34 | <div class="row mts txtcenter"> | ||
35 | <button type="submit">{{ 'registration.submit'|trans({}, 'FOSUserBundle') }}</button> | ||
36 | <a href="{{ path('fos_user_security_login') }}" class="button">{% trans %}Login{% endtrans %}</a> | ||
37 | </div> | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/checkEmail.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/checkEmail.html.twig index 056d65b5..056d65b5 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/checkEmail.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/checkEmail.html.twig | |||
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 index 00000000..10094e83 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request.html.twig | |||
@@ -0,0 +1,20 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}{% trans %}Forgot password{% endtrans %}{% endblock %} | ||
4 | |||
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | {% block messages %}{% endblock %} | ||
9 | |||
10 | {% block content %} | ||
11 | <form action="{{ path('fos_user_resetting_send_email') }}" method="post" name="forgotPasswordform"> | ||
12 | <fieldset class="w500p center"> | ||
13 | <h2 class="mbs txtcenter">{% trans %}Forgot password{% endtrans %}</h2> | ||
14 | {% include "FOSUserBundle:Resetting:request_content.html.twig" %} | ||
15 | </fieldset> | ||
16 | </form> | ||
17 | {% endblock %} | ||
18 | |||
19 | {% block footer %} | ||
20 | {% 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 index 00000000..1f8da8d7 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Resetting/request_content.html.twig | |||
@@ -0,0 +1,17 @@ | |||
1 | {% trans_default_domain 'FOSUserBundle' %} | ||
2 | |||
3 | {% trans %}Enter your email address below and we'll send you password reset instructions.{% endtrans %} | ||
4 | |||
5 | {% if invalid_username is defined %} | ||
6 | <p>{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}) }}</p> | ||
7 | {% endif %} | ||
8 | |||
9 | <div class="row"> | ||
10 | <label for="username">{{ 'resetting.request.username'|trans }}</label> | ||
11 | <input type="text" id="username" name="username" required="required" /> | ||
12 | </div> | ||
13 | |||
14 | <div class="row mts txtcenter"> | ||
15 | <button type="submit">{{ 'resetting.request.submit'|trans }}</button> | ||
16 | <a href="{{ path('fos_user_security_login') }}" class="button">{% trans %}Login{% endtrans %}</a> | ||
17 | </div> | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/login.html.twig b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Security/login.html.twig index 5437d20c..d52c3662 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Security/login.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/Security/login.html.twig | |||
@@ -1,14 +1,7 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | 1 | {% extends "FOSUserBundle::layout.html.twig" %} |
2 | 2 | ||
3 | {% block title %}{% trans %}login to your wallabag{% endtrans %}{% endblock %} | 3 | {% block fos_user_content %} |
4 | 4 | <form action="{{ path('fos_user_security_check') }}" method="post" name="loginform"> | |
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | {% block messages %}{% endblock %} | ||
9 | |||
10 | {% block content %} | ||
11 | <form action="{{ path('login_check') }}" method="post" name="loginform"> | ||
12 | <fieldset class="w500p center"> | 5 | <fieldset class="w500p center"> |
13 | <h2 class="mbs txtcenter">{% trans %}Login to wallabag{% endtrans %}</h2> | 6 | <h2 class="mbs txtcenter">{% trans %}Login to wallabag{% endtrans %}</h2> |
14 | {% if error %} | 7 | {% if error %} |
@@ -32,7 +25,8 @@ | |||
32 | <div class="row mts txtcenter"> | 25 | <div class="row mts txtcenter"> |
33 | <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" /> | 26 | <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" /> |
34 | <button type="submit">Login</button> | 27 | <button type="submit">Login</button> |
35 | <a href="{{ path('forgot_password') }}" class="small">Forgot your password?</a> | 28 | <a href="{{ path('fos_user_registration_register') }}" class="button">{% trans %}Register{% endtrans %}</a> |
29 | <a href="{{ path('fos_user_resetting_request') }}" class="small">Forgot your password?</a> | ||
36 | </div> | 30 | </div> |
37 | </fieldset> | 31 | </fieldset> |
38 | </form> | 32 | </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 index 00000000..ff5b6583 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/baggy/layout.html.twig | |||
@@ -0,0 +1,16 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}Welcome on wallabag!{% endblock %} | ||
4 | |||
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | {% block messages %}{% endblock %} | ||
9 | |||
10 | {% block content %} | ||
11 | {% block fos_user_content %} | ||
12 | {% endblock fos_user_content %} | ||
13 | {% endblock %} | ||
14 | |||
15 | {% block footer %} | ||
16 | {% 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 index 00000000..e7b7318b --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/ChangePassword/changePassword_content.html.twig | |||
@@ -0,0 +1,12 @@ | |||
1 | {% trans_default_domain 'FOSUserBundle' %} | ||
2 | |||
3 | <form action="{{ path('fos_user_change_password') }}" {{ form_enctype(form) }} method="POST" class="fos_user_change_password"> | ||
4 | <div class="card-content"> | ||
5 | <div class="row"> | ||
6 | {{ form_widget(form) }} | ||
7 | <div> | ||
8 | <input type="submit" value="{{ 'change_password.submit'|trans }}" /> | ||
9 | </div> | ||
10 | </div> | ||
11 | </div> | ||
12 | </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 index 00000000..50937276 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/checkEmail.html.twig | |||
@@ -0,0 +1,11 @@ | |||
1 | {% extends "FOSUserBundle::layout.html.twig" %} | ||
2 | |||
3 | {% trans_default_domain 'FOSUserBundle' %} | ||
4 | |||
5 | {% block fos_user_content %} | ||
6 | <div class="card-content"> | ||
7 | <div class="row"> | ||
8 | <p>{{ 'registration.check_email'|trans({'%email%': user.email}) }}</p> | ||
9 | </div> | ||
10 | </div> | ||
11 | {% 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 index 00000000..c6d4d3d2 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/confirmed.html.twig | |||
@@ -0,0 +1,17 @@ | |||
1 | {% extends "FOSUserBundle::layout.html.twig" %} | ||
2 | |||
3 | {% trans_default_domain 'FOSUserBundle' %} | ||
4 | |||
5 | {% block fos_user_content %} | ||
6 | <div class="card-content"> | ||
7 | <div class="row"> | ||
8 | <p>{{ 'registration.confirmed'|trans({'%username%': user.username}) }}</p> | ||
9 | {% if targetUrl %} | ||
10 | <p><a href="{{ targetUrl }}">{{ 'registration.back'|trans }}</a></p> | ||
11 | {% endif %} | ||
12 | </div> | ||
13 | <div class="card-action center"> | ||
14 | <a href="{{ path('homepage') }}" class="waves-effect waves-light btn"><i class="material-icons left"></i> {% trans %}Go to your account{% endtrans %}</a> | ||
15 | </div> | ||
16 | </div> | ||
17 | {% 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 index 00000000..865a24ae --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Registration/register_content.html.twig | |||
@@ -0,0 +1,45 @@ | |||
1 | {% trans_default_domain 'FOSUserBundle' %} | ||
2 | |||
3 | <form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register"> | ||
4 | <div class="card-content"> | ||
5 | <div class="row"> | ||
6 | |||
7 | {{ form_widget(form._token) }} | ||
8 | |||
9 | {% for flashMessage in app.session.flashbag.get('notice') %} | ||
10 | <span class="black-text"><p>{{ flashMessage }}</p></span> | ||
11 | {% endfor %} | ||
12 | |||
13 | <div class="input-field col s12"> | ||
14 | {{ form_errors(form.email) }} | ||
15 | {{ form_label(form.email) }} | ||
16 | {{ form_widget(form.email) }} | ||
17 | </div> | ||
18 | |||
19 | <div class="input-field col s12"> | ||
20 | {{ form_errors(form.username) }} | ||
21 | {{ form_label(form.username) }} | ||
22 | {{ form_widget(form.username) }} | ||
23 | </div> | ||
24 | |||
25 | <div class="input-field col s12"> | ||
26 | {{ form_errors(form.plainPassword.first) }} | ||
27 | {{ form_label(form.plainPassword.first) }} | ||
28 | {{ form_widget(form.plainPassword.first) }} | ||
29 | </div> | ||
30 | |||
31 | <div class="input-field col s12"> | ||
32 | {{ form_errors(form.plainPassword.second) }} | ||
33 | {{ form_label(form.plainPassword.second) }} | ||
34 | {{ form_widget(form.plainPassword.second) }} | ||
35 | </div> | ||
36 | </div> | ||
37 | </div> | ||
38 | <div class="card-action center"> | ||
39 | <a href="{{ path('fos_user_security_login') }}" class="waves-effect waves-light grey btn"><i class="material-icons left"></i> {% trans %}Login{% endtrans %}</a> | ||
40 | <button class="btn waves-effect waves-light" type="submit" name="send"> | ||
41 | {{ 'registration.submit'|trans({}, 'FOSUserBundle') }} | ||
42 | <i class="mdi-content-send right"></i> | ||
43 | </button> | ||
44 | </div> | ||
45 | </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 index 00000000..66cbdc28 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/checkEmail.html.twig | |||
@@ -0,0 +1,11 @@ | |||
1 | {% extends "FOSUserBundle::layout.html.twig" %} | ||
2 | |||
3 | {% trans_default_domain 'FOSUserBundle' %} | ||
4 | |||
5 | {% block fos_user_content %} | ||
6 | <div class="card-content"> | ||
7 | <div class="row"> | ||
8 | {{ 'resetting.check_email'|trans({'%email%': email}) }} | ||
9 | </div> | ||
10 | </div> | ||
11 | {% 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 index 00000000..0eec4301 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/passwordAlreadyRequested.html.twig | |||
@@ -0,0 +1,11 @@ | |||
1 | {% extends "FOSUserBundle::layout.html.twig" %} | ||
2 | |||
3 | {% trans_default_domain 'FOSUserBundle' %} | ||
4 | |||
5 | {% block fos_user_content %} | ||
6 | <div class="card-content"> | ||
7 | <div class="row"> | ||
8 | {{ 'resetting.password_already_requested'|trans }} | ||
9 | </div> | ||
10 | </div> | ||
11 | {% 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 index 00000000..e871d7be --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/request_content.html.twig | |||
@@ -0,0 +1,26 @@ | |||
1 | {% trans_default_domain 'FOSUserBundle' %} | ||
2 | <form action="{{ path('fos_user_resetting_send_email') }}" method="POST" class="fos_user_resetting_request"> | ||
3 | <div class="card-content"> | ||
4 | <div class="row"> | ||
5 | <p>{% trans %}Enter your email address below and we'll send you password reset instructions.{% endtrans %}</p> | ||
6 | {% for flashMessage in app.session.flashbag.get('notice') %} | ||
7 | <span class="black-text"><p>{{ flashMessage }}</p></span> | ||
8 | {% endfor %} | ||
9 | |||
10 | {% if invalid_username is defined %} | ||
11 | <p>{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}) }}</p> | ||
12 | {% endif %} | ||
13 | |||
14 | <div class="input-field col s12"> | ||
15 | <label for="username">{{ 'resetting.request.username'|trans }}</label> | ||
16 | <input type="text" id="username" name="username" required="required" /> | ||
17 | </div> | ||
18 | </div> | ||
19 | </div> | ||
20 | <div class="card-action center"> | ||
21 | <a href="{{ path('fos_user_security_login') }}" class="waves-effect waves-light grey btn"><i class="material-icons left"></i> {% trans %}Login{% endtrans %}</a> | ||
22 | <button class="btn waves-effect waves-light" type="submit" name="send"> | ||
23 | {{ 'resetting.request.submit'|trans }} | ||
24 | </button> | ||
25 | </div> | ||
26 | </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 index 00000000..f7e061dd --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Resetting/reset_content.html.twig | |||
@@ -0,0 +1,15 @@ | |||
1 | {% trans_default_domain 'FOSUserBundle' %} | ||
2 | |||
3 | <form action="{{ path('fos_user_resetting_reset', {'token': token}) }}" {{ form_enctype(form) }} method="POST" class="fos_user_resetting_reset"> | ||
4 | <div class="card-content"> | ||
5 | <div class="row"> | ||
6 | {{ form_widget(form) }} | ||
7 | </div> | ||
8 | <div class="card-action center"> | ||
9 | <button class="btn waves-effect waves-light" type="submit" name="send"> | ||
10 | {{ 'resetting.reset.submit'|trans }} | ||
11 | <i class="mdi-content-send right"></i> | ||
12 | </button> | ||
13 | </div> | ||
14 | </div> | ||
15 | </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 index 00000000..6bf99bf8 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/Security/login.html.twig | |||
@@ -0,0 +1,46 @@ | |||
1 | {% extends "FOSUserBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block fos_user_content %} | ||
4 | <form action="{{ path('fos_user_security_check') }}" method="post" name="loginform"> | ||
5 | <div class="card-content"> | ||
6 | |||
7 | {% if error %} | ||
8 | <span class="black-text">{{ error.message }}</span> | ||
9 | {% endif %} | ||
10 | |||
11 | {% for flashMessage in app.session.flashbag.get('notice') %} | ||
12 | <span class="black-text"><p>{{ flashMessage }}</p></span> | ||
13 | {% endfor %} | ||
14 | |||
15 | <div class="row"> | ||
16 | |||
17 | <div class="input-field col s12"> | ||
18 | <label for="username">{% trans %}Username{% endtrans %}</label> | ||
19 | <input type="text" id="username" name="_username" value="{{ last_username }}" /> | ||
20 | </div> | ||
21 | |||
22 | <div class="input-field col s12"> | ||
23 | <label for="password">{% trans %}Password{% endtrans %}</label> | ||
24 | <input type="password" id="password" name="_password" /> | ||
25 | </div> | ||
26 | |||
27 | <div class="input-field col s12"> | ||
28 | <input type="checkbox" id="remember_me" name="_remember_me" checked /> | ||
29 | <label for="remember_me">{% trans %}Keep me logged in{% endtrans %}</label> | ||
30 | </div> | ||
31 | |||
32 | </div> | ||
33 | </div> | ||
34 | <div class="card-action center"> | ||
35 | <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" /> | ||
36 | <a href="{{ path('fos_user_registration_register') }}" class="waves-effect waves-light grey btn"><i class="material-icons left"></i> {% trans %}Register{% endtrans %}</a> | ||
37 | <button class="btn waves-effect waves-light" type="submit" name="send"> | ||
38 | {% trans %}Login{% endtrans %} | ||
39 | <i class="mdi-content-send right"></i> | ||
40 | </button> | ||
41 | </div> | ||
42 | <div class="center"> | ||
43 | <a href="{{ path('fos_user_resetting_request') }}">{% trans %}Forgot your password?{% endtrans %}</a> | ||
44 | </div> | ||
45 | </form> | ||
46 | {% 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 index 00000000..a69e68c2 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/views/themes/material/layout.html.twig | |||
@@ -0,0 +1,23 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}Welcome on wallabag!{% endblock %} | ||
4 | |||
5 | {% block body_class %}login{% endblock %} | ||
6 | |||
7 | {% block menu %}{% endblock %} | ||
8 | {% block messages %}{% endblock %} | ||
9 | |||
10 | {% block content %} | ||
11 | <main class="valign-wrapper"> | ||
12 | <div class="valign row"> | ||
13 | <div class="card sw"> | ||
14 | <div class="center"><img src="{{ asset('themes/material/img/logo-other_themes.png') }}" alt="wallabag logo" /></div> | ||
15 | {% block fos_user_content %} | ||
16 | {% endblock fos_user_content %} | ||
17 | </div> | ||
18 | </div> | ||
19 | </main> | ||
20 | {% endblock %} | ||
21 | |||
22 | {% block footer %} | ||
23 | {% endblock %} | ||
diff --git a/src/Wallabag/UserBundle/WallabagUserBundle.php b/src/Wallabag/UserBundle/WallabagUserBundle.php new file mode 100644 index 00000000..d9180b3b --- /dev/null +++ b/src/Wallabag/UserBundle/WallabagUserBundle.php | |||
@@ -0,0 +1,13 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle; | ||
4 | |||
5 | use Symfony\Component\HttpKernel\Bundle\Bundle; | ||
6 | |||
7 | class WallabagUserBundle extends Bundle | ||
8 | { | ||
9 | public function getParent() | ||
10 | { | ||
11 | return 'FOSUserBundle'; | ||
12 | } | ||
13 | } | ||