diff --git a/src/Api/HttpApi.php b/src/Api/HttpApi.php index 25a14c1..e6d8b91 100644 --- a/src/Api/HttpApi.php +++ b/src/Api/HttpApi.php @@ -69,7 +69,7 @@ abstract class HttpApi return $response; } - if (200 !== $response->getStatusCode() && 201 !== $response->getStatusCode()) { + if (!in_array($response->getStatusCode(), [200, 201, 202], true)) { $this->handleErrors($response); } diff --git a/src/Api/Suppression.php b/src/Api/Suppression.php index 4147fdb..550a46c 100644 --- a/src/Api/Suppression.php +++ b/src/Api/Suppression.php @@ -14,6 +14,7 @@ namespace Mailgun\Api; use Mailgun\Api\Suppression\Bounce; use Mailgun\Api\Suppression\Complaint; use Mailgun\Api\Suppression\Unsubscribe; +use Mailgun\Api\Suppression\Whitelist; use Mailgun\HttpClient\RequestBuilder; use Mailgun\Hydrator\Hydrator; use Psr\Http\Client\ClientInterface; @@ -61,4 +62,9 @@ class Suppression { return new Unsubscribe($this->httpClient, $this->requestBuilder, $this->hydrator); } + + public function whitelists(): Whitelist + { + return new Whitelist($this->httpClient, $this->requestBuilder, $this->hydrator); + } } diff --git a/src/Api/Suppression/Whitelist.php b/src/Api/Suppression/Whitelist.php new file mode 100644 index 0000000..5c8e54b --- /dev/null +++ b/src/Api/Suppression/Whitelist.php @@ -0,0 +1,149 @@ + + */ +class Whitelist extends HttpApi +{ + use Pagination; + + /** + * @param string $domain Domain to get whitelist for + * @param int $limit optional + * + * @return IndexResponse + */ + public function index(string $domain, int $limit = 100) + { + Assert::stringNotEmpty($domain); + Assert::range($limit, 1, 10000, 'Limit parameter must be between 1 and 10000'); + + $params = [ + 'limit' => $limit, + ]; + + $response = $this->httpGet(sprintf('/v3/%s/whitelists', $domain), $params); + + return $this->hydrateResponse($response, IndexResponse::class); + } + + /** + * @param string $domain Domain to show whitelist for + * @param string $address whitelist address + * + * @return ShowResponse + */ + public function show(string $domain, string $address) + { + Assert::stringNotEmpty($domain); + Assert::stringNotEmpty($address); + + $response = $this->httpGet(sprintf('/v3/%s/whitelists/%s', $domain, $address)); + + return $this->hydrateResponse($response, ShowResponse::class); + } + + /** + * @param string $domain Domain to create whitelist for + * @param string $address whitelist email address or domain name + * @param array $params optional + * + * @return CreateResponse + */ + public function create(string $domain, string $address, array $params = []) + { + Assert::stringNotEmpty($domain); + Assert::stringNotEmpty($address); + + if (false !== filter_var($address, FILTER_VALIDATE_EMAIL)) { + $params['address'] = $address; + } elseif (false !== filter_var($address, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) { + $params['domain'] = $address; + } else { + throw new InvalidArgumentException('Address should be valid email or domain name'); + } + + $response = $this->httpPost(sprintf('/v3/%s/whitelists', $domain), $params); + + return $this->hydrateResponse($response, CreateResponse::class); + } + + /** + * @param string $domain Domain to create whitelist for + * @param string $filePath csv file path + * @param array $params optional + * + * @return ImportResponse + */ + public function import(string $domain, string $filePath, array $params = []) + { + Assert::stringNotEmpty($domain); + Assert::stringNotEmpty($filePath); + Assert::fileExists($filePath); + + $response = $this->httpPost( + sprintf('/v3/%s/whitelists/import', $domain), + ['file' => fopen($filePath, 'r')], + array_merge($params, [ + 'filename' => basename($filePath), + ]) + ); + + return $this->hydrateResponse($response, ImportResponse::class); + } + + /** + * @param string $domain Domain to delete whitelist for + * @param string $address whitelist address + * @param array $params optional + * + * @return DeleteResponse + */ + public function delete(string $domain, string $address, array $params = []) + { + Assert::stringNotEmpty($domain); + Assert::stringNotEmpty($address); + + $response = $this->httpDelete(sprintf('/v3/%s/whitelists/%s', $domain, $address), $params); + + return $this->hydrateResponse($response, DeleteResponse::class); + } + + /** + * @param string $domain Domain to delete all whitelists for + * + * @return DeleteAllResponse + */ + public function deleteAll(string $domain) + { + Assert::stringNotEmpty($domain); + + $response = $this->httpDelete(sprintf('/v3/%s/whitelists', $domain)); + + return $this->hydrateResponse($response, DeleteAllResponse::class); + } +} diff --git a/src/Model/Suppression/Whitelist/CreateResponse.php b/src/Model/Suppression/Whitelist/CreateResponse.php new file mode 100644 index 0000000..7880925 --- /dev/null +++ b/src/Model/Suppression/Whitelist/CreateResponse.php @@ -0,0 +1,53 @@ + + */ +final class CreateResponse implements ApiResponse +{ + private $type; + private $value; + private $message; + + final private function __construct() + { + } + + public static function create(array $data): self + { + $model = new static(); + $model->type = $data['type'] ?? ''; + $model->value = $data['value'] ?? ''; + $model->message = $data['message'] ?? ''; + + return $model; + } + + public function getType(): string + { + return $this->type; + } + + public function getValue(): string + { + return $this->value; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/src/Model/Suppression/Whitelist/DeleteAllResponse.php b/src/Model/Suppression/Whitelist/DeleteAllResponse.php new file mode 100644 index 0000000..fd9b121 --- /dev/null +++ b/src/Model/Suppression/Whitelist/DeleteAllResponse.php @@ -0,0 +1,39 @@ + + */ +final class DeleteAllResponse implements ApiResponse +{ + private $message; + + final private function __construct() + { + } + + public static function create(array $data): self + { + $model = new static(); + $model->message = $data['message'] ?? ''; + + return $model; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/src/Model/Suppression/Whitelist/DeleteResponse.php b/src/Model/Suppression/Whitelist/DeleteResponse.php new file mode 100644 index 0000000..441725c --- /dev/null +++ b/src/Model/Suppression/Whitelist/DeleteResponse.php @@ -0,0 +1,46 @@ + + */ +final class DeleteResponse implements ApiResponse +{ + private $value; + private $message; + + final private function __construct() + { + } + + public static function create(array $data): self + { + $model = new static(); + $model->value = $data['value'] ?? ''; + $model->message = $data['message'] ?? ''; + + return $model; + } + + public function getValue(): string + { + return $this->value; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/src/Model/Suppression/Whitelist/ImportResponse.php b/src/Model/Suppression/Whitelist/ImportResponse.php new file mode 100644 index 0000000..eb91af2 --- /dev/null +++ b/src/Model/Suppression/Whitelist/ImportResponse.php @@ -0,0 +1,39 @@ + + */ +final class ImportResponse implements ApiResponse +{ + private $message; + + final private function __construct() + { + } + + public static function create(array $data): self + { + $model = new static(); + $model->message = $data['message'] ?? null; + + return $model; + } + + public function getMessage(): ?string + { + return $this->message; + } +} diff --git a/src/Model/Suppression/Whitelist/IndexResponse.php b/src/Model/Suppression/Whitelist/IndexResponse.php new file mode 100644 index 0000000..613ec80 --- /dev/null +++ b/src/Model/Suppression/Whitelist/IndexResponse.php @@ -0,0 +1,77 @@ + + */ +final class IndexResponse implements ApiResponse, PagingProvider +{ + use PaginationResponse; + + /** + * Array to store a list of whitelist items from + * index response. + * + * @var Whitelist[] + */ + private $items = []; + + /** + * Store the total number of whitelists items. + * + * @var int + */ + private $totalCount; + + private function __construct() + { + } + + public static function create(array $data): self + { + $whitelists = []; + + if (isset($data['items'])) { + foreach ($data['items'] as $item) { + $whitelists[] = Whitelist::create($item); + } + } + + $model = new self(); + $model->items = $whitelists; + $model->paging = $data['paging']; + + return $model; + } + + /** + * @return Whitelist[] + */ + public function getItems(): array + { + return $this->items; + } + + public function getTotalCount(): int + { + if (null === $this->totalCount) { + $this->totalCount = count($this->items); + } + + return $this->totalCount; + } +} diff --git a/src/Model/Suppression/Whitelist/ShowResponse.php b/src/Model/Suppression/Whitelist/ShowResponse.php new file mode 100644 index 0000000..c7ae400 --- /dev/null +++ b/src/Model/Suppression/Whitelist/ShowResponse.php @@ -0,0 +1,21 @@ + + */ +final class ShowResponse extends Whitelist implements ApiResponse +{ +} diff --git a/src/Model/Suppression/Whitelist/Whitelist.php b/src/Model/Suppression/Whitelist/Whitelist.php new file mode 100644 index 0000000..6df53af --- /dev/null +++ b/src/Model/Suppression/Whitelist/Whitelist.php @@ -0,0 +1,60 @@ + + */ +class Whitelist +{ + private $value; + private $reason; + private $type; + private $createdAt; + + private function __construct() + { + } + + public static function create(array $data): self + { + $model = new self(); + $model->value = $data['value'] ?? null; + $model->reason = $data['reason'] ?? null; + $model->type = $data['type'] ?? null; + $model->createdAt = isset($data['createdAt']) ? new DateTimeImmutable($data['createdAt']) : null; + + return $model; + } + + public function getValue(): ?string + { + return $this->value; + } + + public function getReason(): ?string + { + return $this->reason; + } + + public function getType(): ?string + { + return $this->type; + } + + public function getCreatedAt(): ?DateTimeImmutable + { + return $this->createdAt; + } +} diff --git a/tests/Api/Suppression/WhitelistTest.php b/tests/Api/Suppression/WhitelistTest.php new file mode 100644 index 0000000..eb040f2 --- /dev/null +++ b/tests/Api/Suppression/WhitelistTest.php @@ -0,0 +1,134 @@ + + */ +class WhitelistTest extends TestCase +{ + public function testIndex() + { + $this->setRequestMethod('GET'); + $this->setRequestUri('/v3/example.com/whitelists?limit=25'); + $this->setHydrateClass(IndexResponse::class); + + $api = $this->getApiInstance(); + $api->index('example.com', 25); + } + + public function testShow() + { + $this->setRequestMethod('GET'); + $this->setRequestUri('/v3/example.com/whitelists/foo@bar.com'); + $this->setHydrateClass(ShowResponse::class); + + $api = $this->getApiInstance(); + $api->show('example.com', 'foo@bar.com'); + } + + public function testCreateDomain() + { + $this->setRequestMethod('POST'); + $this->setRequestUri('/v3/example.com/whitelists'); + $this->setHydrateClass(CreateResponse::class); + $this->setRequestBody([ + 'address' => 'foo@bar.com', + ]); + + $api = $this->getApiInstance(); + $api->create('example.com', 'foo@bar.com'); + } + + public function testCreateEmail() + { + $this->setRequestMethod('POST'); + $this->setRequestUri('/v3/example.com/whitelists'); + $this->setHydrateClass(CreateResponse::class); + $this->setRequestBody([ + 'domain' => 'foobar.com', + ]); + + $api = $this->getApiInstance(); + $api->create('example.com', 'foobar.com'); + } + + public function testCreateNonValidDomainOrAddress() + { + $this->expectException(\InvalidArgumentException::class); + + $api = $this->getApiInstance(); + $api->create('example.com', '_123'); + } + + public function testImport() + { + $this->setRequestMethod('POST'); + $this->setRequestUri('/v3/example.com/whitelists/import'); + $this->setHydrateClass(ImportResponse::class); + $this->setRequestBody([ + 'file' => 'resource', + ]); + $this->setRequestHeaders([ + 'filename' => basename(__FILE__), + ]); + + $api = $this->getApiInstance(); + $api->import('example.com', __FILE__); + } + + public function testDelete() + { + $this->setRequestMethod('DELETE'); + $this->setRequestUri('/v3/example.com/whitelists/foo@bar.com'); + $this->setHydrateClass(DeleteResponse::class); + + $api = $this->getApiInstance(); + $api->delete('example.com', 'foo@bar.com'); + } + + public function testDeleteDomain() + { + $this->setRequestMethod('DELETE'); + $this->setRequestUri('/v3/example.com/whitelists/foobar.com'); + $this->setHydrateClass(DeleteResponse::class); + + $api = $this->getApiInstance(); + $api->delete('example.com', 'foobar.com'); + } + + public function testDeleteAll() + { + $this->setRequestMethod('DELETE'); + $this->setRequestUri('/v3/example.com/whitelists'); + $this->setHydrateClass(DeleteAllResponse::class); + + $api = $this->getApiInstance(); + $api->deleteAll('example.com'); + } + + /** + * {@inheritdoc} + */ + protected function getApiClass() + { + return Whitelist::class; + } +} diff --git a/tests/Api/SuppressionTest.php b/tests/Api/SuppressionTest.php index 21a5b26..d1dd7c5 100644 --- a/tests/Api/SuppressionTest.php +++ b/tests/Api/SuppressionTest.php @@ -36,6 +36,12 @@ class SuppressionTest extends TestCase $this->assertInstanceOf(Suppression\Unsubscribe::class, $api->unsubscribes()); } + public function testWhitelists() + { + $api = $this->getApiInstance(); + $this->assertInstanceOf(Suppression\Whitelist::class, $api->whitelists()); + } + /** * {@inheritdoc} */ diff --git a/tests/Model/Suppression/Whitelists/CreateResponseTest.php b/tests/Model/Suppression/Whitelists/CreateResponseTest.php new file mode 100644 index 0000000..962d2ab --- /dev/null +++ b/tests/Model/Suppression/Whitelists/CreateResponseTest.php @@ -0,0 +1,35 @@ +assertEquals('Address/Domain has been added to the whitelists table', $model->getMessage()); + $this->assertEquals('domain', $model->getType()); + $this->assertEquals('example.com', $model->getValue()); + } +} diff --git a/tests/Model/Suppression/Whitelists/DeleteAllResponseTest.php b/tests/Model/Suppression/Whitelists/DeleteAllResponseTest.php new file mode 100644 index 0000000..2ef8f51 --- /dev/null +++ b/tests/Model/Suppression/Whitelists/DeleteAllResponseTest.php @@ -0,0 +1,31 @@ +assertEquals('Whitelist addresses/domains for this domain have been removed', $model->getMessage()); + } +} diff --git a/tests/Model/Suppression/Whitelists/DeleteResponseTest.php b/tests/Model/Suppression/Whitelists/DeleteResponseTest.php new file mode 100644 index 0000000..dfae2af --- /dev/null +++ b/tests/Model/Suppression/Whitelists/DeleteResponseTest.php @@ -0,0 +1,33 @@ +assertEquals('Whitelist address/domain has been removed', $model->getMessage()); + $this->assertEquals('alice@example.com', $model->getValue()); + } +} diff --git a/tests/Model/Suppression/Whitelists/ImportResponseTest.php b/tests/Model/Suppression/Whitelists/ImportResponseTest.php new file mode 100644 index 0000000..fc15c32 --- /dev/null +++ b/tests/Model/Suppression/Whitelists/ImportResponseTest.php @@ -0,0 +1,31 @@ +assertEquals('file uploaded successfully', $model->getMessage()); + } +} diff --git a/tests/Model/Suppression/Whitelists/IndexResponseTest.php b/tests/Model/Suppression/Whitelists/IndexResponseTest.php new file mode 100644 index 0000000..c05e96e --- /dev/null +++ b/tests/Model/Suppression/Whitelists/IndexResponseTest.php @@ -0,0 +1,72 @@ +assertEquals(2, $model->getTotalCount()); + $this->assertEquals('https://url_to_next_page', $model->getFirstUrl()); + $this->assertEquals('https://url_to_last_page', $model->getLastUrl()); + $this->assertEquals('https://url_to_next_page', $model->getNextUrl()); + $this->assertEquals('https://url_to_previous_page', $model->getPreviousUrl()); + + $items = $model->getItems(); + $this->assertCount(2, $items); + + $item = $items[0]; + $this->assertInstanceOf(Whitelist::class, $item); + $this->assertEquals('alice@example.com', $item->getValue()); + $this->assertEquals('reason of white listing', $item->getReason()); + $this->assertEquals('address', $item->getType()); + $this->assertEquals('2011-10-21 11:02:55', $item->getCreatedAt()->format('Y-m-d H:i:s')); + + $item = $items[1]; + $this->assertInstanceOf(Whitelist::class, $item); + $this->assertEquals('test.com', $item->getValue()); + $this->assertEquals('reason of white listing', $item->getReason()); + $this->assertEquals('domain', $item->getType()); + $this->assertEquals('2012-10-26 11:02:56', $item->getCreatedAt()->format('Y-m-d H:i:s')); + } +} diff --git a/tests/Model/Suppression/Whitelists/ShowResponseTest.php b/tests/Model/Suppression/Whitelists/ShowResponseTest.php new file mode 100644 index 0000000..3d09280 --- /dev/null +++ b/tests/Model/Suppression/Whitelists/ShowResponseTest.php @@ -0,0 +1,37 @@ +assertEquals('alice@example.com', $model->getValue()); + $this->assertEquals('why the record was created', $model->getReason()); + $this->assertEquals('address', $model->getType()); + $this->assertEquals('2011-10-21 11:02:55', $model->getCreatedAt()->format('Y-m-d H:i:s')); + } +} diff --git a/tests/Model/Suppression/Whitelists/WhitelistTest.php b/tests/Model/Suppression/Whitelists/WhitelistTest.php new file mode 100644 index 0000000..fa7bb4c --- /dev/null +++ b/tests/Model/Suppression/Whitelists/WhitelistTest.php @@ -0,0 +1,37 @@ +assertEquals('alice@example.com', $model->getValue()); + $this->assertEquals('why the record was created', $model->getReason()); + $this->assertEquals('address', $model->getType()); + $this->assertEquals('2011-10-21 11:02:55', $model->getCreatedAt()->format('Y-m-d H:i:s')); + } +}