diff --git a/lib/Alchemy/Phrasea/Form/Constraint/NewEmail.php b/lib/Alchemy/Phrasea/Form/Constraint/NewEmail.php new file mode 100644 index 0000000000..821f749ffc --- /dev/null +++ b/lib/Alchemy/Phrasea/Form/Constraint/NewEmail.php @@ -0,0 +1,34 @@ +message = _('This email is already bound to an account'); + $this->app = $app; + parent::__construct(); + } + + public function isAlreadyRegistered($email) + { + $ret = (Boolean) \User_Adapter::get_usr_id_from_email($this->app, $email); + + return $ret; + } +} diff --git a/lib/Alchemy/Phrasea/Form/Constraint/NewEmailValidator.php b/lib/Alchemy/Phrasea/Form/Constraint/NewEmailValidator.php new file mode 100644 index 0000000000..ed1b1afe79 --- /dev/null +++ b/lib/Alchemy/Phrasea/Form/Constraint/NewEmailValidator.php @@ -0,0 +1,28 @@ +isAlreadyRegistered($value)) { + $this->context->addViolation(_('There is already an account bound to this email address')); + } + } +} diff --git a/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php b/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php new file mode 100644 index 0000000000..26b51cf77c --- /dev/null +++ b/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php @@ -0,0 +1,40 @@ +message = _('The token provided is not valid anymore'); + $this->app = $app; + $this->random = $random; + parent::__construct(); + } + + public function isValid($token) + { + try { + $datas = $this->random->helloToken($this->app, $token); + } catch (\Exception_NotFound $e) { + return false; + } + + return \random::TYPE_PASSWORD === $datas['type']; + } +} diff --git a/lib/Alchemy/Phrasea/Form/Constraint/PasswordTokenValidator.php b/lib/Alchemy/Phrasea/Form/Constraint/PasswordTokenValidator.php new file mode 100644 index 0000000000..c41e2d1a78 --- /dev/null +++ b/lib/Alchemy/Phrasea/Form/Constraint/PasswordTokenValidator.php @@ -0,0 +1,28 @@ +isValid($value)) { + $this->context->addViolation('The token provided is not valid anymore'); + } + } +} diff --git a/lib/Alchemy/Phrasea/Form/Login/PhraseaRecoverPasswordForm.php b/lib/Alchemy/Phrasea/Form/Login/PhraseaRecoverPasswordForm.php new file mode 100644 index 0000000000..918245073d --- /dev/null +++ b/lib/Alchemy/Phrasea/Form/Login/PhraseaRecoverPasswordForm.php @@ -0,0 +1,64 @@ +app = $app; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('token', 'hidden', array( + 'required' => true, + 'constraints' => array( + new PasswordToken($this->app, $this->app['tokens']) + ) + )); + + $builder->add('password', 'password', array( + 'label' => _('New password'), + 'required' => true, + 'constraints' => array( + new Assert\NotBlank(), + new Assert\Length(array('min' => 5)), + ) + )); + + $builder->add('passwordConfirm', 'password', array( + 'label' => _('New password (confirmation)'), + 'required' => false, + 'constraints' => array( + new Assert\NotBlank(), + new Assert\Length(array('min' => 5)), + ) + )); + } + + public function getName() + { + return null; + } +} diff --git a/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php b/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php index ceef1df808..fb73cd2e13 100644 --- a/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php +++ b/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Form\Login; +use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Utilities\String\Camelizer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -23,8 +24,9 @@ class PhraseaRegisterForm extends AbstractType private $params; private $camelizer; - public function __construct(array $available, array $params = array(), Camelizer $camelizer = null) + public function __construct(Application $app, array $available, array $params = array(), Camelizer $camelizer = null) { + $this->app = $app; $this->available = $available; $this->params = $params; $this->camelizer = $camelizer ?: new Camelizer(); @@ -37,6 +39,8 @@ class PhraseaRegisterForm extends AbstractType 'required' => true, 'constraints' => array( new Assert\NotBlank(), + new Assert\Email(), + new \Alchemy\Phrasea\Form\Constraint\NewEmail($this->app), ), )); @@ -44,7 +48,8 @@ class PhraseaRegisterForm extends AbstractType 'label' => _('Password'), 'required' => true, 'constraints' => array( - new Assert\NotBlank() + new Assert\NotBlank(), + new Assert\Length(array('min' => 5)), ) )); @@ -52,13 +57,40 @@ class PhraseaRegisterForm extends AbstractType 'label' => _('Password (confirmation)'), 'required' => false, 'constraints' => array( - new Assert\NotBlank() + new Assert\NotBlank(), + new Assert\Length(array('min' => 5)), ) )); $builder->add('accept-tou', 'checkbox', array( 'mapped' => false, - 'required' => false + "constraints" => new Assert\True(array( + "message" => "Please accept the Terms and conditions in order to register") + ), + )); + + require_once($this->app['phraseanet.registry']->get('GV_RootPath') . 'lib/classes/deprecated/inscript.api.php'); + $baseIds = array(); + + foreach (\giveMeBases($this->app) as $sbas_id => $baseInsc) { + if (($baseInsc['CollsCGU'] || $baseInsc['Colls']) && $baseInsc['inscript']) { + if ($baseInsc['Colls']) { + foreach($baseInsc['Colls'] as $collId => $collName) { + $baseIds[\phrasea::baseFromColl($sbas_id, $collId, $this->app)] = $collName; + } + } + if ($baseInsc['CollsCGU']) { + foreach($baseInsc['CollsCGU'] as $collId => $collName) { + $baseIds[\phrasea::baseFromColl($sbas_id, $collId, $this->app)] = $collName; + } + } + } + } + + $builder->add('collections', 'choice', array( + 'choices' => $baseIds, + 'multiple' => true, + 'expanded' => true, )); foreach ($this->params as $param) { diff --git a/lib/Alchemy/Phrasea/Form/Login/PhraseaRenewPasswordForm.php b/lib/Alchemy/Phrasea/Form/Login/PhraseaRenewPasswordForm.php index 4d5ee982e8..fffdfb0887 100644 --- a/lib/Alchemy/Phrasea/Form/Login/PhraseaRenewPasswordForm.php +++ b/lib/Alchemy/Phrasea/Form/Login/PhraseaRenewPasswordForm.php @@ -15,6 +15,9 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints as Assert; +/** + * Form used to renew the password once the user is logged, in its account. + */ class PhraseaRenewPasswordForm extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) @@ -31,7 +34,8 @@ class PhraseaRenewPasswordForm extends AbstractType 'label' => _('New password'), 'required' => true, 'constraints' => array( - new Assert\NotBlank() + new Assert\NotBlank(), + new Assert\Length(array('min' => 5)), ) )); @@ -39,7 +43,8 @@ class PhraseaRenewPasswordForm extends AbstractType 'label' => _('New password (confirmation)'), 'required' => false, 'constraints' => array( - new Assert\NotBlank() + new Assert\NotBlank(), + new Assert\Length(array('min' => 5)), ) )); } diff --git a/lib/Alchemy/Phrasea/Form/Type/GeonameType.php b/lib/Alchemy/Phrasea/Form/Type/GeonameType.php index ce03da8169..b8184af259 100644 --- a/lib/Alchemy/Phrasea/Form/Type/GeonameType.php +++ b/lib/Alchemy/Phrasea/Form/Type/GeonameType.php @@ -13,7 +13,6 @@ namespace Alchemy\Phrasea\Form\Type; use Symfony\Component\Form\AbstractType; -// write tests class GeonameType extends AbstractType { public function getParent() diff --git a/tests/Alchemy/Tests/Phrasea/Form/Constraint/NewEmailTest.php b/tests/Alchemy/Tests/Phrasea/Form/Constraint/NewEmailTest.php new file mode 100644 index 0000000000..e721a868aa --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/Constraint/NewEmailTest.php @@ -0,0 +1,32 @@ +assertFalse($constraint->isAlreadyRegistered('nonehere')); + } + + public function testARegisteredAddressIsAlreadyRegistered() + { + $constraint = new NewEmail(self::$DI['app']); + $this->assertTrue($constraint->isAlreadyRegistered(self::$DI['user']->get_email())); + } + + public function testNullIsNotAlreadyRegistered() + { + $constraint = new NewEmail(self::$DI['app']); + $this->assertFalse($constraint->isAlreadyRegistered('null')); + } + + public function testBlankIsNotAlreadyRegistered() + { + $constraint = new NewEmail(self::$DI['app']); + $this->assertFalse($constraint->isAlreadyRegistered('')); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/Constraint/NewEmailValidatorTest.php b/tests/Alchemy/Tests/Phrasea/Form/Constraint/NewEmailValidatorTest.php new file mode 100644 index 0000000000..4a12e00b39 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/Constraint/NewEmailValidatorTest.php @@ -0,0 +1,53 @@ +getMock('Symfony\Component\Validator\ExecutionContextInterface'); + $builder = $context + ->expects($this->exactly($alreadyRegistered ? 1 : 0)) + ->method('addViolation'); + + if ($alreadyRegistered) { + $builder->with($this->isType('string')); + } + + $validator = new NewEmailValidator(); + $validator->initialize($context); + + $constraint = $this->getConstraint(); + $constraint + ->expects($this->once()) + ->method('isAlreadyRegistered') + ->with($value) + ->will($this->returnValue($alreadyRegistered)); + + $validator->validate($value, $constraint); + } + + public function provideValidationData() + { + return array( + array('romain@neutron.io', true), + array('romain@neutron.io', false), + array('', false), + array(null, false), + ); + } + + private function getConstraint() + { + return $this + ->getMockBuilder('Alchemy\Phrasea\Form\Constraint\NewEmail') + ->disableOriginalConstructor() + ->getMock(); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php b/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php new file mode 100644 index 0000000000..65102f90ca --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php @@ -0,0 +1,48 @@ +getMockBuilder('random') + ->disableOriginalConstructor() + ->setMethods(array('helloToken')) + ->getMock(); + + $token = \random::generatePassword(); + + $random + ->expects($this->once()) + ->method('helloToken') + ->with(self::$DI['app'], $token) + ->will($this->throwException(new \Exception_NotFound('Token not found'))); + + $constraint = new PasswordToken(self::$DI['app'], $random); + $this->assertFalse($constraint->isValid($token)); + } + + public function testValidTokenIsValid() + { + $random = $this + ->getMockBuilder('random') + ->disableOriginalConstructor() + ->setMethods(array('helloToken')) + ->getMock(); + + $token = \random::generatePassword(); + + $random + ->expects($this->once()) + ->method('helloToken') + ->with(self::$DI['app'], $token) + ->will($this->returnValue(array('usr_id' => mt_rand(), 'type' => \random::TYPE_PASSWORD))); + + $constraint = new PasswordToken(self::$DI['app'], $random); + $this->assertTrue($constraint->isValid($token)); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenValidatorTest.php b/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenValidatorTest.php new file mode 100644 index 0000000000..a378c25759 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenValidatorTest.php @@ -0,0 +1,51 @@ +getMock('Symfony\Component\Validator\ExecutionContextInterface'); + $builder = $context + ->expects($this->exactly($isValid ? 1 : 0)) + ->method('addViolation'); + + if ($isValid) { + $builder->with($this->isType('string')); + } + + $validator = new PasswordTokenValidator(); + $validator->initialize($context); + + $constraint = $this->getConstraint(); + $constraint + ->expects($this->once()) + ->method('isValid') + ->with($value) + ->will($this->returnValue($isValid)); + + $validator->validate($value, $constraint); + } + + public function provideValidationData() + { + return array( + array(\random::generatePassword(), true), + array(\random::generatePassword(), false), + ); + } + + private function getConstraint() + { + return $this + ->getMockBuilder('Alchemy\Phrasea\Form\Constraint\PasswordToken') + ->disableOriginalConstructor() + ->getMock(); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/FormTestCase.php b/tests/Alchemy/Tests/Phrasea/Form/FormTestCase.php new file mode 100644 index 0000000000..62d52488c0 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/FormTestCase.php @@ -0,0 +1,26 @@ +getForm(); + + $builder = $this + ->getMockBuilder('Symfony\Component\Form\FormBuilder') + ->disableOriginalConstructor() + ->getMock(); + + $form->buildForm($builder, array('disabled' => false)); + } + + public function testGetName() + { + $form = $this->getForm(); + $this->assertNull($form->getName()); + } + + abstract protected function getForm(); +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/Login/PhraseaAuthenticationFormTest.php b/tests/Alchemy/Tests/Phrasea/Form/Login/PhraseaAuthenticationFormTest.php new file mode 100644 index 0000000000..bc5f77ec6c --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/Login/PhraseaAuthenticationFormTest.php @@ -0,0 +1,14 @@ + array( + 'type' => 'text', + 'label' => 'Yollah !', + ) + ); + $params = array( + array( + 'name' => 'parameter', + 'required' => true + ) + ); + + return new PhraseaRegisterForm(self::$DI['app'], $available, $params, new \Alchemy\Phrasea\Utilities\String\Camelizer()); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/Login/PhraseaRenewPasswordFormTest.php b/tests/Alchemy/Tests/Phrasea/Form/Login/PhraseaRenewPasswordFormTest.php new file mode 100644 index 0000000000..79b84bce51 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Form/Login/PhraseaRenewPasswordFormTest.php @@ -0,0 +1,14 @@ +assertEquals('text', $geoname->getParent()); + } + + public function testGetName() + { + $geoname = new GeonameType(); + $this->assertEquals('geoname', $geoname->getName()); + } +}