diff --git a/api/config/config-test.php b/api/config/config-test.php index acce9a6..a757f64 100644 --- a/api/config/config-test.php +++ b/api/config/config-test.php @@ -36,6 +36,10 @@ return [ } public function profile(string $username, bool $signed = false): ?array { + if ($username === 'NotSynchronized') { + return null; + } + $account = common\models\Account::findOne(['username' => $username]); $uuid = $account ? str_replace('-', '', $account->uuid) : '00000000000000000000000000000000'; diff --git a/api/tests/functional/sessionserver/ProfileCest.php b/api/tests/functional/sessionserver/ProfileCest.php index d9f6eb1..9b43021 100644 --- a/api/tests/functional/sessionserver/ProfileCest.php +++ b/api/tests/functional/sessionserver/ProfileCest.php @@ -1,4 +1,6 @@ canSeeValidTexturesResponse('Admin', 'df936908b2e1544d96f82977ec213022', true); } + public function getProfileWhichIsNotSynchronized(SessionServerSteps $I) { + $I->wantTo('get info about player textures by uuid'); + $this->route->profile('7ff4a9dcd1774ea0ab567f31218004f9', true); + + // Ensure that empty textures was serialized as an empty object + $I->seeResponseIsJson(); + $I->canSeeResponseContainsJson([ + 'id' => '7ff4a9dcd1774ea0ab567f31218004f9', + ]); + $texturesValue = $I->grabDataFromResponseByJsonPath('$.properties[0].value')[0]; + $texturesJson = base64_decode($texturesValue); + $I->assertStringContainsString('"textures":{}', $texturesJson); + } + public function directCallWithoutUuidPart(FunctionalTester $I) { $I->wantTo('call profile route without passing uuid'); $this->route->profile(''); diff --git a/common/models/Textures.php b/common/models/Textures.php index ec93f2f..0e82bd2 100644 --- a/common/models/Textures.php +++ b/common/models/Textures.php @@ -3,6 +3,7 @@ declare(strict_types=1); namespace common\models; +use ArrayObject; use Carbon\Carbon; use common\components\SkinsSystemApi; use GuzzleHttp\Client as GuzzleHttpClient; @@ -22,7 +23,7 @@ class Textures { $profile = $this->getProfile($signed); if ($profile === null) { // This case shouldn't happen at all, but synchronization isn't perfect and sometimes - // information might be now updated. Provide fallback solution + // information might be not updated. Provide fallback solution $profile = [ 'name' => $this->account->username, 'id' => $uuid, @@ -33,7 +34,7 @@ class Textures { 'timestamp' => Carbon::now()->getPreciseTimestamp(3), 'profileId' => $uuid, 'profileName' => $this->account->username, - 'textures' => [], + 'textures' => new ArrayObject(), // Force {} rather than [] when json_encode ])), ], [ diff --git a/common/tests/fixtures/data/accounts.php b/common/tests/fixtures/data/accounts.php index 0031294..b459414 100644 --- a/common/tests/fixtures/data/accounts.php +++ b/common/tests/fixtures/data/accounts.php @@ -233,4 +233,21 @@ return [ 'password_changed_at' => 1591893532, 'deleted_at' => time(), ], + 'not-synchronized-on-chrly-account' => [ + 'id' => 16, + 'uuid' => '7ff4a9dc-d177-4ea0-ab56-7f31218004f9', + 'username' => 'NotSynchronized', + 'email' => 'not-synchronized@ely.by', + 'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0 + 'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2, + 'lang' => 'ru', + 'status' => \common\models\Account::STATUS_ACTIVE, + 'rules_agreement_version' => \common\LATEST_RULES_VERSION, + 'otp_secret' => null, + 'is_otp_enabled' => false, + 'created_at' => 1670264178, + 'updated_at' => 1670264178, + 'password_changed_at' => 1670264178, + 'deleted_at' => null, + ], ];