From 39379bc8b6e1f17868c53f09984d05875bee8d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Farr=C3=A9?= <23310825+marc-farre@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:25:31 +0200 Subject: [PATCH] Fix #6730: Invitation link for existing user (#6916) --- CHANGELOG-DEV.md | 1 + .../user/controllers/AuthController.php | 2 +- .../controllers/RegistrationController.php | 7 +++++-- .../humhub/modules/user/models/Invite.php | 21 ++++++++++--------- .../user/services/LinkRegistrationService.php | 19 +++++++++++++---- .../user/views/mails/UserInviteSelf.php | 7 +++++-- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/CHANGELOG-DEV.md b/CHANGELOG-DEV.md index 146feb86a9..6d09a7a3c3 100644 --- a/CHANGELOG-DEV.md +++ b/CHANGELOG-DEV.md @@ -75,3 +75,4 @@ HumHub Changelog - Fix #6908: Fix default mentioning URL - Enh #6901: Auto load pages on content search - Fix #6913: Fix API tests +- Fix #6730: Invitation link for existing user diff --git a/protected/humhub/modules/user/controllers/AuthController.php b/protected/humhub/modules/user/controllers/AuthController.php index 77fca33cb7..0277173a11 100644 --- a/protected/humhub/modules/user/controllers/AuthController.php +++ b/protected/humhub/modules/user/controllers/AuthController.php @@ -113,7 +113,7 @@ class AuthController extends Controller // Self Invite $invite = new Invite(); - $invite->scenario = 'invite'; + $invite->scenario = Invite::SCENARIO_INVITE; if ($invite->load(Yii::$app->request->post()) && $invite->selfInvite()) { if (Yii::$app->request->isAjax) { return $this->renderAjax('register_success_modal', ['model' => $invite]); diff --git a/protected/humhub/modules/user/controllers/RegistrationController.php b/protected/humhub/modules/user/controllers/RegistrationController.php index d992d7f948..f975ac19d5 100644 --- a/protected/humhub/modules/user/controllers/RegistrationController.php +++ b/protected/humhub/modules/user/controllers/RegistrationController.php @@ -147,10 +147,13 @@ class RegistrationController extends Controller $linkRegistrationService->storeInSession(); - $form = new Invite(['source' => Invite::SOURCE_INVITE_BY_LINK]); + $form = new Invite([ + 'source' => Invite::SOURCE_INVITE_BY_LINK, + 'scenario' => Invite::SCENARIO_INVITE_BY_LINK_FORM, + ]); if ($form->load(Yii::$app->request->post()) && $form->validate()) { $invite = $linkRegistrationService->convertToInvite($form->email); - $invite->sendInviteMail(); + $invite?->sendInviteMail(); return $this->render('@user/views/auth/register_success', ['model' => $invite]); } diff --git a/protected/humhub/modules/user/models/Invite.php b/protected/humhub/modules/user/models/Invite.php index 012156351d..7131c3307c 100644 --- a/protected/humhub/modules/user/models/Invite.php +++ b/protected/humhub/modules/user/models/Invite.php @@ -43,6 +43,8 @@ class Invite extends ActiveRecord public const SOURCE_SELF = 'self'; public const SOURCE_INVITE = 'invite'; public const SOURCE_INVITE_BY_LINK = 'invite_by_link'; + public const SCENARIO_INVITE = 'invite'; + public const SCENARIO_INVITE_BY_LINK_FORM = 'invite_by_link_form'; public const EMAIL_TOKEN_LENGTH = 12; public const LINK_TOKEN_LENGTH = 14; // Should be different that EMAIL_TOKEN_LENGTH @@ -74,9 +76,9 @@ class Invite extends ActiveRecord [['email'], 'string', 'max' => 150], [['language'], 'string', 'max' => 10], [['email'], 'required'], - [['email'], 'unique'], + [['email'], 'unique', 'except' => self::SCENARIO_INVITE_BY_LINK_FORM], [['email'], 'email'], - [['captcha'], 'captcha', 'captchaAction' => 'user/auth/captcha', 'on' => static::SOURCE_INVITE], + [['captcha'], 'captcha', 'captchaAction' => 'user/auth/captcha', 'on' => [self::SCENARIO_INVITE, self::SCENARIO_INVITE_BY_LINK_FORM]], ]; } @@ -86,10 +88,12 @@ class Invite extends ActiveRecord public function scenarios() { $scenarios = parent::scenarios(); - $scenarios['invite'] = ['email']; + $scenarios[self::SCENARIO_INVITE] = ['email']; + $scenarios[self::SCENARIO_INVITE_BY_LINK_FORM] = ['email']; if ($this->showCaptureInRegisterForm()) { - $scenarios['invite'][] = 'captcha'; + $scenarios[self::SCENARIO_INVITE][] = 'captcha'; + $scenarios[self::SCENARIO_INVITE_BY_LINK_FORM][] = 'captcha'; } return $scenarios; @@ -175,13 +179,12 @@ class Invite extends ActiveRecord 'html' => '@humhub/modules/user/views/mails/UserInviteSelf', 'text' => '@humhub/modules/user/views/mails/plaintext/UserInviteSelf' ], [ - 'token' => $this->token, 'registrationUrl' => $registrationUrl ]); $mail->setTo($this->email); $mail->setSubject(Yii::t('UserModule.base', 'Welcome to %appName%', ['%appName%' => Yii::$app->name])); $result = $mail->send(); - } elseif ($this->source == self::SOURCE_INVITE && $this->space !== null) { + } elseif ($this->source === self::SOURCE_INVITE && $this->space !== null) { if ($module->sendInviteMailsInGlobalLanguage) { Yii::$app->setLanguage(Yii::$app->settings->get('defaultLanguage')); } @@ -190,7 +193,6 @@ class Invite extends ActiveRecord 'html' => '@humhub/modules/user/views/mails/UserInviteSpace', 'text' => '@humhub/modules/user/views/mails/plaintext/UserInviteSpace' ], [ - 'token' => $this->token, 'originator' => $this->originator, 'originatorName' => $this->originator->displayName, 'space' => $this->space, @@ -202,7 +204,7 @@ class Invite extends ActiveRecord // Switch back to users language Yii::$app->setLanguage(Yii::$app->user->language); - } elseif ($this->source == self::SOURCE_INVITE) { + } elseif ($this->source === self::SOURCE_INVITE) { // Switch to systems default language if ($module->sendInviteMailsInGlobalLanguage) { @@ -215,7 +217,6 @@ class Invite extends ActiveRecord ], [ 'originator' => $this->originator, 'originatorName' => $this->originator->displayName, - 'token' => $this->token, 'registrationUrl' => $registrationUrl ]); $mail->setTo($this->email); @@ -234,7 +235,7 @@ class Invite extends ActiveRecord * * @return bool */ - private function isRegisteredUser(): bool + public function isRegisteredUser(): bool { return User::find()->where(['email' => $this->email])->exists(); } diff --git a/protected/humhub/modules/user/services/LinkRegistrationService.php b/protected/humhub/modules/user/services/LinkRegistrationService.php index 28f294262c..f8cbeb2f1b 100644 --- a/protected/humhub/modules/user/services/LinkRegistrationService.php +++ b/protected/humhub/modules/user/services/LinkRegistrationService.php @@ -12,8 +12,10 @@ use humhub\modules\space\models\Space; use humhub\modules\user\models\Invite; use humhub\modules\user\models\User; use humhub\modules\user\Module; +use Throwable; use Yii; use yii\base\Exception; +use yii\db\StaleObjectException; /** * LinkRegistrationService is responsible for registrations (Global or per Space) using an Invite Link. @@ -88,17 +90,21 @@ final class LinkRegistrationService return $newToken; } - public function convertToInvite(string $email): Invite + /** + * @throws Exception + * @throws Throwable + * @throws StaleObjectException + */ + public function convertToInvite(string $email): ?Invite { // Deleting any previous email invitation or abandoned link invitation - $oldInvite = Invite::findOne(['email' => $email]); - if ($oldInvite !== null) { + $oldInvites = Invite::findAll(['email' => $email]); + foreach ($oldInvites as $oldInvite) { $oldInvite->delete(); } $invite = new Invite([ 'email' => $email, - 'scenario' => 'invite', 'language' => Yii::$app->language, ]); $invite->skipCaptchaValidation = true; @@ -107,6 +113,11 @@ final class LinkRegistrationService $invite->space_invite_id = $this->space->id; } + if ($invite->isRegisteredUser()) { + $invite->sendAlreadyRegisteredUserMail(); + return null; + } + if (!$invite->save()) { throw new Exception('Could not create invite!'); } diff --git a/protected/humhub/modules/user/views/mails/UserInviteSelf.php b/protected/humhub/modules/user/views/mails/UserInviteSelf.php index d13a608b2e..4815d1e354 100644 --- a/protected/humhub/modules/user/views/mails/UserInviteSelf.php +++ b/protected/humhub/modules/user/views/mails/UserInviteSelf.php @@ -1,9 +1,12 @@ @@ -126,7 +129,7 @@ use yii\helpers\Html; -