diff --git a/src/IDF/Form/Register.php b/src/IDF/Form/Register.php index 042c1cb..5c28e14 100644 --- a/src/IDF/Form/Register.php +++ b/src/IDF/Form/Register.php @@ -107,5 +107,36 @@ class IDF_Form_Register extends Pluf_Form if (!$this->isValid()) { throw new Exception(__('Cannot save the model from an invalid form.')); } + $user = new Pluf_User(); + $user->first_name = '---'; // with both this set and + // active==false we can find later + // on, all the unconfirmed accounts + // that could be purged. + $user->last_name = $this->cleaned_data['login']; + $user->login = $this->cleaned_data['login']; + $user->email = $this->cleaned_data['email']; + $user->active = false; + $user->create(); + $from_email = Pluf::f('from_email'); + Pluf::loadFunction('Pluf_HTTP_URL_urlForView'); + $cr = new Pluf_Crypt(md5(Pluf::f('secret_key'))); + $encrypted = trim($cr->encrypt($user->email.':'.$user->id), '~'); + $key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted; + $url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::registerConfirmation', array($key), array(), false); + $urlik = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey', array(), array(), false); + $context = new Pluf_Template_Context( + array('key' => $key, + 'url' => $url, + 'urlik' => $urlik, + 'user'=> $user, + ) + ); + $tmpl = new Pluf_Template('register/confirmation-email.txt'); + $text_email = $tmpl->render($context); + $email = new Pluf_Mail($from_email, $user->email, + __('Confirm the creation of your account.')); + $email->addTextMessage($text_email); + $email->sendMail(); + return $user; } } diff --git a/src/IDF/Form/RegisterConfirmation.php b/src/IDF/Form/RegisterConfirmation.php new file mode 100644 index 0000000..ce253d6 --- /dev/null +++ b/src/IDF/Form/RegisterConfirmation.php @@ -0,0 +1,147 @@ +_user = $extra['user']; + + $this->fields['key'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Your confirmation key'), + 'initial' => $extra['key'], + 'widget' => 'Pluf_Form_Widget_HiddenInput', + 'widget_attrs' => array( + 'readonly' => 'readonly', + ), + + )); + $this->fields['first_name'] = new Pluf_Form_Field_Varchar( + array('required' => false, + 'label' => __('First name'), + 'initial' => '', + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + $this->fields['last_name'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Last name'), + 'initial' => '', + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + $this->fields['password'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Your password'), + 'initial' => '', + 'widget' => 'Pluf_Form_Widget_PasswordInput', + 'help_text' => __('Your password must be hard for other people to find it, but easy for you to remember.'), + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + $this->fields['password2'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Confirm your password'), + 'initial' => '', + 'widget' => 'Pluf_Form_Widget_PasswordInput', + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + + + + } + + /** + * Just a simple control. + */ + public function clean_key() + { + $this->cleaned_data['key'] = trim($this->cleaned_data['key']); + $error = __('We are sorry but this confirmation key is not valid. Maybe you should directly copy/paste it from your confirmation email.'); + if (false === ($email_id=IDF_Form_RegisterInputKey::checkKeyHash($this->cleaned_data['key']))) { + throw new Pluf_Form_Invalid($error); + } + $guser = new Pluf_User(); + $sql = new Pluf_SQL('email=%s AND id=%s', $email_id); + $users = $guser->getList(array('filter' => $sql->gen())); + if ($users->count() != 1) { + throw new Pluf_Form_Invalid($error); + } + if ($users[0]->active) { + throw new Pluf_Form_Invalid(__('This account has already been confirmed. Maybe should you try to recover your password using the help link.')); + } + $this->_user_id = $email_id[1]; + return $this->cleaned_data['key']; + } + + /** + * Check the passwords. + */ + public function clean() + { + if ($this->cleaned_data['password'] != $this->cleaned_data['password2']) { + throw new Pluf_Form_Invalid(__('The two passwords must be the same.')); + } + return $this->cleaned_data; + } + + /** + * Save the model in the database. + * + * @param bool Commit in the database or not. If not, the object + * is returned but not saved in the database. + * @return Object Model with data set from the form. + */ + function save($commit=true) + { + if (!$this->isValid()) { + throw new Exception(__('Cannot save an invalid form.')); + } + $this->_user->setFromFormData($this->cleaned_data); + $this->_user->active = true; + $this->_user->administrator = false; + $this->_user->staff = false; + if ($commit) { + $this->_user->update(); + } + return $this->_user; + } +} diff --git a/src/IDF/Form/RegisterInputKey.php b/src/IDF/Form/RegisterInputKey.php new file mode 100644 index 0000000..658291b --- /dev/null +++ b/src/IDF/Form/RegisterInputKey.php @@ -0,0 +1,96 @@ +fields['key'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Your confirmation key'), + 'initial' => '', + 'widget_attrs' => array( + 'size' => 50, + ), + )); + } + + /** + * Validate the key. + */ + public function clean_key() + { + $this->cleaned_data['key'] = trim($this->cleaned_data['key']); + $error = __('We are sorry but this confirmation key is not valid. Maybe you should directly copy/paste it from your confirmation email.'); + if (false === ($email_id=self::checkKeyHash($this->cleaned_data['key']))) { + throw new Pluf_Form_Invalid($error); + } + $guser = new Pluf_User(); + $sql = new Pluf_SQL('email=%s AND id=%s', $email_id); + if ($guser->getCount(array('filter' => $sql->gen())) != 1) { + throw new Pluf_Form_Invalid($error); + } + return $this->cleaned_data['key']; + } + + /** + * Save the model in the database. + * + * @param bool Commit in the database or not. If not, the object + * is returned but not saved in the database. + * @return string Url to redirect to the form. + */ + function save($commit=true) + { + if (!$this->isValid()) { + throw new Exception(__('Cannot save an invalid form.')); + } + return Pluf_HTTP_URL_urlForView('IDF_Views::registerConfirmation', + array($this->cleaned_data['key'])); + } + + /** + * Return false or an array with the email and id. + * + * This is a static function to be reused by other forms. + * + * @param string Confirmation key + * @return mixed Either false or array(email, id) + */ + public static function checkKeyHash($key) + { + $hash = substr($key, 0, 2); + $encrypted = substr($key, 2); + if ($hash != substr(md5(Pluf::f('secret_key').$encrypted), 0, 2)) { + return false; + } + $cr = new Pluf_Crypt(md5(Pluf::f('secret_key'))); + return split(':', $cr->decrypt($encrypted), 2); + } +} diff --git a/src/IDF/Views.php b/src/IDF/Views.php index ab201ac..ab50a8a 100644 --- a/src/IDF/Views.php +++ b/src/IDF/Views.php @@ -82,16 +82,84 @@ class IDF_Views if ($request->method == 'POST') { $form = new IDF_Form_Register($request->POST); if ($form->isValid()) { - $user = $form->save(); - $url = Pluf_HTTP_URL_urlForView('IDF_Views::registerConfirmation'); + $user = $form->save(); // It is sending the confirmation email + $url = Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey'); return new Pluf_HTTP_Response_Redirect($url); } } else { $init = (isset($request->GET['login'])) ? array('initial' => array('login' => $request->GET['login'])) : array(); $form = new IDF_Form_Register(null, $init); } - return Pluf_Shortcuts_RenderToResponse('register.html', + return Pluf_Shortcuts_RenderToResponse('register/index.html', + array('page_title' => $title, + 'form' => $form), + $request); + } + + /** + * Input the registration confirmation key. + * + * Very simple view just to redirect to the register confirmation + * views to input the password. + */ + function registerInputKey($request, $match) + { + $title = __('Confirm Your Account Creation'); + if ($request->method == 'POST') { + $form = new IDF_Form_RegisterInputKey($request->POST); + if ($form->isValid()) { + $url = $form->save(); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_RegisterInputKey(); + } + return Pluf_Shortcuts_RenderToResponse('register/inputkey.html', + array('page_title' => $title, + 'form' => $form), + $request); + } + + /** + * Registration confirmation. + * + * Input first/last name, password and sign in the user. + * + * Maybe in the future send the user to its personal page for + * customization. + */ + function registerConfirmation($request, $match) + { + $title = __('Confirm Your Account Creation'); + $key = $match[1]; + // first "check", full check is done in the form. + $email_id = IDF_Form_RegisterInputKey::checkKeyHash($key); + if (false == $email_id) { + $url = Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey'); + return new Pluf_HTTP_Response_Redirect($url); + } + $user = new Pluf_User($email_id[1]); + $extra = array('key' => $key, + 'user' => $user); + if ($request->method == 'POST') { + $form = new IDF_Form_RegisterConfirmation($request->POST, $extra); + if ($form->isValid()) { + $user = $form->save(); + $request->user = $user; + $request->session->clear(); + $request->session->setData('login_time', gmdate('Y-m-d H:i:s')); + $user->last_login = gmdate('Y-m-d H:i:s'); + $user->update(); + $request->user->setMessage(__('Welcome! You can now participate in the life of your project of choice.')); + $url = Pluf_HTTP_URL_urlForView('IDF_Views::index'); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_RegisterConfirmation(null, $extra); + } + return Pluf_Shortcuts_RenderToResponse('register/confirmation.html', array('page_title' => $title, + 'new_user' => $user, 'form' => $form), $request); } diff --git a/src/IDF/conf/views.php b/src/IDF/conf/views.php index ef8c433..ff1dccb 100644 --- a/src/IDF/conf/views.php +++ b/src/IDF/conf/views.php @@ -42,6 +42,18 @@ $ctl[] = array('regex' => '#^/register/$#', 'model' => 'IDF_Views', 'method' => 'register'); +$ctl[] = array('regex' => '#^/register/k/(.*)/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views', + 'method' => 'registerConfirmation'); + +$ctl[] = array('regex' => '#^/register/ik/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views', + 'method' => 'registerInputKey'); + $ctl[] = array('regex' => '#^/logout/$#', 'base' => $base, 'priority' => 4, diff --git a/src/IDF/templates/register.html b/src/IDF/templates/register.html deleted file mode 100644 index ca3c3c6..0000000 --- a/src/IDF/templates/register.html +++ /dev/null @@ -1,57 +0,0 @@ -{extends "base-simple.html"} -{block body} -{if $form.errors} -
-{/if} - - -{/block} -{block context} -{trans 'Be sure to provide a valid email address, as we are sending a validation link by email.'}
- -{trans 'Did you know?'}
-{aurl 'url', 'IDF_Views::faq'}
-{blocktrans}With your account, you will able to participate in the life of all the projects hosted here. Participating in a software project must be fun, so if you have troubles, you can let us know about your issues at anytime!{/blocktrans}
-
{trans 'This is the last step, but just be sure to have the cookies enabled to log in afterwards.'}
+{trans 'Be sure to provide a valid email address, as we are sending a validation link by email.'}
+ +{trans 'Did you know?'}
+{aurl 'url', 'IDF_Views::faq'}
+{blocktrans}With your account, you will able to participate in the life of all the projects hosted here. Participating in a software project must be fun, so if you have troubles, you can let us know about your issues at anytime!{/blocktrans}
+
{trans 'Use your email software to read your emails and open your confirmation email. Either click directly on the confirmation link or copy/paste the confirmation key in the box and submit the form.'}
+{trans 'Just after providing the confirmation key, you will be able to set your password and start using this website fully.'}
+