From 618b8b290657306db56d09db8031170493896e9b Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Thu, 16 Mar 2017 09:46:30 +0100 Subject: [PATCH 01/10] Optimize actionDelete() in SettingsController --- controllers/SettingsController.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/controllers/SettingsController.php b/controllers/SettingsController.php index ded1feb43..233636d33 100644 --- a/controllers/SettingsController.php +++ b/controllers/SettingsController.php @@ -274,7 +274,7 @@ public function actionDisconnect($id) public function actionDelete() { if (!$this->module->enableAccountDelete) { - throw new NotFoundHttpException(\Yii::t('user', 'Not found')); + throw new NotFoundHttpException(\Yii::t('user', 'Account deletion is deactivated')); } /** @var User $user */ @@ -284,10 +284,13 @@ public function actionDelete() \Yii::$app->user->logout(); $this->trigger(self::EVENT_BEFORE_DELETE, $event); - $user->delete(); + $success = $user->delete(); $this->trigger(self::EVENT_AFTER_DELETE, $event); - \Yii::$app->session->setFlash('info', \Yii::t('user', 'Your account has been completely deleted')); + if($success) + \Yii::$app->session->setFlash('info', \Yii::t('user', 'Your account has been completely deleted')); + else + \Yii::$app->session->setFlash('danger', \Yii::t('user', 'Your account could not be deleted')); return $this->goHome(); } From 94f2b629c0b66158060685f1b2c6c016c9f1ee2d Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Thu, 16 Mar 2017 09:47:27 +0100 Subject: [PATCH 02/10] add german translations regarding account deletion --- messages/de/user.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/messages/de/user.php b/messages/de/user.php index 8875e24d2..7ac183e96 100644 --- a/messages/de/user.php +++ b/messages/de/user.php @@ -19,6 +19,7 @@ */ return [ 'Are you sure?' => 'Sind Sie sicher?', + 'Are you sure? There is no going back' => 'Sind Sie wirklich Sicher? Ihr Konto wird permanent entfernt', 'A confirmation message has been sent to your new email address' => 'Eine Aktivierungsnachricht wurde an ihre E-Mail Adresse versandt', 'A message has been sent to your email address. It contains a confirmation link that you must click to complete registration.' => 'Eine Nachricht wurde an ihre E-Mail Adresse versandt. Diese enthält einen Aktivierungslink, den Sie besuchen müssen, um die Registrierung fortzusetzen.', 'A message has been sent to your email address. It contains a password that we generated for you.' => 'Eine Nachricht wurde an ihre E-Mail Adresse versandt. Diese enthält ein Passwort, das für Sie generiert wurde.', @@ -27,6 +28,7 @@ 'A new confirmation link has been sent' => 'Ein neuer Bestätigungs-Link wurde versendet.', 'Account' => 'Konto', 'Account confirmation' => 'Kontobestätigung', + 'Account deletion is deactivated' => 'Konto-Löschung ist deaktiviert', 'Account details' => 'Kontodetails', 'Account details have been updated' => 'Kontodetails wurden gespeichert', 'Account settings' => 'Kontoeinstellungen', @@ -47,6 +49,7 @@ 'Credentials will be sent to the user by email' => 'Zugangsdaten werden dem Benutzer per E-Mail gesendet', 'Delete' => 'Löschen', 'Don\'t have an account? Sign up!' => 'Noch kein Konto? Jetzt registrieren!', + 'Delete account' => 'Konto löschen', 'In order to finish your registration, we need you to enter your email address' => 'Um ihre Registrierung abzuschliessen, müssen Sie ihre E-Mail Adresse angeben', 'Invalid or expired link' => 'Falscher oder abgelaufener Link', 'New email' => 'Neue E-Mail Adresse', @@ -175,6 +178,7 @@ 'In order to complete your registration, please click the link below' => 'Um die Registrierung abzuschließen, klicken Sie bitte auf den folgenden Link', 'In order to complete your request, please click the link below' => 'Um die Anfrage abzuschließen, klicken Sie bitte auf den folgenden Link', 'Information' => 'Information', + 'It will be deleted forever' => 'Es wird für immer gelöscht', 'Impersonate user is disabled in the application configuration' => 'Das wechseln zu anderen Nutzern wurde deaktiviert', 'Invalid login or password' => 'Benutzername oder Passwort ungültig', 'Joined on {0, date}' => 'Registriert am d. {0, date}', @@ -191,11 +195,13 @@ 'Profile' => 'Profil', 'Profile settings' => 'Profil Einstellungen', 'Recover your password' => 'Passwort wiederherstellen', + 'Please be certain' => 'Seien Sie sich sicher', 'Registration ip' => 'Registrierungs-IP', 'Registration time' => 'Registrierungszeit', 'Remember me next time' => 'Anmeldung für das nächste Mal merken', 'Request new confirmation message' => 'Neue Bestätigungsmail anfordern', 'Reset your password' => 'Passwort zurücksetzen', + 'Once you delete your account, there is no going back' => 'Wenn Sie ihr Konto löschen, gibt es kein Zurück', 'Never' => 'Nie', 'Last login' => 'Letzte Anmeldung', 'Save' => 'Speichern', @@ -222,6 +228,7 @@ 'You need to confirm your email address' => 'Sie müssen Ihre Email-Adresse bestätigen.', 'Your account has been blocked' => 'Ihr Zugang wurde gesperrt', 'Your account has been created' => 'Ihr Zugang wurde erstellt', + 'Your account has been completely deleted' => 'Ihr Konto wurde komplett gelöscht', 'Your account on {0} has a new password' => 'Ihr Konto auf {0} hat ein neues Passwort', 'Your password on {0} has been changed' => 'Ihr Passwort auf {0} wurde verändert', '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd MMMM, YYYY HH:mm}', From bb12d9af628683d24c2fa330aad2c02c1ce3b731 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Thu, 16 Mar 2017 09:49:46 +0100 Subject: [PATCH 03/10] optimize redirection when deletion fails --- controllers/SettingsController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/controllers/SettingsController.php b/controllers/SettingsController.php index 233636d33..1d7e2dfea 100644 --- a/controllers/SettingsController.php +++ b/controllers/SettingsController.php @@ -287,10 +287,14 @@ public function actionDelete() $success = $user->delete(); $this->trigger(self::EVENT_AFTER_DELETE, $event); - if($success) + + if ($success) { \Yii::$app->session->setFlash('info', \Yii::t('user', 'Your account has been completely deleted')); - else + return $this->goHome(); + } else { \Yii::$app->session->setFlash('danger', \Yii::t('user', 'Your account could not be deleted')); + return $this->goBack(); + } return $this->goHome(); } From cb8db26c93492f61ca6cff42933401c501c1c297 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Tue, 10 Jan 2017 12:46:28 +0100 Subject: [PATCH 04/10] Feature: ask for password confirmation on password change request since passwords are entered blindly --- messages/de/user.php | 1 + models/RecoveryForm.php | 6 ++++++ models/SettingsForm.php | 13 +++++++++---- views/recovery/reset.php | 2 ++ views/settings/account.php | 2 ++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/messages/de/user.php b/messages/de/user.php index 7ac183e96..63c74b35b 100644 --- a/messages/de/user.php +++ b/messages/de/user.php @@ -54,6 +54,7 @@ 'Invalid or expired link' => 'Falscher oder abgelaufener Link', 'New email' => 'Neue E-Mail Adresse', 'New password' => 'Neues Passwort', + 'New password confirmation' => 'Neues Passwort Bestätigung', 'New permission' => 'Neue Berechtigung', 'New role' => 'Neue Rolle', 'New user' => 'Neuer Benutzer', diff --git a/models/RecoveryForm.php b/models/RecoveryForm.php index f5a1b3b38..872357d28 100644 --- a/models/RecoveryForm.php +++ b/models/RecoveryForm.php @@ -35,6 +35,11 @@ class RecoveryForm extends Model */ public $password; + /** + * @var string + */ + public $password_confirmation; + /** * @var Mailer */ @@ -89,6 +94,7 @@ public function rules() 'emailRequired' => ['email', 'required'], 'emailPattern' => ['email', 'email'], 'passwordRequired' => ['password', 'required'], + 'newPasswordConfirmation' => ['password_confirmation', 'compare', 'compareAttribute' => 'password'], 'passwordLength' => ['password', 'string', 'max' => 72, 'min' => 6], ]; } diff --git a/models/SettingsForm.php b/models/SettingsForm.php index e76f4b961..9f5af861b 100644 --- a/models/SettingsForm.php +++ b/models/SettingsForm.php @@ -38,6 +38,9 @@ class SettingsForm extends Model /** @var string */ public $new_password; + /** @var string */ + public $new_password_confirmation; + /** @var string */ public $current_password; @@ -83,6 +86,7 @@ public function rules() return $this->user->$attribute != $model->$attribute; }, 'targetClass' => $this->module->modelMap['User']], 'newPasswordLength' => ['new_password', 'string', 'max' => 72, 'min' => 6], + 'newPasswordConfirmation' => ['new_password_confirmation', 'compare', 'compareAttribute' => 'new_password'], 'currentPasswordRequired' => ['current_password', 'required'], 'currentPasswordValidate' => ['current_password', function ($attr) { if (!Password::validate($this->$attr, $this->user->password_hash)) { @@ -96,10 +100,11 @@ public function rules() public function attributeLabels() { return [ - 'email' => Yii::t('user', 'Email'), - 'username' => Yii::t('user', 'Username'), - 'new_password' => Yii::t('user', 'New password'), - 'current_password' => Yii::t('user', 'Current password'), + 'email' => Yii::t('user', 'Email'), + 'username' => Yii::t('user', 'Username'), + 'new_password' => Yii::t('user', 'New password'), + 'new_password_confirmation' => Yii::t('user', 'New password confirmation'), + 'current_password' => Yii::t('user', 'Current password'), ]; } diff --git a/views/recovery/reset.php b/views/recovery/reset.php index 041ba79b2..d1ce70b3b 100644 --- a/views/recovery/reset.php +++ b/views/recovery/reset.php @@ -36,6 +36,8 @@ field($model, 'password')->passwordInput() ?> + field($model, 'password_confirmation')->passwordInput() ?> + 'btn btn-success btn-block']) ?>
diff --git a/views/settings/account.php b/views/settings/account.php index dbee38d2b..1f4752524 100644 --- a/views/settings/account.php +++ b/views/settings/account.php @@ -51,6 +51,8 @@ field($model, 'new_password')->passwordInput() ?> + field($model, 'new_password_confirmation')->passwordInput() ?> +
field($model, 'current_password')->passwordInput() ?> From 799ad57bfbbf3a2009d47eb180e15538ee6d6d9c Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Tue, 10 Jan 2017 12:50:38 +0100 Subject: [PATCH 05/10] Ask for confirmation also on registration --- messages/de/user.php | 1 + models/RegistrationForm.php | 6 ++++-- views/registration/register.php | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/messages/de/user.php b/messages/de/user.php index 63c74b35b..16c9a7673 100644 --- a/messages/de/user.php +++ b/messages/de/user.php @@ -190,6 +190,7 @@ 'Name' => 'Name', 'Networks' => 'Netzwerke', 'Password' => 'Passwort', + 'Password confirmation' => 'Passwort Bestätigung', 'Password has been changed' => 'Passwort wurde geändert', 'Please click the link below to complete your password reset' => 'Bitte überprüfen Sie Ihre E-Mail und klicken Sie auf den Bestätigungslink um Ihren Passwort-Reset abzuschließen', 'Please fix following errors:' => 'Bitte beheben Sie folgende Fehler:', diff --git a/models/RegistrationForm.php b/models/RegistrationForm.php index e7bba8935..821bc7016 100644 --- a/models/RegistrationForm.php +++ b/models/RegistrationForm.php @@ -68,8 +68,9 @@ public function rules() 'message' => Yii::t('user', 'This email address has already been taken') ], // password rules - 'passwordRequired' => ['password', 'required', 'skipOnEmpty' => $this->module->enableGeneratingPassword], - 'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72], + 'passwordRequired' => ['password', 'required', 'skipOnEmpty' => $this->module->enableGeneratingPassword], + 'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72], + 'passwordConfirmation' => ['password_confirmation', 'compare', 'compareAttribute' => 'password'], ]; } @@ -82,6 +83,7 @@ public function attributeLabels() 'email' => Yii::t('user', 'Email'), 'username' => Yii::t('user', 'Username'), 'password' => Yii::t('user', 'Password'), + 'password_confirmation' => Yii::t('user', 'Password confirmation'), ]; } diff --git a/views/registration/register.php b/views/registration/register.php index 97e7b494c..9d1d9b541 100644 --- a/views/registration/register.php +++ b/views/registration/register.php @@ -40,6 +40,8 @@ enableGeneratingPassword == false): ?> field($model, 'password')->passwordInput() ?> + + field($model, 'password_confirmation')->passwordInput() ?> 'btn btn-success btn-block']) ?> From 36256714ce1efe66508b1ca22331dca00e27ea59 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Tue, 10 Jan 2017 13:14:30 +0100 Subject: [PATCH 06/10] Adjust tests --- tests/_pages/RegistrationPage.php | 1 + tests/functional/RecoveryCept.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/_pages/RegistrationPage.php b/tests/_pages/RegistrationPage.php index 0387d7ff6..1dec82972 100644 --- a/tests/_pages/RegistrationPage.php +++ b/tests/_pages/RegistrationPage.php @@ -25,6 +25,7 @@ public function register($email, $username = null, $password = null) $this->actor->fillField('#register-form-username', $username); if ($password !== null) { $this->actor->fillField('#register-form-password', $password); + $this->actor->fillField('#register-form-password-confirmation', $password); } $this->actor->click('Sign up'); } diff --git a/tests/functional/RecoveryCept.php b/tests/functional/RecoveryCept.php index 6e8e7cba7..324ce5bf9 100644 --- a/tests/functional/RecoveryCept.php +++ b/tests/functional/RecoveryCept.php @@ -46,6 +46,7 @@ $token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_RECOVERY]); $I->amOnPage(Url::toRoute(['/user/recovery/reset', 'id' => $user->id, 'code' => $token->code])); $I->fillField('#recovery-form-password', 'newpass'); +$I->fillField('#recovery-form-password-confirmation', 'newpass'); $I->click('Finish'); $I->see('Your password has been changed successfully.'); From 05123207ebe9cdf98d09068da5c2b014808fbb15 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Tue, 10 Jan 2017 13:18:29 +0100 Subject: [PATCH 07/10] add $password_confirmation to RegistrationForm --- models/RegistrationForm.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/models/RegistrationForm.php b/models/RegistrationForm.php index 821bc7016..b25287520 100644 --- a/models/RegistrationForm.php +++ b/models/RegistrationForm.php @@ -38,6 +38,11 @@ class RegistrationForm extends Model */ public $password; + /** + * @var string Password confirmation + */ + public $password_confirmation; + /** * @inheritdoc */ From 9a29210164dd6a3cf509b993350ead0953aff6b1 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Tue, 10 Jan 2017 13:23:03 +0100 Subject: [PATCH 08/10] Adjust tests --- tests/_pages/RegistrationPage.php | 2 +- tests/functional/RecoveryCept.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/_pages/RegistrationPage.php b/tests/_pages/RegistrationPage.php index 1dec82972..5c323930c 100644 --- a/tests/_pages/RegistrationPage.php +++ b/tests/_pages/RegistrationPage.php @@ -25,7 +25,7 @@ public function register($email, $username = null, $password = null) $this->actor->fillField('#register-form-username', $username); if ($password !== null) { $this->actor->fillField('#register-form-password', $password); - $this->actor->fillField('#register-form-password-confirmation', $password); + $this->actor->fillField('#register-form-password_confirmation', $password); } $this->actor->click('Sign up'); } diff --git a/tests/functional/RecoveryCept.php b/tests/functional/RecoveryCept.php index 324ce5bf9..e6176620e 100644 --- a/tests/functional/RecoveryCept.php +++ b/tests/functional/RecoveryCept.php @@ -46,7 +46,7 @@ $token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_RECOVERY]); $I->amOnPage(Url::toRoute(['/user/recovery/reset', 'id' => $user->id, 'code' => $token->code])); $I->fillField('#recovery-form-password', 'newpass'); -$I->fillField('#recovery-form-password-confirmation', 'newpass'); +$I->fillField('#recovery-form-password_confirmation', 'newpass'); $I->click('Finish'); $I->see('Your password has been changed successfully.'); From 5d99595a71d895d7a9e37f7f0c3d1cb53571fa38 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Mon, 20 Mar 2017 12:37:19 +0100 Subject: [PATCH 09/10] profile settings overhaul --- controllers/SettingsController.php | 77 ++++++++++------ messages/de/user.php | 4 +- models/AccountDeletionForm.php | 93 +++++++++++++++++++ models/PasswordChangeForm.php | 97 ++++++++++++++++++++ models/SettingsForm.php | 55 ++++------- views/settings/account.php | 141 +++++++++++++++++++---------- 6 files changed, 351 insertions(+), 116 deletions(-) create mode 100644 models/AccountDeletionForm.php create mode 100644 models/PasswordChangeForm.php diff --git a/controllers/SettingsController.php b/controllers/SettingsController.php index 1d7e2dfea..1dbfd4a08 100644 --- a/controllers/SettingsController.php +++ b/controllers/SettingsController.php @@ -12,12 +12,15 @@ namespace dektrium\user\controllers; use dektrium\user\Finder; +use dektrium\user\models\AccountDeletionForm; +use dektrium\user\models\PasswordChangeForm; use dektrium\user\models\Profile; use dektrium\user\models\SettingsForm; use dektrium\user\models\User; use dektrium\user\Module; use dektrium\user\traits\AjaxValidationTrait; use dektrium\user\traits\EventTrait; +use Yii; use yii\filters\AccessControl; use yii\filters\VerbFilter; use yii\web\Controller; @@ -103,10 +106,10 @@ class SettingsController extends Controller protected $finder; /** - * @param string $id + * @param string $id * @param \yii\base\Module $module - * @param Finder $finder - * @param array $config + * @param Finder $finder + * @param array $config */ public function __construct($id, $module, Finder $finder, $config = []) { @@ -122,21 +125,21 @@ public function behaviors() 'class' => VerbFilter::className(), 'actions' => [ 'disconnect' => ['post'], - 'delete' => ['post'], + 'delete' => ['post'], ], ], 'access' => [ 'class' => AccessControl::className(), 'rules' => [ [ - 'allow' => true, + 'allow' => true, 'actions' => ['profile', 'account', 'networks', 'disconnect', 'delete'], - 'roles' => ['@'], + 'roles' => ['@'], ], [ - 'allow' => true, + 'allow' => true, 'actions' => ['confirm'], - 'roles' => ['?', '@'], + 'roles' => ['?', '@'], ], ], ], @@ -180,28 +183,39 @@ public function actionProfile() */ public function actionAccount() { - /** @var SettingsForm $model */ - $model = \Yii::createObject(SettingsForm::className()); - $event = $this->getFormEvent($model); + $settings = \Yii::createObject(SettingsForm::className()); + $account_deletion = \Yii::createObject(AccountDeletionForm::className()); + $password_change = \Yii::createObject(PasswordChangeForm::className()); + $event = $this->getFormEvent($settings); - $this->performAjaxValidation($model); + $this->performAjaxValidation($settings); + $this->performAjaxValidation($password_change); $this->trigger(self::EVENT_BEFORE_ACCOUNT_UPDATE, $event); - if ($model->load(\Yii::$app->request->post()) && $model->save()) { - \Yii::$app->session->setFlash('success', \Yii::t('user', 'Your account details have been updated')); + + if ($settings->load(\Yii::$app->request->post()) && $settings->save()) { + \Yii::$app->session->setFlash('success', Yii::t('user', 'Your account details have been updated')); + $this->trigger(self::EVENT_AFTER_ACCOUNT_UPDATE, $event); + return $this->refresh(); + } + + if ($password_change->load(\Yii::$app->request->post()) && $password_change->save()) { + \Yii::$app->session->setFlash('success', Yii::t('user', 'Your password has been changed successfully.')); $this->trigger(self::EVENT_AFTER_ACCOUNT_UPDATE, $event); return $this->refresh(); } return $this->render('account', [ - 'model' => $model, + 'settings' => $settings, + 'account_deletion' => $account_deletion, + 'password_change' => $password_change, ]); } /** * Attempts changing user's email address. * - * @param int $id + * @param int $id * @param string $code * * @return string @@ -273,27 +287,32 @@ public function actionDisconnect($id) */ public function actionDelete() { - if (!$this->module->enableAccountDelete) { + if (!Yii::$app->getModule('user')->enableAccountDelete) { throw new NotFoundHttpException(\Yii::t('user', 'Account deletion is deactivated')); } /** @var User $user */ - $user = \Yii::$app->user->identity; - $event = $this->getUserEvent($user); + $user = \Yii::$app->user->identity; + $account_deletion = new AccountDeletionForm(); + + $this->performAjaxValidation($account_deletion); - \Yii::$app->user->logout(); + if ($account_deletion->load(Yii::$app->request->post()) && $account_deletion->validate()) { + $event = $this->getUserEvent($user); - $this->trigger(self::EVENT_BEFORE_DELETE, $event); - $success = $user->delete(); - $this->trigger(self::EVENT_AFTER_DELETE, $event); + Yii::$app->user->logout(); + $this->trigger(self::EVENT_BEFORE_DELETE, $event); + $success = $user->delete(); + $this->trigger(self::EVENT_AFTER_DELETE, $event); - if ($success) { - \Yii::$app->session->setFlash('info', \Yii::t('user', 'Your account has been completely deleted')); - return $this->goHome(); - } else { - \Yii::$app->session->setFlash('danger', \Yii::t('user', 'Your account could not be deleted')); - return $this->goBack(); + if ($success) { + Yii::$app->session->setFlash('info', \Yii::t('user', 'Your account has been completely deleted')); + return $this->goHome(); + } else { + Yii::$app->session->setFlash('danger', \Yii::t('user', 'Your account could not be deleted')); + return $this->goBack(); + } } return $this->goHome(); diff --git a/messages/de/user.php b/messages/de/user.php index 16c9a7673..760b05cb0 100644 --- a/messages/de/user.php +++ b/messages/de/user.php @@ -54,7 +54,7 @@ 'Invalid or expired link' => 'Falscher oder abgelaufener Link', 'New email' => 'Neue E-Mail Adresse', 'New password' => 'Neues Passwort', - 'New password confirmation' => 'Neues Passwort Bestätigung', + 'New password confirmation' => 'Passwort Bestätigung', 'New permission' => 'Neue Berechtigung', 'New role' => 'Neue Rolle', 'New user' => 'Neuer Benutzer', @@ -156,6 +156,7 @@ 'Confirmed at {0, date, MMMM dd, YYYY HH:mm}' => 'Bestätigt am {0, date, dd MMMM, YYYY HH:mm}', 'Connect' => 'Verbunden', 'Continue' => 'Weiter', + 'Change password' => 'Passwort ändern', 'Create a user account' => 'Neuen Zugang erstellen', 'Current password' => 'Aktuelles Passwort', 'Current password is not valid' => 'Das von Ihnen eingegebene Passwort stimmt nicht', @@ -207,6 +208,7 @@ 'Never' => 'Nie', 'Last login' => 'Letzte Anmeldung', 'Save' => 'Speichern', + 'Save account settings' => 'Kontoänderungen speichern', 'Sign in' => 'Anmelden', 'Sign up' => 'Registrieren', 'Thank you for signing up on {0}' => 'Vielen Dank für Ihre Anmeldung bei {0}', diff --git a/models/AccountDeletionForm.php b/models/AccountDeletionForm.php new file mode 100644 index 000000000..397e7421d --- /dev/null +++ b/models/AccountDeletionForm.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace dektrium\user\models; + +use dektrium\user\helpers\Password; +use dektrium\user\traits\ModuleTrait; +use Yii; +use yii\base\Model; +use yii\web\BadRequestHttpException; + +/** + * AccountDeletionForm prompts for the password of the currently logged in user. If it´s correct, + * the account gets deleted. + * + * @property User $user + * + * @author Herbert Maschke + */ +class AccountDeletionForm extends Model +{ + use ModuleTrait; + + /** @var string */ + public $current_password; + + /** @var User */ + private $_user; + + /** @return User */ + public function getUser() + { + if ($this->_user == null) { + $this->_user = Yii::$app->user->identity; + } + + return $this->_user; + } + + /** @inheritdoc */ + public function rules() + { + return [ + 'currentPasswordRequired' => ['current_password', 'required'], + 'currentPasswordValidate' => ['current_password', function ($attr) { + if (!Password::validate($this->$attr, $this->user->password_hash)) { + $this->addError($attr, Yii::t('user', 'Current password is not valid')); + } + }], + ]; + } + + /** @inheritdoc */ + public function attributeLabels() + { + return [ + 'current_password' => Yii::t('user', 'Current password'), + ]; + } + + /** @inheritdoc */ + public function formName() + { + return 'account-deletion-form'; + } + + /** + * Do the dirty work. + * + * @return bool + */ + protected function delete() + { + if (!$this->module->enableAccountDelete) { + throw new NotFoundHttpException(\Yii::t('user', 'Account deletion is deactivated')); + } + + if (!$this->validate()) { + return false; + } + + return false; + } + +} diff --git a/models/PasswordChangeForm.php b/models/PasswordChangeForm.php new file mode 100644 index 000000000..d94d83c7b --- /dev/null +++ b/models/PasswordChangeForm.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace dektrium\user\models; + +use dektrium\user\helpers\Password; +use dektrium\user\traits\ModuleTrait; +use Yii; +use yii\base\Model; +use yii\web\BadRequestHttpException; + +/** + * PasswordChangeForm prompts for the password of the currently logged in user. If it´s correct, + * the user can set a new password for his account. + * + * @property User $user + * + * @author Herbert Maschke + */ +class PasswordChangeForm extends Model +{ + use ModuleTrait; + + /** @var string */ + public $username; + + /** @var string */ + public $new_password; + + /** @var string */ + public $new_password_confirmation; + + /** @var string */ + public $current_password; + + /** @var User */ + private $_user; + + /** @return User */ + public function getUser() + { + if ($this->_user == null) { + $this->_user = Yii::$app->user->identity; + } + + return $this->_user; + } + + /** @inheritdoc */ + public function rules() + { + return [ + 'newPasswordRequired' => ['new_password', 'required'], + 'newPasswordConfirmationRequired' => ['new_password_confirmation', 'required'], + 'newPasswordLength' => ['new_password', 'string', 'max' => 72, 'min' => 6], + 'newPasswordConfirmation' => ['new_password_confirmation', 'compare', 'compareAttribute' => 'new_password'], + 'currentPasswordRequired' => ['current_password', 'required'], + 'currentPasswordValidate' => ['current_password', function ($attr) { + if (!Password::validate($this->$attr, $this->user->password_hash)) { + $this->addError($attr, Yii::t('user', 'Current password is not valid')); + } + }], + ]; + } + + /** @inheritdoc */ + public function attributeLabels() + { + return [ + 'new_password' => Yii::t('user', 'New password'), + 'new_password_confirmation' => Yii::t('user', 'New password confirmation'), + 'current_password' => Yii::t('user', 'Current password'), + ]; + } + + /** @inheritdoc */ + public function formName() + { + return 'password-change-form'; + } + + /** @inheritdoc */ + public function save() + { + $this->user->password = $this->new_password; + return $this->user->save(true, ['password', 'password_hash']); + } + +} diff --git a/models/SettingsForm.php b/models/SettingsForm.php index 9f5af861b..3008c0678 100644 --- a/models/SettingsForm.php +++ b/models/SettingsForm.php @@ -35,21 +35,22 @@ class SettingsForm extends Model /** @var string */ public $username; - /** @var string */ - public $new_password; - - /** @var string */ - public $new_password_confirmation; - - /** @var string */ - public $current_password; - /** @var Mailer */ protected $mailer; /** @var User */ private $_user; + /** @inheritdoc */ + public function __construct(Mailer $mailer, $config = []) + { + $this->setAttributes([ + 'username' => $this->user->username, + 'email' => $this->user->unconfirmed_email ?: $this->user->email, + ], false); + parent::__construct($config); + } + /** @return User */ public function getUser() { @@ -60,24 +61,13 @@ public function getUser() return $this->_user; } - /** @inheritdoc */ - public function __construct(Mailer $mailer, $config = []) - { - $this->mailer = $mailer; - $this->setAttributes([ - 'username' => $this->user->username, - 'email' => $this->user->unconfirmed_email ?: $this->user->email, - ], false); - parent::__construct($config); - } - /** @inheritdoc */ public function rules() { return [ 'usernameTrim' => ['username', 'trim'], 'usernameRequired' => ['username', 'required'], - 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], + 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], 'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'], 'emailTrim' => ['email', 'trim'], 'emailRequired' => ['email', 'required'], @@ -85,14 +75,6 @@ public function rules() 'emailUsernameUnique' => [['email', 'username'], 'unique', 'when' => function ($model, $attribute) { return $this->user->$attribute != $model->$attribute; }, 'targetClass' => $this->module->modelMap['User']], - 'newPasswordLength' => ['new_password', 'string', 'max' => 72, 'min' => 6], - 'newPasswordConfirmation' => ['new_password_confirmation', 'compare', 'compareAttribute' => 'new_password'], - 'currentPasswordRequired' => ['current_password', 'required'], - 'currentPasswordValidate' => ['current_password', function ($attr) { - if (!Password::validate($this->$attr, $this->user->password_hash)) { - $this->addError($attr, Yii::t('user', 'Current password is not valid')); - } - }], ]; } @@ -100,11 +82,8 @@ public function rules() public function attributeLabels() { return [ - 'email' => Yii::t('user', 'Email'), - 'username' => Yii::t('user', 'Username'), - 'new_password' => Yii::t('user', 'New password'), - 'new_password_confirmation' => Yii::t('user', 'New password confirmation'), - 'current_password' => Yii::t('user', 'Current password'), + 'email' => Yii::t('user', 'Email'), + 'username' => Yii::t('user', 'Username'), ]; } @@ -166,9 +145,9 @@ protected function defaultEmailChange() $this->user->unconfirmed_email = $this->email; /** @var Token $token */ $token = Yii::createObject([ - 'class' => Token::className(), + 'class' => Token::className(), 'user_id' => $this->user->id, - 'type' => Token::TYPE_CONFIRM_NEW_EMAIL, + 'type' => Token::TYPE_CONFIRM_NEW_EMAIL, ]); $token->save(false); $this->mailer->sendReconfirmationMessage($this->user, $token); @@ -188,9 +167,9 @@ protected function secureEmailChange() $this->defaultEmailChange(); /** @var Token $token */ $token = Yii::createObject([ - 'class' => Token::className(), + 'class' => Token::className(), 'user_id' => $this->user->id, - 'type' => Token::TYPE_CONFIRM_OLD_EMAIL, + 'type' => Token::TYPE_CONFIRM_OLD_EMAIL, ]); $token->save(false); $this->mailer->sendReconfirmationMessage($this->user, $token); diff --git a/views/settings/account.php b/views/settings/account.php index 1f4752524..06a5a9b89 100644 --- a/views/settings/account.php +++ b/views/settings/account.php @@ -9,17 +9,32 @@ * file that was distributed with this source code. */ +use yii\helpers\ArrayHelper; use yii\helpers\Html; +use yii\helpers\Url; use yii\widgets\ActiveForm; /** - * @var yii\web\View $this - * @var yii\widgets\ActiveForm $form - * @var dektrium\user\models\SettingsForm $model + * @var $this yii\web\View + * @var $form yii\widgets\ActiveForm + * @var $settings dektrium\user\models\SettingsForm + * @var $account_deletion dektrium\user\models\AccountDeletionForm + * @var $password_change dektrium\user\models\PasswordChangeForm */ $this->title = Yii::t('user', 'Account settings'); $this->params['breadcrumbs'][] = $this->title; + +$form_options = [ + 'options' => ['class' => 'form-horizontal'], + 'enableAjaxValidation' => true, + 'enableClientValidation' => true, + 'fieldConfig' => [ + 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", + 'labelOptions' => ['class' => 'col-lg-4 control-label'] + ], +]; + ?> render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> @@ -28,63 +43,93 @@
render('_menu') ?>
+
-
-
-

title) ?>

-
-
- 'account-form', - 'options' => ['class' => 'form-horizontal'], - 'fieldConfig' => [ - 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", - 'labelOptions' => ['class' => 'col-lg-3 control-label'], - ], - 'enableAjaxValidation' => true, - 'enableClientValidation' => false, - ]); ?> +
+
+
+
+

title) ?>

+
+
+ 'account-form-settings'])); ?> - field($model, 'email') ?> + - field($model, 'username') ?> + field($settings, 'email') ?> - field($model, 'new_password')->passwordInput() ?> + field($settings, 'username') ?> - field($model, 'new_password_confirmation')->passwordInput() ?> +
+
+ 'btn btn-block btn-success']) ?> +
+
+
-
+ +
+
- field($model, 'current_password')->passwordInput() ?> + 'password-change-form'])); ?> -
-
- 'btn btn-block btn-success']) ?>
+
+
+

-
+
- -
-
+ field($password_change, 'new_password')->passwordInput() ?> - module->enableAccountDelete): ?> -
-
-

-
-
-

- . - . - . -

- 'btn btn-danger', - 'data-method' => 'post', - 'data-confirm' => Yii::t('user', 'Are you sure? There is no going back'), - ]) ?> + field($password_change, 'new_password_confirmation')->passwordInput() ?> + +
+ + field($password_change, 'current_password')->passwordInput() ?> + +
+
+ 'btn btn-block btn-success']) ?> +
+
+
+ + +
+ + + getModule('user')->enableAccountDelete): ?> +
+ 'account-form-account-deletion', + 'action' => Url::to(['delete']), + ])); ?> + +
+

+
+
+

+ . + . + . +

+ + field($account_deletion, 'current_password')->passwordInput() ?> + + 'btn btn-danger pull-right', + 'data-method' => 'post', + 'data-confirm' => Yii::t('user', 'Are you sure? There is no going back'), + ]) ?> +
+ +
+ +
- +
+ From dec3316c304d9acdbe6791464317b1445e70746d Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Tue, 21 Mar 2017 16:51:58 +0100 Subject: [PATCH 10/10] Do not set password in SettingsForm - its done in PasswordChangeForm --- models/SettingsForm.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models/SettingsForm.php b/models/SettingsForm.php index 3008c0678..12c8a02b7 100644 --- a/models/SettingsForm.php +++ b/models/SettingsForm.php @@ -19,7 +19,7 @@ use yii\base\Model; /** - * SettingsForm gets user's username, email and password and changes them. + * SettingsForm gets user's username and email and changes them. * * @property User $user * @@ -103,7 +103,6 @@ public function save() if ($this->validate()) { $this->user->scenario = 'settings'; $this->user->username = $this->username; - $this->user->password = $this->new_password; if ($this->email == $this->user->email && $this->user->unconfirmed_email != null) { $this->user->unconfirmed_email = null; } elseif ($this->email != $this->user->email) {