From c28b8bdd9e3ca7d737cb34cafede784e6170958f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 1 Sep 2024 19:32:15 +0600 Subject: [PATCH] Add Bitrix24Account entity and unit tests This commit introduces the `Bitrix24Account` entity with full implementation for managing Bitrix24 account statuses, auth tokens, and domain URLs. It also includes unit tests for the added entity, and updates the `composer.json` to reflect changes in namespace configurations. Signed-off-by: mesilov --- composer.json | 6 +- .../Entity/Bitrix24Account.php | 298 ++++++++++++++++++ .../Entity/Bitrix24AccountTest.php | 59 ++++ 3 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 src/Bitrix24Accounts/Entity/Bitrix24Account.php create mode 100644 tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php diff --git a/composer.json b/composer.json index 15096b4..593339e 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,6 @@ "doctrine/doctrine-migrations-bundle": "^3", "symfony/event-dispatcher": "^7", "symfony/uid": "^7", - "symfony/uid": "^7", "knplabs/knp-paginator-bundle": "^6" }, "require-dev": { @@ -57,12 +56,13 @@ }, "autoload": { "psr-4": { - "Mesilov\\Bitrix24\\ApplicationCore\\": "src" + "Bitrix24\\SDK\\ApplicationCore\\": "src" } }, "autoload-dev": { "psr-4": { - "Mesilov\\Bitrix24\\ApplicationCore\\Tests\\": "tests" + "Bitrix24\\SDK\\ApplicationCore\\Tests\\": "tests", + "Bitrix24\\SDK\\Tests\\":"vendor/mesilov/bitrix24-php-sdk/tests" } } } diff --git a/src/Bitrix24Accounts/Entity/Bitrix24Account.php b/src/Bitrix24Accounts/Entity/Bitrix24Account.php new file mode 100644 index 0000000..a1a5dac --- /dev/null +++ b/src/Bitrix24Accounts/Entity/Bitrix24Account.php @@ -0,0 +1,298 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\ApplicationCore\Bitrix24Accounts\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; + +class Bitrix24Account implements Bitrix24AccountInterface +{ + private string $accessToken; + + private string $refreshToken; + + private int $expires; + + private array $applicationScope; + + private ?string $applicationToken = null; + + private ?string $comment = null; + + public function __construct( + private readonly Uuid $id, + private readonly int $bitrix24UserId, + private readonly bool $isBitrix24UserAdmin, + private readonly string $memberId, + private string $domainUrl, + private Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + private readonly CarbonImmutable $createdAt, + private CarbonImmutable $updatedAt, + private int $applicationVersion, + Scope $applicationScope, + ) + { + $this->accessToken = $authToken->getAccessToken(); + $this->refreshToken = $authToken->getRefreshToken(); + $this->expires = $authToken->getExpires(); + $this->applicationScope = $applicationScope->getScopeCodes(); + } + + #[\Override] + public function getId(): Uuid + { + return $this->id; + } + + #[\Override] + public function getBitrix24UserId(): int + { + return $this->bitrix24UserId; + } + + #[\Override] + public function isBitrix24UserAdmin(): bool + { + return $this->isBitrix24UserAdmin; + } + + #[\Override] + public function getMemberId(): string + { + return $this->memberId; + } + + #[\Override] + public function getDomainUrl(): string + { + return $this->domainUrl; + } + + #[\Override] + public function getStatus(): Bitrix24AccountStatus + { + return $this->accountStatus; + } + + #[\Override] + public function getAuthToken(): AuthToken + { + return new AuthToken($this->accessToken, $this->refreshToken, $this->expires); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function renewAuthToken(RenewedAuthToken $renewedAuthToken): void + { + if ($this->memberId !== $renewedAuthToken->memberId) { + throw new InvalidArgumentException( + sprintf( + 'member id %s for bitrix24 account %s for domain %s mismatch with member id %s for renewed access token', + $this->memberId, + $this->id->toRfc4122(), + $this->domainUrl, + $renewedAuthToken->memberId, + ) + ); + } + + $this->accessToken = $renewedAuthToken->authToken->getAccessToken(); + $this->refreshToken = $renewedAuthToken->authToken->getRefreshToken(); + $this->expires = $renewedAuthToken->authToken->getExpires(); + $this->updatedAt = new CarbonImmutable(); + } + + #[\Override] + public function getApplicationVersion(): int + { + return $this->applicationVersion; + } + + /** + * @throws UnknownScopeCodeException + */ + #[\Override] + public function getApplicationScope(): Scope + { + return new Scope($this->applicationScope); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function changeDomainUrl(string $newDomainUrl): void + { + if ($newDomainUrl === '') { + throw new InvalidArgumentException('new domain url cannot be empty'); + } + + if (Bitrix24AccountStatus::blocked === $this->accountStatus || Bitrix24AccountStatus::deleted === $this->accountStatus) { + throw new InvalidArgumentException( + sprintf( + 'bitrix24 account %s for domain %s must be in active or new state, now account in %s state. domain url cannot be changed', + $this->id->toRfc4122(), + $this->domainUrl, + $this->accountStatus->name + ) + ); + } + + $this->domainUrl = $newDomainUrl; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function applicationInstalled(string $applicationToken): void + { + if (Bitrix24AccountStatus::new !== $this->accountStatus) { + throw new InvalidArgumentException(sprintf( + 'for finish installation bitrix24 account must be in status «new», current status - «%s»', + $this->accountStatus->name)); + } + + if ($applicationToken === '') { + throw new InvalidArgumentException('application token cannot be empty'); + } + + $this->accountStatus = Bitrix24AccountStatus::active; + $this->applicationToken = $applicationToken; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function applicationUninstalled(string $applicationToken): void + { + if ($applicationToken === '') { + throw new InvalidArgumentException('application token cannot be empty'); + } + + if (Bitrix24AccountStatus::active !== $this->accountStatus) { + throw new InvalidArgumentException(sprintf( + 'for uninstall account must be in status «active», current status - «%s»', + $this->accountStatus->name)); + } + + if ($this->applicationToken !== $applicationToken) { + throw new InvalidArgumentException( + sprintf( + 'application token «%s» mismatch with application token «%s» for bitrix24 account %s for domain %s', + $applicationToken, + $this->applicationToken, + $this->id->toRfc4122(), + $this->domainUrl + ) + ); + } + + $this->accountStatus = Bitrix24AccountStatus::deleted; + $this->updatedAt = new CarbonImmutable(); + } + + #[\Override] + public function isApplicationTokenValid(string $applicationToken): bool + { + return $this->applicationToken === $applicationToken; + } + + #[\Override] + public function getCreatedAt(): CarbonImmutable + { + return $this->createdAt; + } + + #[\Override] + public function getUpdatedAt(): CarbonImmutable + { + return $this->updatedAt; + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function updateApplicationVersion(int $version, ?Scope $newScope): void + { + if (Bitrix24AccountStatus::active !== $this->accountStatus) { + throw new InvalidArgumentException(sprintf('account must be in status «active», but now account in status «%s»', $this->accountStatus->name)); + } + + if ($this->applicationVersion >= $version) { + throw new InvalidArgumentException( + sprintf('you cannot downgrade application version or set some version, current version «%s», but you try to upgrade to «%s»', + $this->applicationVersion, + $version)); + } + + $this->applicationVersion = $version; + if ($newScope instanceof \Bitrix24\SDK\Core\Credentials\Scope) { + $this->applicationScope = $newScope->getScopeCodes(); + } + + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function markAsActive(?string $comment): void + { + if (Bitrix24AccountStatus::blocked !== $this->accountStatus) { + throw new InvalidArgumentException( + sprintf('you can activate account only in status blocked, now account in status %s', + $this->accountStatus->name)); + } + + $this->accountStatus = Bitrix24AccountStatus::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function markAsBlocked(?string $comment): void + { + if (Bitrix24AccountStatus::deleted === $this->accountStatus) { + throw new InvalidArgumentException('you cannot block account in status «deleted»'); + } + + $this->accountStatus = Bitrix24AccountStatus::blocked; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + #[\Override] + public function getComment(): ?string + { + return $this->comment; + } +} \ No newline at end of file diff --git a/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php b/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php new file mode 100644 index 0000000..f4986a9 --- /dev/null +++ b/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\ApplicationCore\Tests\Unit\Bitrix24Accounts\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\ApplicationCore\Bitrix24Accounts\Entity\Bitrix24Account; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterfaceTest; +use Carbon\CarbonImmutable; +use Override; +use PHPUnit\Framework\Attributes\CoversClass; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24Account::class)] +class Bitrix24AccountTest extends Bitrix24AccountInterfaceTest +{ + #[Override] + protected function createBitrix24AccountImplementation( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): Bitrix24AccountInterface + { + return new Bitrix24Account( + $uuid, + $bitrix24UserId, + $isBitrix24UserAdmin, + $memberId, + $domainUrl, + $bitrix24AccountStatus, + $authToken, + $createdAt, + $updatedAt, + $applicationVersion, + $applicationScope + ); + } +} \ No newline at end of file