From cf6c7bc88e8e376eb51b329040f28c396ac5c2cf Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Sat, 6 Aug 2016 18:52:03 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BF=D0=BE=D0=BB=D0=B5=20=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=81=D0=B8=D0=B8=20=D0=BF=D1=80=D0=B8=D0=BD=D1=8F=D1=82=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/controllers/AccountsController.php | 6 +++-- .../authentication/RegistrationForm.php | 2 ++ common/consts.php | 5 ++++ common/models/Account.php | 22 ++++++++++++++++ composer.json | 5 ++++ ...144759_account_rules_agreement_version.php | 15 +++++++++++ .../api/functional/AccountsCurrentCest.php | 2 +- .../authentication/RegistrationFormTest.php | 2 ++ .../common/fixtures/data/accounts.php | 8 ++++++ .../common/unit/models/AccountTest.php | 26 +++++++++++++++++++ 10 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 common/consts.php create mode 100644 console/migrations/m160806_144759_account_rules_agreement_version.php diff --git a/api/controllers/AccountsController.php b/api/controllers/AccountsController.php index 8a66258..2861d3c 100644 --- a/api/controllers/AccountsController.php +++ b/api/controllers/AccountsController.php @@ -37,9 +37,10 @@ class AccountsController extends Controller { 'allow' => true, 'roles' => ['@'], 'matchCallback' => function() { - /** @var Account $account */ $account = Yii::$app->user->identity; - return $account->status > Account::STATUS_REGISTERED; + + return $account->status > Account::STATUS_REGISTERED + && $account->isAgreedWithActualRules(); }, ], ], @@ -72,6 +73,7 @@ class AccountsController extends Controller { 'isActive' => $account->status === Account::STATUS_ACTIVE, 'passwordChangedAt' => $account->password_changed_at, 'hasMojangUsernameCollision' => $account->hasMojangUsernameCollision(), + 'shouldAcceptRules' => !$account->isAgreedWithActualRules(), ]; } diff --git a/api/models/authentication/RegistrationForm.php b/api/models/authentication/RegistrationForm.php index 04accb4..f285478 100644 --- a/api/models/authentication/RegistrationForm.php +++ b/api/models/authentication/RegistrationForm.php @@ -16,6 +16,7 @@ use Ramsey\Uuid\Uuid; use Yii; use yii\base\ErrorException; use yii\base\InvalidConfigException; +use const common\LATEST_RULES_VERSION; class RegistrationForm extends ApiForm { @@ -92,6 +93,7 @@ class RegistrationForm extends ApiForm { $account->password = $this->password; $account->lang = $this->lang; $account->status = Account::STATUS_REGISTERED; + $account->rules_agreement_version = LATEST_RULES_VERSION; if (!$account->save()) { throw new ErrorException('Account not created.'); } diff --git a/common/consts.php b/common/consts.php new file mode 100644 index 0000000..5018f6c --- /dev/null +++ b/common/consts.php @@ -0,0 +1,5 @@ +exists(); } + /** + * Т.к. у нас нет инфы по static_url пользователя, то пока генерируем самый простой вариант + * с ссылкой на профиль по id. На Ely он всё равно редиректнется на static, а мы так или + * иначе обеспечим отдачу этой инфы. + * + * @return string + */ public function getProfileLink() : string { return 'http://ely.by/u' . $this->id; } + /** + * При создании структуры БД все аккаунты получают null значение в это поле, однако оно + * обязательно для заполнения. Все мигрировавшие с Ely аккаунты будут иметь null значение, + * а актуальной версией будет 1 версия правил сайта (т.к. раньше их просто не было). Ну а + * дальше уже будем инкрементить. + * + * @return bool + */ + public function isAgreedWithActualRules() : bool { + return $this->rules_agreement_version === LATEST_RULES_VERSION; + } + } diff --git a/composer.json b/composer.json index d4a6c1d..51435db 100644 --- a/composer.json +++ b/composer.json @@ -51,5 +51,10 @@ ], "scripts": { "phploc" : "phploc ./api ./common ./console" + }, + "autoload": { + "files": [ + "common/consts.php" + ] } } diff --git a/console/migrations/m160806_144759_account_rules_agreement_version.php b/console/migrations/m160806_144759_account_rules_agreement_version.php new file mode 100644 index 0000000..6b7005d --- /dev/null +++ b/console/migrations/m160806_144759_account_rules_agreement_version.php @@ -0,0 +1,15 @@ +addColumn('{{%accounts}}', 'rules_agreement_version', $this->smallInteger()->unsigned()->after('status')); + } + + public function safeDown() { + $this->dropColumn('{{%accounts}}', 'rules_agreement_version'); + } + +} diff --git a/tests/codeception/api/functional/AccountsCurrentCest.php b/tests/codeception/api/functional/AccountsCurrentCest.php index 114826f..8ecc90f 100644 --- a/tests/codeception/api/functional/AccountsCurrentCest.php +++ b/tests/codeception/api/functional/AccountsCurrentCest.php @@ -1,7 +1,6 @@ false, 'isActive' => true, 'hasMojangUsernameCollision' => false, + 'shouldAcceptRules' => false, ]); $I->canSeeResponseJsonMatchesJsonPath('$.passwordChangedAt'); } diff --git a/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php b/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php index 6d3e89e..0e09ccc 100644 --- a/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php +++ b/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php @@ -8,6 +8,7 @@ use common\models\EmailActivation; use tests\codeception\api\unit\DbTestCase; use tests\codeception\common\fixtures\AccountFixture; use Yii; +use const common\LATEST_RULES_VERSION; /** * @property array $accounts @@ -99,6 +100,7 @@ class RegistrationFormTest extends DbTestCase { expect('user should be valid', $account)->isInstanceOf(Account::class); expect('password should be correct', $account->validatePassword('some_password'))->true(); expect('uuid is set', $account->uuid)->notEmpty(); + expect('actual rules version is set', $account->rules_agreement_version)->equals(LATEST_RULES_VERSION); expect('user model exists in database', Account::find()->andWhere([ 'username' => 'some_username', 'email' => 'some_email@example.com', diff --git a/tests/codeception/common/fixtures/data/accounts.php b/tests/codeception/common/fixtures/data/accounts.php index 28dc423..b4f66f9 100644 --- a/tests/codeception/common/fixtures/data/accounts.php +++ b/tests/codeception/common/fixtures/data/accounts.php @@ -9,6 +9,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1451775316, 'updated_at' => 1451775316, 'password_changed_at' => 1451775316, @@ -22,6 +23,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_OLD_ELY, 'lang' => 'en', 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1385225069, 'updated_at' => 1385225069, 'password_changed_at' => 1385225069, @@ -35,6 +37,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_REGISTERED, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1453146616, 'updated_at' => 1453146616, 'password_changed_at' => 1453146616, @@ -48,6 +51,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_REGISTERED, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1457890086, 'updated_at' => 1457890086, ], @@ -60,6 +64,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1462891432, 'updated_at' => 1462891432, ], @@ -72,6 +77,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1462891612, 'updated_at' => 1462891612, ], @@ -84,6 +90,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1463427287, 'updated_at' => 1463427287, ], @@ -96,6 +103,7 @@ return [ 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, 'lang' => 'en', 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, 'created_at' => 1463349615, 'updated_at' => 1463349615, ], diff --git a/tests/codeception/common/unit/models/AccountTest.php b/tests/codeception/common/unit/models/AccountTest.php index 3dbaad9..e00afdf 100644 --- a/tests/codeception/common/unit/models/AccountTest.php +++ b/tests/codeception/common/unit/models/AccountTest.php @@ -8,6 +8,7 @@ use tests\codeception\common\fixtures\AccountFixture; use tests\codeception\common\fixtures\MojangUsernameFixture; use tests\codeception\common\unit\DbTestCase; use Yii; +use const common\LATEST_RULES_VERSION; /** * @property array $accounts @@ -176,4 +177,29 @@ class AccountTest extends DbTestCase { }); } + public function testGetProfileLink() { + $model = new Account(); + $model->id = '123'; + $this->assertEquals('http://ely.by/u123', $model->getProfileLink()); + } + + public function testIsAgreedWithActualRules() { + $this->specify('get false, if rules field set in null', function() { + $model = new Account(); + expect($model->isAgreedWithActualRules())->false(); + }); + + $this->specify('get false, if rules field have version less, then actual', function() { + $model = new Account(); + $model->rules_agreement_version = 0; + expect($model->isAgreedWithActualRules())->false(); + }); + + $this->specify('get true, if rules field have equals rules version', function() { + $model = new Account(); + $model->rules_agreement_version = LATEST_RULES_VERSION; + expect($model->isAgreedWithActualRules())->true(); + }); + } + } From 16fc1ecb8cc4ec9c7827772c98914b191151bec0 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Sat, 6 Aug 2016 19:22:09 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20action=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D1=8F=D1=82=D0=B8=D1=8F=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20+=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=B3=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/controllers/AccountsController.php | 20 ++++++++++- api/models/profile/AcceptRulesForm.php | 35 +++++++++++++++++++ .../codeception/api/_pages/AccountsRoute.php | 5 +++ .../functional/AccountsAcceptRulesCest.php | 28 +++++++++++++++ .../models/profile/AcceptRulesFormTest.php | 33 +++++++++++++++++ .../common/fixtures/data/accounts.php | 13 +++++++ 6 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 api/models/profile/AcceptRulesForm.php create mode 100644 tests/codeception/api/functional/AccountsAcceptRulesCest.php create mode 100644 tests/codeception/api/unit/models/profile/AcceptRulesFormTest.php diff --git a/api/controllers/AccountsController.php b/api/controllers/AccountsController.php index 2861d3c..e349d18 100644 --- a/api/controllers/AccountsController.php +++ b/api/controllers/AccountsController.php @@ -1,6 +1,7 @@ AccessControl::class, 'rules' => [ [ - 'actions' => ['current'], + 'actions' => ['current', 'accept-rules'], 'allow' => true, 'roles' => ['@'], ], @@ -57,6 +58,7 @@ class AccountsController extends Controller { 'change-email-submit-new-email' => ['POST'], 'change-email-confirm-new-email' => ['POST'], 'change-lang' => ['POST'], + 'accept-rules' => ['POST'], ]; } @@ -185,4 +187,20 @@ class AccountsController extends Controller { ]; } + public function actionAcceptRules() { + $account = Yii::$app->user->identity; + $model = new AcceptRulesForm($account); + $model->load(Yii::$app->request->post()); + if (!$model->agreeWithLatestRules()) { + return [ + 'success' => false, + 'errors' => $this->normalizeModelErrors($model->getErrors()), + ]; + } + + return [ + 'success' => true, + ]; + } + } diff --git a/api/models/profile/AcceptRulesForm.php b/api/models/profile/AcceptRulesForm.php new file mode 100644 index 0000000..05785f0 --- /dev/null +++ b/api/models/profile/AcceptRulesForm.php @@ -0,0 +1,35 @@ +account = $account; + parent::__construct($config); + } + + public function agreeWithLatestRules() : bool { + $account = $this->getAccount(); + $account->rules_agreement_version = LATEST_RULES_VERSION; + if (!$account->save()) { + throw new ErrorException('Cannot set user rules version'); + } + + return true; + } + + public function getAccount() : Account { + return $this->account; + } + +} diff --git a/tests/codeception/api/_pages/AccountsRoute.php b/tests/codeception/api/_pages/AccountsRoute.php index 7b4938b..5ff4a3b 100644 --- a/tests/codeception/api/_pages/AccountsRoute.php +++ b/tests/codeception/api/_pages/AccountsRoute.php @@ -59,4 +59,9 @@ class AccountsRoute extends BasePage { ]); } + public function acceptRules() { + $this->route = ['accounts/accept-rules']; + $this->actor->sendPOST($this->getUrl()); + } + } diff --git a/tests/codeception/api/functional/AccountsAcceptRulesCest.php b/tests/codeception/api/functional/AccountsAcceptRulesCest.php new file mode 100644 index 0000000..4f6fee7 --- /dev/null +++ b/tests/codeception/api/functional/AccountsAcceptRulesCest.php @@ -0,0 +1,28 @@ +route = new AccountsRoute($I); + } + + public function testCurrent(FunctionalTester $I) { + $I->loggedInAsActiveAccount('Veleyaba', 'password_0'); + $this->route->acceptRules(); + $I->canSeeResponseCodeIs(200); + $I->canSeeResponseIsJson(); + $I->canSeeResponseContainsJson([ + 'success' => true, + ]); + } + +} diff --git a/tests/codeception/api/unit/models/profile/AcceptRulesFormTest.php b/tests/codeception/api/unit/models/profile/AcceptRulesFormTest.php new file mode 100644 index 0000000..2105a40 --- /dev/null +++ b/tests/codeception/api/unit/models/profile/AcceptRulesFormTest.php @@ -0,0 +1,33 @@ + AccountFixture::class, + ]; + } + + public function testApplyLanguage() { + $this->specify('rules version bumped to latest', function() { + /** @var Account $account */ + $account = Account::findOne($this->accounts['account-with-old-rules-version']); + $model = new AcceptRulesForm($account); + expect($model->agreeWithLatestRules())->true(); + expect($account->rules_agreement_version)->equals(LATEST_RULES_VERSION); + }); + } + +} diff --git a/tests/codeception/common/fixtures/data/accounts.php b/tests/codeception/common/fixtures/data/accounts.php index b4f66f9..cde12ff 100644 --- a/tests/codeception/common/fixtures/data/accounts.php +++ b/tests/codeception/common/fixtures/data/accounts.php @@ -107,4 +107,17 @@ return [ 'created_at' => 1463349615, 'updated_at' => 1463349615, ], + 'account-with-old-rules-version' => [ + 'id' => 9, + 'uuid' => '410462d3-8e71-47cc-bac6-64f77f88cf80', + 'username' => 'Veleyaba', + 'email' => 'veleyaba@gmail.com', + 'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0 + 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, + 'lang' => 'en', + 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => null, + 'created_at' => 1470499952, + 'updated_at' => 1470499952, + ], ];