diff --git a/src/IDF/Form/UserAccount.php b/src/IDF/Form/UserAccount.php index 806e625..e0a8cda 100644 --- a/src/IDF/Form/UserAccount.php +++ b/src/IDF/Form/UserAccount.php @@ -21,6 +21,8 @@ # # ***** END LICENSE BLOCK ***** */ +Pluf::loadFunction('Pluf_HTTP_URL_urlForView'); + /** * Allow a user to update its details. */ @@ -50,6 +52,13 @@ class IDF_Form_UserAccount extends Pluf_Form ), )); + $this->fields['email'] = new Pluf_Form_Field_Email( + array('required' => true, + 'label' => __('Your mail'), + 'initial' => $this->user->email, + 'help_text' => __('If you change your email address, an email will be sent to the new address to confirm it.'), + )); + $this->fields['language'] = new Pluf_Form_Field_Varchar( array('required' => true, 'label' => __('Language'), @@ -116,6 +125,31 @@ class IDF_Form_UserAccount extends Pluf_Form } else { $update_pass = true; } + $old_email = $this->user->email; + $new_email = $this->cleaned_data['email']; + unset($this->cleaned_data['email']); + if ($old_email != $new_email) { + $cr = new Pluf_Crypt(md5(Pluf::f('secret_key'))); + $encrypted = trim($cr->encrypt($new_email.':'.$this->user->id.':'.time()), '~'); + $key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted; + $url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailDo', array($key), array(), false); + $urlik = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey', array(), array(), false); + $context = new Pluf_Template_Context( + array('key' => Pluf_Template::markSafe($key), + 'url' => Pluf_Template::markSafe($url), + 'urlik' => Pluf_Template::markSafe($urlik), + 'email' => $new_email, + 'user'=> $this->user, + ) + ); + $tmpl = new Pluf_Template('idf/user/changeemail-email.txt'); + $text_email = $tmpl->render($context); + $email = new Pluf_Mail(Pluf::f('from_email'), $new_email, + __('Confirm your new email address.')); + $email->addTextMessage($text_email); + $email->sendMail(); + $this->user->setMessage(sprintf(__('A validation email has been sent to "%s" to validate the email address change.'), Pluf_esc($new_email))); + } $this->user->setFromFormData($this->cleaned_data); // Get keys $keys = $this->user->get_idf_key_list(); @@ -181,6 +215,18 @@ class IDF_Form_UserAccount extends Pluf_Form return $first_name; } + function clean_email() + { + $this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email'])); + $guser = new Pluf_User(); + $sql = new Pluf_SQL('email=%s AND id!=%s', + array($this->cleaned_data['email'], $this->user->id)); + if ($guser->getCount(array('filter' => $sql->gen())) > 0) { + throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email'])); + } + return $this->cleaned_data['email']; + } + /** * Check to see if the 2 passwords are the same. */ diff --git a/src/IDF/Form/UserChangeEmail.php b/src/IDF/Form/UserChangeEmail.php new file mode 100644 index 0000000..ddb7ac9 --- /dev/null +++ b/src/IDF/Form/UserChangeEmail.php @@ -0,0 +1,84 @@ +fields['key'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Your verification key'), + 'initial' => '', + 'widget_attrs' => array( + 'size' => 50, + ), + )); + } + + function clean_key() + { + self::validateKey($this->cleaned_data['key']); + return $this->cleaned_data['key']; + } + + /** + * Validate the key. + * + * Throw a Pluf_Form_Invalid exception if the key is not valid. + * + * @param string Key + * @return array array($new_email, $user_id, time()) + */ + public static function validateKey($key) + { + $hash = substr($key, 0, 2); + $encrypted = substr($key, 2); + if ($hash != substr(md5(Pluf::f('secret_key').$encrypted), 0, 2)) { + throw new Pluf_Form_Invalid(__('The validation key is not valid. Please copy/paste it from your confirmation email.')); + } + $cr = new Pluf_Crypt(md5(Pluf::f('secret_key'))); + return split(':', $cr->decrypt($encrypted), 3); + + } + + /** + * 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 the model from an invalid form.')); + } + return Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailDo', array($this->cleaned_data['key'])); + } +} diff --git a/src/IDF/Views/User.php b/src/IDF/Views/User.php index 1cf8725..75c130d 100644 --- a/src/IDF/Views/User.php +++ b/src/IDF/Views/User.php @@ -96,8 +96,6 @@ class IDF_Views_User 'issues' => $pag, ), $request); - - } /** @@ -140,6 +138,55 @@ class IDF_Views_User } /** + * Enter the key to change an email address. + * + * This is redirecting to changeEmailDo + */ + public $changeEmailInputKey_precond = array('Pluf_Precondition::loginRequired'); + public function changeEmailInputKey($request, $match) + { + if ($request->method == 'POST') { + $form = new IDF_Form_UserChangeEmail($request->POST); + if ($form->isValid()) { + $url = $form->save(); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_UserChangeEmail(); + } + return Pluf_Shortcuts_RenderToResponse('idf/user/changeemail.html', + array('page_title' => __('Confirm The Email Change'), + 'form' => $form), + $request); + + } + + /** + * Really change the email address. + */ + public $changeEmailDo_precond = array('Pluf_Precondition::loginRequired'); + public function changeEmailDo($request, $match) + { + $key = $match[1]; + $url = Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey'); + try { + list($email, $id, $time) = IDF_Form_UserChangeEmail::validateKey($key); + } catch (Pluf_Form_Invalid $e) { + return new Pluf_HTTP_Response_Redirect($url); + } + if ($id != $request->user->id) { + return new Pluf_HTTP_Response_Redirect($url); + } + // Now we have a change link coming from the right user. + $request->user->email = $email; + $request->user->update(); + $request->user->setMessage(sprintf(__('Your new email address "%s" has been validated. Thank you!'), Pluf_esc($email))); + $url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount'); + return new Pluf_HTTP_Response_Redirect($url); + } + + + /** * Public profile of a user. */ public function view($request, $match) diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php index 07e8bce..57805cb 100644 --- a/src/IDF/conf/urls.php +++ b/src/IDF/conf/urls.php @@ -473,6 +473,19 @@ $ctl[] = array('regex' => '#^/password/k/(.*)/$#', 'model' => 'IDF_Views', 'method' => 'passwordRecovery'); +$ctl[] = array('regex' => '#^/preferences/email/ik/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views_User', + 'method' => 'changeEmailInputKey'); + +$ctl[] = array('regex' => '#^/preferences/email/ak/(.*)/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views_User', + 'method' => 'changeEmailDo'); + + return $ctl; diff --git a/src/IDF/templates/idf/user/changeemail-email.txt b/src/IDF/templates/idf/user/changeemail-email.txt new file mode 100644 index 0000000..8e9c5a9 --- /dev/null +++ b/src/IDF/templates/idf/user/changeemail-email.txt @@ -0,0 +1,22 @@ +{blocktrans}Hello {$user}, + +To confirm that you want {$email} +to be your new email address, just follow this link: + +{$url} + +Alternatively, go to this page: + +{$urlik} + +and provide the following verification key: + +{$key} + +If you do not want to change your email address, +just ignore this message. + +Yours faithfully, +The development team. +{/blocktrans} + diff --git a/src/IDF/templates/idf/user/changeemail.html b/src/IDF/templates/idf/user/changeemail.html new file mode 100644 index 0000000..6a29b3d --- /dev/null +++ b/src/IDF/templates/idf/user/changeemail.html @@ -0,0 +1,39 @@ +{extends "idf/base-simple.html"} +{block body} +{if $form.errors} +
+{/if} + + +{/block} +{block context} +{trans 'Use your email software to read your emails and open your verification email. Either click directly on the verification link or copy/paste the verification key in the box and submit the form.'}
+