<?php declare(strict_types=1); namespace api\models\authentication; use api\components\ReCaptcha\Validator as ReCaptchaValidator; use api\models\base\ApiForm; use common\components\UserFriendlyRandomKey; use common\helpers\Error as E; use common\models\Account; use common\models\confirmations\ForgotPassword; use common\models\EmailActivation; use common\tasks\SendPasswordRecoveryEmail; use Yii; use yii\base\ErrorException; class ForgotPasswordForm extends ApiForm { public mixed $captcha = null; public mixed $login = null; public function rules(): array { return [ ['captcha', ReCaptchaValidator::class], ['login', 'required', 'message' => E::LOGIN_REQUIRED], ['login', 'validateLogin'], ['login', 'validateActivity'], ['login', 'validateFrequency'], ]; } public function validateLogin(string $attribute): void { if (!$this->hasErrors()) { if ($this->getAccount() === null) { $this->addError($attribute, E::LOGIN_NOT_EXIST); } } } public function validateActivity(string $attribute): void { if (!$this->hasErrors()) { $account = $this->getAccount(); if ($account->status !== Account::STATUS_ACTIVE) { $this->addError($attribute, E::ACCOUNT_NOT_ACTIVATED); } } } public function validateFrequency(string $attribute): void { if (!$this->hasErrors()) { $emailConfirmation = $this->getEmailActivation(); if ($emailConfirmation !== null && !$emailConfirmation->canResend()) { $this->addError($attribute, E::RECENTLY_SENT_MESSAGE); } } } public function getAccount(): ?Account { return Account::find()->andWhereLogin($this->login)->one(); } public function forgotPassword(): bool { if (!$this->validate()) { return false; } $account = $this->getAccount(); $emailActivation = $this->getEmailActivation(); if ($emailActivation === null) { $emailActivation = new ForgotPassword(); $emailActivation->account_id = $account->id; } else { $emailActivation->created_at = time(); } $emailActivation->key = UserFriendlyRandomKey::make(); if (!$emailActivation->save()) { throw new ErrorException('Cannot create email activation for forgot password form'); } Yii::$app->queue->push(SendPasswordRecoveryEmail::createFromConfirmation($emailActivation)); return true; } public function getEmailActivation(): ?ForgotPassword { $account = $this->getAccount(); if ($account === null) { return null; } // @phpstan-ignore return.type return $account->getEmailActivations()->withType(EmailActivation::TYPE_FORGOT_PASSWORD_KEY)->one(); } }