Код модели подтверждения через email теперь является первичным ключом тамблицы

Реализована форма подтверждения email, обмазана тестами
Слегка отрефакторена форма регистрации и авторизации в пользу выноса части логики в общего родителя
Проект зачищен от стандартных тестовых параметров
Пофикшены методы доступа к API
This commit is contained in:
ErickSkrauch
2016-01-21 00:14:29 +03:00
parent 44aaea2c08
commit 7e90f1838e
30 changed files with 430 additions and 107 deletions

View File

@@ -34,11 +34,14 @@ return [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [],
'rules' => require __DIR__ . '/routes.php',
],
'reCaptcha' => [
'class' => 'api\components\ReCaptcha\Component',
],
'response' => [
'format' => \yii\web\Response::FORMAT_JSON,
],
],
'params' => $params,
];

3
api/config/routes.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
return [
];

View File

@@ -10,11 +10,10 @@ class AuthenticationController extends Controller {
public function behaviors() {
return array_merge(parent::behaviors(), [
'access' => [
'class' => AccessControl::className(),
'only' => ['login'],
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['login', 'register'],
'actions' => ['login'],
'allow' => true,
'roles' => ['?'],
],
@@ -25,8 +24,7 @@ class AuthenticationController extends Controller {
public function verbs() {
return [
'login' => ['post'],
'register' => ['post'],
'login' => ['POST'],
];
}

View File

@@ -1,6 +1,7 @@
<?php
namespace api\controllers;
use api\models\ConfirmEmailForm;
use api\models\RegistrationForm;
use Yii;
use yii\filters\AccessControl;
@@ -10,11 +11,10 @@ class SignupController extends Controller {
public function behaviors() {
return array_merge(parent::behaviors(), [
'access' => [
'class' => AccessControl::className(),
'only' => ['register'],
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['register'],
'actions' => ['register', 'confirm'],
'allow' => true,
'roles' => ['?'],
],
@@ -23,6 +23,13 @@ class SignupController extends Controller {
]);
}
public function verbs() {
return [
'register' => ['POST'],
'confirm' => ['POST'],
];
}
public function actionRegister() {
$model = new RegistrationForm();
$model->load(Yii::$app->request->post());
@@ -38,4 +45,24 @@ class SignupController extends Controller {
];
}
public function actionConfirm() {
$model = new ConfirmEmailForm();
$model->load(Yii::$app->request->post());
if (!$model->confirm()) {
return [
'success' => false,
'errors' => $this->normalizeModelErrors($model->getErrors()),
];
}
// TODO: не уверен, что логин должен быть здесь + нужно разобраться с параметрами установки куки авторизации и сессии
$activationCode = $model->getActivationCodeModel();
$account = $activationCode->account;
Yii::$app->user->login($account);
return [
'success' => true,
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace api\models;
use yii\base\Model;
class BaseApiForm extends Model {
public function formName() {
return '';
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace api\models;
use common\models\EmailActivation;
class BaseKeyConfirmationForm extends BaseApiForm {
public $key;
private $model;
public function rules() {
return [
['key', 'required', 'message' => 'error.key_is_required'],
['key', 'validateKey'],
];
}
public function validateKey($attribute) {
if (!$this->hasErrors()) {
if ($this->getActivationCodeModel() === null) {
$this->addError($attribute, "error.{$attribute}_not_exists");
}
}
}
/**
* @return EmailActivation|null
*/
public function getActivationCodeModel() {
if ($this->model === null) {
$this->model = EmailActivation::findOne($this->key);
}
return $this->model;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace api\models;
use common\models\Account;
use common\models\EmailActivation;
use Yii;
use yii\base\ErrorException;
class ConfirmEmailForm extends BaseKeyConfirmationForm {
public function confirm() {
if (!$this->validate()) {
return false;
}
$confirmModel = $this->getActivationCodeModel();
if ($confirmModel->type != EmailActivation::TYPE_REGISTRATION_EMAIL_CONFIRMATION) {
$confirmModel->delete();
// TODO: вот где-то здесь нужно ещё попутно сгенерировать соответствующую ошибку
return false;
}
$transaction = Yii::$app->db->beginTransaction();
try {
$account = $confirmModel->account;
$account->status = Account::STATUS_ACTIVE;
if (!$confirmModel->delete()) {
throw new ErrorException('Unable remove activation key.');
}
if (!$account->save()) {
throw new ErrorException('Unable activate user account.');
}
$transaction->commit();
} catch (ErrorException $e) {
$transaction->rollBack();
throw $e;
}
return true;
}
}

View File

@@ -3,9 +3,8 @@ namespace api\models;
use common\models\Account;
use Yii;
use yii\base\Model;
class LoginForm extends Model {
class LoginForm extends BaseApiForm {
public $login;
public $password;
@@ -13,10 +12,6 @@ class LoginForm extends Model {
private $_account;
public function formName() {
return '';
}
public function rules() {
return [
['login', 'required', 'message' => 'error.login_required'],

View File

@@ -7,9 +7,8 @@ use common\models\Account;
use common\models\EmailActivation;
use Yii;
use yii\base\ErrorException;
use yii\base\Model;
class RegistrationForm extends Model {
class RegistrationForm extends BaseApiForm {
public $username;
public $email;
@@ -17,10 +16,6 @@ class RegistrationForm extends Model {
public $rePassword;
public $rulesAgreement;
public function formName() {
return '';
}
public function rules() {
return [
['rulesAgreement', 'required', 'message' => 'error.you_must_accept_rules'],