diff --git a/src/CrowdinApiClient/Api/ApplicationApi.php b/src/CrowdinApiClient/Api/ApplicationApi.php index 470ee7bd..6e1dd2f3 100644 --- a/src/CrowdinApiClient/Api/ApplicationApi.php +++ b/src/CrowdinApiClient/Api/ApplicationApi.php @@ -4,6 +4,7 @@ namespace CrowdinApiClient\Api; +use CrowdinApiClient\Model\ApplicationConsent; use CrowdinApiClient\Model\ApplicationData; use CrowdinApiClient\Model\ApplicationInstallation; use CrowdinApiClient\ModelCollection; @@ -153,6 +154,62 @@ public function updateInstallation(ApplicationInstallation $installation): ?Appl return $this->_update('applications/installations/' . $installation->getIdentifier(), $installation); } + /** + * List Application Consents + * @link https://developer.crowdin.com/api/v2/#operation/api.applications.consents.getMany API Documentation + * + * @param array $params + * integer $params[limit]
+ * integer $params[offset]
+ * string $params[identifier]
+ * string $params[orderBy] + * @return ModelCollection + */ + public function listConsents(array $params = []): ModelCollection + { + return $this->_list('applications/consents', ApplicationConsent::class, $params); + } + + /** + * Add Application Consent + * @link https://developer.crowdin.com/api/v2/#operation/api.applications.consents.post API Documentation + * + * @param array $data + * string $data[identifier] required
+ * integer $data[installedBy] required
+ * string $data[status] required
+ * array $data[scopes] + * @return ApplicationConsent|null + */ + public function addConsent(array $data): ?ApplicationConsent + { + return $this->_create('applications/consents', ApplicationConsent::class, $data); + } + + /** + * Edit Application Consent + * @link https://developer.crowdin.com/api/v2/#operation/api.applications.consents.patch API Documentation + * + * @param ApplicationConsent $consent + * @return ApplicationConsent|null + */ + public function updateConsent(ApplicationConsent $consent): ?ApplicationConsent + { + return $this->_update('applications/consents/' . $consent->getId(), $consent); + } + + /** + * Delete Application Consent + * @link https://developer.crowdin.com/api/v2/#operation/api.applications.consents.delete API Documentation + * + * @param int $consentId + * @return mixed + */ + public function deleteConsent(int $consentId) + { + return $this->_delete('applications/consents/' . $consentId); + } + /** * Edit Application Data * @link https://developer.crowdin.com/api/v2/#operation/api.applications.api.patch API Documentation diff --git a/src/CrowdinApiClient/Model/ApplicationConsent.php b/src/CrowdinApiClient/Model/ApplicationConsent.php new file mode 100644 index 00000000..bef06581 --- /dev/null +++ b/src/CrowdinApiClient/Model/ApplicationConsent.php @@ -0,0 +1,99 @@ +id = (int)$this->getDataProperty('id'); + $this->installedBy = $this->getDataProperty('installedBy'); + $this->identifier = (string)$this->getDataProperty('identifier'); + $this->name = $this->getDataProperty('name'); + $this->status = (string)$this->getDataProperty('status'); + $this->scopes = (array)$this->getDataProperty('scopes'); + $this->createdAt = (string)$this->getDataProperty('createdAt'); + $this->updatedAt = (string)$this->getDataProperty('updatedAt'); + } + + public function getId(): int + { + return $this->id; + } + + /** + * @return array|null + */ + public function getInstalledBy(): ?array + { + return $this->installedBy; + } + + public function getIdentifier(): string + { + return $this->identifier; + } + + public function getName(): ?string + { + return $this->name; + } + + public function getStatus(): string + { + return $this->status; + } + + public function getScopes(): array + { + return $this->scopes; + } + + public function getCreatedAt(): string + { + return $this->createdAt; + } + + public function getUpdatedAt(): string + { + return $this->updatedAt; + } + + public function setStatus(string $status): void + { + $this->status = $status; + } + + public function setScopes(array $scopes): void + { + $this->scopes = $scopes; + } +} diff --git a/tests/CrowdinApiClient/Api/ApplicationApiTest.php b/tests/CrowdinApiClient/Api/ApplicationApiTest.php index a2cceef0..a904170d 100644 --- a/tests/CrowdinApiClient/Api/ApplicationApiTest.php +++ b/tests/CrowdinApiClient/Api/ApplicationApiTest.php @@ -4,6 +4,7 @@ namespace CrowdinApiClient\Tests\Api; +use CrowdinApiClient\Model\ApplicationConsent; use CrowdinApiClient\Model\ApplicationData; use CrowdinApiClient\Model\ApplicationInstallation; use CrowdinApiClient\ModelCollection; @@ -54,6 +55,30 @@ protected function getInstallationResponseJson(): string return json_encode(['data' => $this->getInstallationData()]); } + protected function getConsentData(): array + { + return [ + 'id' => 12, + 'installedBy' => [ + 'id' => 1, + 'username' => 'admin', + 'fullName' => 'Admin User', + 'avatarUrl' => '', + ], + 'identifier' => 'my-app', + 'name' => 'My Application', + 'status' => 'granted', + 'scopes' => ['project', 'tm'], + 'createdAt' => '2026-07-24T10:00:00+00:00', + 'updatedAt' => '2026-07-24T10:00:00+00:00', + ]; + } + + protected function getConsentResponseJson(): string + { + return json_encode(['data' => $this->getConsentData()]); + } + public function testListInstallations(): void { $this->mockRequest([ @@ -131,6 +156,92 @@ public function testUpdateInstallation(): void $this->assertEquals('my-app', $result->getIdentifier()); } + public function testListConsents(): void + { + $this->mockRequest([ + 'uri' => 'https://api.crowdin.com/api/v2/applications/consents?identifier=my-app&orderBy=createdAt', + 'method' => 'get', + 'response' => json_encode([ + 'data' => [ + ['data' => $this->getConsentData()], + ], + 'pagination' => [['offset' => 0, 'limit' => 25]], + ]), + ]); + + $list = $this->crowdin->application->listConsents([ + 'identifier' => 'my-app', + 'orderBy' => 'createdAt', + ]); + + $this->assertInstanceOf(ModelCollection::class, $list); + $this->assertCount(1, $list); + $this->assertInstanceOf(ApplicationConsent::class, $list[0]); + $this->assertEquals(12, $list[0]->getId()); + $this->assertEquals('my-app', $list[0]->getIdentifier()); + } + + public function testAddConsent(): void + { + $requestBody = [ + 'identifier' => 'my-app', + 'installedBy' => 1, + 'status' => 'granted', + 'scopes' => ['project', 'tm'], + ]; + + $this->mockRequest([ + 'path' => '/applications/consents', + 'method' => 'post', + 'body' => json_encode($requestBody), + 'response' => $this->getConsentResponseJson(), + ]); + + $consent = $this->crowdin->application->addConsent($requestBody); + + $this->assertInstanceOf(ApplicationConsent::class, $consent); + $this->assertEquals(12, $consent->getId()); + $this->assertEquals('granted', $consent->getStatus()); + } + + public function testUpdateConsent(): void + { + $consentData = $this->getConsentData(); + $consent = new ApplicationConsent($consentData); + $consent->setStatus('denied'); + $consent->setScopes(['project']); + + $this->mockRequest([ + 'path' => '/applications/consents/12', + 'method' => 'patch', + 'body' => json_encode([ + [ + 'op' => 'replace', + 'path' => '/status', + 'value' => 'denied', + ], + [ + 'op' => 'replace', + 'path' => '/scopes', + 'value' => ['project'], + ], + ]), + 'response' => $this->getConsentResponseJson(), + ]); + + $result = $this->crowdin->application->updateConsent($consent); + + $this->assertInstanceOf(ApplicationConsent::class, $result); + $this->assertEquals(12, $result->getId()); + } + + public function testDeleteConsent(): void + { + $this->mockRequestDelete('/applications/consents/12'); + + $this->crowdin->application->deleteConsent(12); + } + public function testGetApplicationData(): void { $this->mockRequestGet( diff --git a/tests/CrowdinApiClient/Model/ApplicationConsentTest.php b/tests/CrowdinApiClient/Model/ApplicationConsentTest.php new file mode 100644 index 00000000..b14a9d77 --- /dev/null +++ b/tests/CrowdinApiClient/Model/ApplicationConsentTest.php @@ -0,0 +1,66 @@ + 12, + 'installedBy' => [ + 'id' => 1, + 'username' => 'admin', + 'fullName' => 'Admin User', + 'avatarUrl' => '', + ], + 'identifier' => 'my-app', + 'name' => 'My Application', + 'status' => 'granted', + 'scopes' => ['project', 'tm'], + 'createdAt' => '2026-07-24T10:00:00+00:00', + 'updatedAt' => '2026-07-24T10:00:00+00:00', + ]; + + public function testLoadData(): void + { + $consent = new ApplicationConsent($this->data); + + $this->assertEquals(12, $consent->getId()); + $this->assertEquals($this->data['installedBy'], $consent->getInstalledBy()); + $this->assertEquals('my-app', $consent->getIdentifier()); + $this->assertEquals('My Application', $consent->getName()); + $this->assertEquals('granted', $consent->getStatus()); + $this->assertEquals(['project', 'tm'], $consent->getScopes()); + $this->assertEquals($this->data['createdAt'], $consent->getCreatedAt()); + $this->assertEquals($this->data['updatedAt'], $consent->getUpdatedAt()); + } + + public function testLoadDataWithoutOptionalFields(): void + { + $consent = new ApplicationConsent([ + 'id' => 12, + 'identifier' => 'my-app', + 'status' => 'denied', + 'scopes' => [], + 'createdAt' => '2026-07-24T10:00:00+00:00', + 'updatedAt' => '2026-07-24T10:00:00+00:00', + ]); + + $this->assertNull($consent->getInstalledBy()); + $this->assertNull($consent->getName()); + } + + public function testSetData(): void + { + $consent = new ApplicationConsent($this->data); + $consent->setStatus('denied'); + $consent->setScopes(['project']); + + $this->assertEquals('denied', $consent->getStatus()); + $this->assertEquals(['project'], $consent->getScopes()); + } +}