diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php index ded8cf54b8..87b641db7e 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Account.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -154,21 +154,6 @@ class Account implements ControllerProviderInterface */ $controllers->get('/access/', $this->call('accountAccess'))->bind('account_access'); -// /** -// * Give account open sessions -// * -// * name : register_account -// * -// * description : Display form to create a new account -// * -// * method : GET -// * -// * parameters : none -// * -// * return : HTML Response -// */ -// $controllers->get('/register/', $this->call('registerAccount'))->bind('register_account'); - /** * Give authorized applications that can access user informations * @@ -182,7 +167,7 @@ class Account implements ControllerProviderInterface * * return : HTML Response */ - $controllers->get('/reset-email/', $this->call('resetEmail'))->bind('reset_email'); + $controllers->post('/reset-email/', $this->call('resetEmail'))->bind('reset_email'); /** * Grant access to an authorized app @@ -251,11 +236,13 @@ class Account implements ControllerProviderInterface return $controllers; } - public function registerAccount(Application $app, Request $request) - { - return new Response($app['twig']->render('account/register.html.twig')); - } - + /** + * Reset Password + * + * @param \Silex\Application $app + * @param \Symfony\Component\HttpFoundation\Request $request + * @return \Symfony\Component\HttpFoundation\Response + */ public function resetPassword(Application $app, Request $request) { if (null !== $passwordMsg = $request->get('pass-error')) { @@ -278,7 +265,7 @@ class Account implements ControllerProviderInterface } /** - * Reset email + * Reset Email * * @param \Silex\Application $app * @param \Symfony\Component\HttpFoundation\Request $request @@ -443,12 +430,12 @@ class Account implements ControllerProviderInterface , new \API_OAuth2_Application($appbox, $application_id) , $app['phraseanet.core']->getAuthenticatedUser() ); + + $account->set_revoked((bool) $request->get('revoke'), false); } catch (\Exception_NotFound $e) { $error = true; } - $account->set_revoked((bool) $request->get('revoke'), false); - return $app->json(array('success' => ! $error)); } @@ -555,7 +542,7 @@ class Account implements ControllerProviderInterface $demands = (array) $request->get('demand', array()); - if (0 === count($demands)) { + if (0 !== count($demands)) { $register = new \appbox_register($appbox); foreach ($demands as $baseId) { @@ -563,7 +550,7 @@ class Account implements ControllerProviderInterface $register->add_request($user, \collection::get_from_base_id($baseId)); $notice = 'demand-ok'; } catch (\Exception $e) { - + exit($e->getMessage()); } } } @@ -640,10 +627,10 @@ class Account implements ControllerProviderInterface foreach ($evtMngr->list_notifications_available($user->get_id()) as $notifications) { foreach ($notifications as $notification) { - $notifId = (int) $notification['id']; + $notifId = $notification['id']; $notifName = sprintf('notification_%d', $notifId); - if (isset($requestedNotifications[$notifId])) { + if (in_array($notifId, $requestedNotifications)) { $user->setPrefs($notifName, '1'); } else { $user->setPrefs($notifName, '0'); diff --git a/templates/web/account/access.html.twig b/templates/web/account/access.html.twig index d1471f0f4d..afa68d7610 100644 --- a/templates/web/account/access.html.twig +++ b/templates/web/account/access.html.twig @@ -18,7 +18,7 @@ {% if baseInsc['CollsRegistered'] is not none %} {% for base in baseInsc['CollsRegistered']%} {% for collId, isTrue in base %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %} {% trans 'login::register: acces authorise sur la collection ' %}{{ sbasId |sbas_names }} @@ -37,7 +37,7 @@ {% if baseInsc['CollsRefuse'] %} {% for collId, isTrue in baseInsc['CollsRefuse'] %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %} {% trans 'login::register: acces refuse sur la collection ' %}{{ sbasId |sbas_names }} @@ -55,7 +55,7 @@ {% if baseInsc['CollsWait'] %} {% for collId, isTrue in baseInsc['CollsWait'] %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %} {% trans 'login::register: en attente d\'acces sur' %} {{ sbasId |sbas_names }} @@ -70,7 +70,7 @@ {% if baseInsc['CollsIntime'] %} {% for collId, isTrue in baseInsc['CollsIntime'] %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %} {% trans 'login::register: acces temporaire sur' %} {{ sbasId |sbas_names }} @@ -85,7 +85,7 @@ {% if baseInsc['CollsOuttime'] %} {% for collId, isTrue in baseInsc['CollsOuttime'] %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %} {% trans 'login::register: acces temporaire termine sur ' %}{{ sbasId |sbas_names }} @@ -100,7 +100,7 @@ {% if baseInsc['CollsNonactif'] %} {% for collId, isTrue in baseInsc['CollsNonactif'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {% set base_id = sbasId |base_from_coll(collId) %} {% trans 'login::register: acces supendu sur' %} {{ sbasId |sbas_names }} @@ -114,7 +114,6 @@ {% endif %} {% if (baseInsc['CollsCGU'] or baseInsc['Colls']) and baseInsc['inscript'] %} - {{ noDemand == false }} {% if baseInsc['Colls'] %} {% if baseInsc['CGU'] %} @@ -125,7 +124,7 @@ {% endif %} {% for collId, collName in baseInsc['Colls'] %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %} {{ collName }} @@ -138,7 +137,7 @@ {% endif %} {% if baseInsc['CollsCGU'] %} {% for collId, collDesc in baseInsc['CollsCGU'] %} - {{ base_id == sbasId |base_from_coll(collId) }} + {% set base_id = sbasId |base_from_coll(collId) %}
diff --git a/templates/web/account/reset-email.html.twig b/templates/web/account/reset-email.html.twig index 3e6f348d4a..6c2a17cfd0 100644 --- a/templates/web/account/reset-email.html.twig +++ b/templates/web/account/reset-email.html.twig @@ -48,7 +48,7 @@ $(document).ready(function() { {% block content %} {% if updateMsg is not none %} -
{{ updateMsg }}
+
{{ updateMsg }}
{% trans 'admin::compte-utilisateur retour a mon compte'%} {% else %} diff --git a/templates/web/account/reset-password.html.twig b/templates/web/account/reset-password.html.twig index 036fec84ed..1b7b1b9152 100644 --- a/templates/web/account/reset-password.html.twig +++ b/templates/web/account/reset-password.html.twig @@ -56,7 +56,7 @@ {% block content %}
{% if passwordMsg is not none %} -

{{ passwordMsg }}

+

{{ passwordMsg }}

{% endif %}
diff --git a/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php b/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php index 737705c9c4..a3b895ef20 100644 --- a/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php +++ b/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php @@ -4,6 +4,27 @@ require_once __DIR__ . '/../../../../PhraseanetWebTestCaseAuthenticatedAbstract. class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { + protected static $authorizedApp; + + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + + try { + self::$authorizedApp = \API_OAuth2_Application::create(\appbox::get_instance(\bootstrap::getCore()), self::$user, 'test API v1'); + } catch (\Exception $e) { + + } + } + + public static function tearDownAfterClass() + { + parent::tearDownAfterClass(); + + if (self::$authorizedApp) { + self::$authorizedApp->delete(); + } + } public function setUp() { @@ -22,19 +43,53 @@ class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::displayAccount + * @covers \Alchemy\Phrasea\Controller\Root\Account::displayAccount + * @covers \Alchemy\Phrasea\Controller\Root\Account::call */ public function testGetAccount() { - $this->client->request('GET', '/account/'); + $crawler = $this->client->request('GET', '/account/'); $response = $this->client->getResponse(); $this->assertTrue($response->isOk()); + + $actionForm = $crawler->filter('form[name=account]')->attr('action'); + $methodForm = $crawler->filter('form[name=account]')->attr('method'); + + $this->assertEquals('/account/', $actionForm); + $this->assertEquals('post', $methodForm); } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::accountAccess + * @dataProvider msgProvider + */ + public function testGetAccountNotice($msg) + { + $crawler = $this->client->request('GET', '/account/', array( + 'notice' => $msg + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isOk()); + + $this->assertEquals(1, $crawler->filter('.notice')->count()); + } + + public function msgProvider() + { + return array( + array('pass-ok'), + array('pass-ko'), + array('account-update-ok'), + array('account-update-bad'), + array('demand-ok'), + ); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::accountAccess */ public function testGetAccountAccess() { @@ -46,19 +101,165 @@ class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::resetEmail + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail */ - public function testGetResetMail() + public function testPostResetMailWithToken() { - $this->client->request('GET', '/account/reset-email/'); - + $token = \random::getUrlToken(\random::TYPE_EMAIL, self::$user->get_id(), null, 'new_email@email.com'); + $this->client->request('POST', '/account/reset-email/', array('token' => $token)); $response = $this->client->getResponse(); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/reset-email/?update=ok', $response->headers->get('location')); - $this->assertTrue($response->isOk()); + $this->assertEquals('new_email@email.com', self::$user->get_email()); + + try { + \random::helloToken($token); + $this->fail('TOken has not been removed'); + } catch (\Exception_NotFound $e) { + + } } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::accountSessionsAccess + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail + */ + public function testPostResetMailWithBadToken() + { + $this->client->request('POST', '/account/reset-email/', array('token' => '134dT0k3n')); + $response = $this->client->getResponse(); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/reset-email/?update=ko', $response->headers->get('location')); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail + * @expectedException Symfony\Component\HttpKernel\Exception\HttpException + */ + public function testPostResetMailBadRequest() + { + $this->client->request('POST', '/account/reset-email/'); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail + */ + public function testPostResetMailBadPassword() + { + $this->client->request('POST', '/account/reset-email/', array( + 'form_password' => 'changeme', + 'form_email' => 'new@email.com', + 'form_email_confirm' => 'new@email.com', + )); + + $response = $this->client->getResponse(); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/reset-email/?notice=bad-password', $response->headers->get('location')); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail + */ + public function testPostResetMailBadEmail() + { + $password = \random::generatePassword(); + self::$user->set_password($password); + $this->client->request('POST', '/account/reset-email/', array( + 'form_password' => $password, + 'form_email' => "invalid#!&&@@email.x", + 'form_email_confirm' => 'invalid#!&&@@email.x', + )); + + $response = $this->client->getResponse(); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/reset-email/?notice=mail-invalid', $response->headers->get('location')); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail + */ + public function testPostResetMailEmailNotIdentical() + { + $password = \random::generatePassword(); + self::$user->set_password($password); + $this->client->request('POST', '/account/reset-email/', array( + 'form_password' => $password, + 'form_email' => 'email1@email.com', + 'form_email_confirm' => 'email2@email.com', + )); + + $response = $this->client->getResponse(); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/reset-email/?notice=mail-match', $response->headers->get('location')); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetEmail + */ + public function testPostResetMailEmail() + { + $password = \random::generatePassword(); + self::$user->set_password($password); + $this->client->request('POST', '/account/reset-email/', array( + 'form_password' => $password, + 'form_email' => 'email1@email.com', + 'form_email_confirm' => 'email1@email.com', + )); + + $response = $this->client->getResponse(); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/reset-email/?update=mail-send', $response->headers->get('location')); + } + + /** + * @dataProvider noticeProvider + */ + public function testGetResetMailNotice($notice) + { + $crawler = $this->client->request('GET', '/account/reset-email/', array( + 'notice' => $notice + )); + + $this->assertTrue($this->client->getResponse()->isOk()); + + $this->assertEquals(2, $crawler->filter('.notice')->count()); + } + + public function noticeProvider() + { + return array( + array('mail-server'), + array('mail-match'), + array('mail-invalid'), + array('bad-password'), + ); + } + + /** + * @dataProvider updateMsgProvider + */ + public function testGetResetMailUpdate($updateMessage) + { + $crawler = $this->client->request('GET', '/account/reset-email/', array( + 'update' => $updateMessage + )); + + $this->assertTrue($this->client->getResponse()->isOk()); + + $this->assertEquals(1, $crawler->filter('.update-msg')->count()); + } + + public function updateMsgProvider() + { + return array( + array('ok'), + array('ko'), + array('mail-send'), + ); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::accountSessionsAccess */ public function testGetAccountSecuritySessions() { @@ -70,7 +271,7 @@ class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::accountAuthorizedApps + * @covers \Alchemy\Phrasea\Controller\Root\Account::accountAuthorizedApps */ public function testGetAccountSecurityApplications() { @@ -82,7 +283,7 @@ class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::resetPassword + * @covers \Alchemy\Phrasea\Controller\Root\Account::resetPassword */ public function testGetResetPassword() { @@ -94,50 +295,209 @@ class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract } /** - * @covers \Alchemy\Phrasea\Controller\Root/Account::renewPassword + * @dataProvider passwordMsgProvider + */ + public function testGetResetPasswordPassError($msg) + { + $crawler = $this->client->request('GET', '/account/reset-password/', array( + 'pass-error' => $msg + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isOk()); + + $this->assertEquals(1, $crawler->filter('.password-msg')->count()); + } + + public function passwordMsgProvider() + { + return array( + array('pass-match'), + array('pass-short'), + array('pass-invalid'), + ); + } + + /** + * @covers \Alchemy\Phrasea\Controller\Root\Account::updateAccount */ public function testUpdateAccount() { - $core = \bootstrap::getCore(); - $appbox = \appbox::get_instance($core); + $evtMngr = \eventsmanager_broker::getInstance($this->app['phraseanet.appbox'], $this->app['phraseanet.core']); + $register = new \appbox_register($this->app['phraseanet.appbox']); + $bases = $notifs = array(); - $bases = array(); - foreach ($appbox->get_databoxes() as $databox) { + foreach ($this->app['phraseanet.appbox']->get_databoxes() as $databox) { foreach ($databox->get_collections() as $collection) { $bases[] = $collection->get_base_id(); } } - if(0 === count($bases)) { + if (0 === count($bases)) { $this->markTestSkipped('No collections'); } + foreach ($evtMngr->list_notifications_available($this->app['phraseanet.core']->getAUthenticatedUser()->get_id()) as $notifications) { + foreach ($notifications as $notification) { + $notifs[] = $notification['id']; + } + } + + array_shift($notifs); + $this->client->request('POST', '/account/', array( - 'demand' => $bases, - 'form_gender' => 'M', - 'form_firstname' => 'gros', - 'form_lastname' => 'minet', - 'form_address' => 'rue du lac', - 'form_zip' => '75005', - 'form_phone' => '+33645787878', - 'form_fax' => '+33145787845', - 'form_function' => 'astronaute', - 'form_company' => 'NASA', - 'form_activity' => 'Space', - 'form_geonameid' => '', - 'form_addrFTP' => '', - 'form_loginFTP' => '', - 'form_pwdFTP' => '', - 'form_destFTP' => '', - 'form_prefixFTPfolder' => '', - 'form_defaultdataFTP' => array('document', 'preview', 'caption'), - 'mail_notifications' => '1' + 'demand' => $bases, + 'form_gender' => 'M', + 'form_firstname' => 'gros', + 'form_lastname' => 'minet', + 'form_address' => 'rue du lac', + 'form_zip' => '75005', + 'form_phone' => '+33645787878', + 'form_fax' => '+33145787845', + 'form_function' => 'astronaute', + 'form_company' => 'NASA', + 'form_activity' => 'Space', + 'form_geonameid' => '', + 'form_addrFTP' => '', + 'form_loginFTP' => '', + 'form_pwdFTP' => '', + 'form_destFTP' => '', + 'form_prefixFTPfolder' => '', + 'notifications' => $notifs, + 'form_defaultdataFTP' => array('document', 'preview', 'caption'), + 'mail_notifications' => '1' )); $response = $this->client->getResponse(); $this->assertTrue($response->isRedirect()); - $this->assertEquals('minet', $core->getAUthenticatedUser()->get_lastname()); + $this->assertEquals('minet', $this->app['phraseanet.core']->getAUthenticatedUser()->get_lastname()); + + $ret = $register->get_collection_awaiting_for_user(self::$user); + + $this->assertEquals(count($ret), count($bases)); } + /** + * @expectedException Symfony\Component\HttpKernel\Exception\HttpException + */ + public function testAUthorizedAppGrantAccessBadRequest() + { + $this->client->request('GET', '/account/security/application/3/grant/'); + } + public function testAUthorizedAppGrantAccessNotSuccessfull() + { + $this->client->request('GET', '/account/security/application/3/grant/', array(), array(), array('HTTP_ACCEPT' => 'application/json', 'HTTP_X-Requested-With' => 'XMLHttpRequest')); + $response = $this->client->getResponse(); + + $this->assertTrue($response->isOk()); + $json = json_decode($response->getContent()); + $this->assertInstanceOf('StdClass', $json); + $this->assertObjectHasAttribute('success', $json); + $this->assertFalse($json->success); + } + + /** + * @dataProvider revokeProvider + */ + public function testAUthorizedAppGrantAccessSuccessfull($revoke, $expected) + { + if (null === self::$authorizedApp) { + $this->markTestSkipped('Application could not be created'); + } + + $this->client->request('GET', '/account/security/application/' . self::$authorizedApp->get_id() . '/grant/', array( + 'revoke' => $revoke + ), array(), array( + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_X-Requested-With' => 'XMLHttpRequest' + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isOk()); + $json = json_decode($response->getContent()); + $this->assertInstanceOf('StdClass', $json); + $this->assertObjectHasAttribute('success', $json); + $this->assertTrue($json->success); + + $account = \API_OAuth2_Account::load_with_user( + $this->app['phraseanet.appbox'] + , self::$authorizedApp + , self::$user + ); + + $this->assertEquals($expected, $account->is_revoked()); + } + + public function revokeProvider() + { + return array( + array('1', true), + array('0', false), + array(null, false), + array('titi', true), + ); + } + + /** + * @dataProvider passwordProvider + */ + public function testPostRenewPasswordBadArguments($oldPassword, $password, $passwordConfirm, $redirect) + { + self::$user->set_password($oldPassword); + + $this->client->request('POST', '/account/forgot-password/', array( + 'form_password' => $password, + 'form_password_confirm' => $passwordConfirm, + 'form_old_password' => $oldPassword + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isRedirect()); + $this->assertEquals($redirect, $response->headers->get('location')); + } + + public function testPostRenewPasswordBadOldPassword() + { + $this->client->request('POST', '/account/forgot-password/', array( + 'form_password' => 'password', + 'form_password_confirm' => 'password', + 'form_old_password' => 'oulala' + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/?notice=pass-ko', $response->headers->get('location')); + } + + public function testPostRenewPassword() + { + $password = \random::generatePassword(); + + self::$user->set_password($password); + + $this->client->request('POST', '/account/forgot-password/', array( + 'form_password' => 'password', + 'form_password_confirm' => 'password', + 'form_old_password' => $password + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/account/?notice=pass-ok', $response->headers->get('location')); + } + + public function passwordProvider() + { + return array( + array(\random::generatePassword(), 'password', 'not_identical_password', '/account/reset-password/?pass-error=pass-match'), + array(\random::generatePassword(), 'min', 'min', '/account/reset-password/?pass-error=pass-short'), + array(\random::generatePassword(), 'invalid password \n', 'invalid password \n', '/account/reset-password/?pass-error=pass-invalid'), + ); + } }