From 7b9574992e24fe8b1d897f58ea42660f182925fa Mon Sep 17 00:00:00 2001 From: pk Date: Fri, 18 Oct 2024 23:20:37 +0200 Subject: [PATCH] Smart SMS v1 --- .env.testing | 1 + .gitignore | 4 + README.md | 100 +++++++++++++ composer.json | 26 ++++ docker-compose.yml | 11 ++ docker/Dockerfile | 20 +++ phpunit.xml | 15 ++ src/DTO/SMSMessage.php | 14 ++ src/Exceptions/BadRequestException.php | 8 + src/Exceptions/Exception.php | 8 + src/Exceptions/ForbiddenException.php | 8 + src/Exceptions/InternalServerException.php | 8 + src/Exceptions/NotFoundException.php | 8 + src/Exceptions/UnathorizedException.php | 8 + src/Requests/MessagingRequest.php | 166 +++++++++++++++++++++ tests/MessagingMockRequestTest.php | 92 ++++++++++++ 16 files changed, 497 insertions(+) create mode 100644 .env.testing create mode 100644 .gitignore create mode 100644 README.md create mode 100644 composer.json create mode 100644 docker-compose.yml create mode 100644 docker/Dockerfile create mode 100644 phpunit.xml create mode 100644 src/DTO/SMSMessage.php create mode 100644 src/Exceptions/BadRequestException.php create mode 100644 src/Exceptions/Exception.php create mode 100644 src/Exceptions/ForbiddenException.php create mode 100644 src/Exceptions/InternalServerException.php create mode 100644 src/Exceptions/NotFoundException.php create mode 100644 src/Exceptions/UnathorizedException.php create mode 100644 src/Requests/MessagingRequest.php create mode 100644 tests/MessagingMockRequestTest.php diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000..9ec7e9d --- /dev/null +++ b/.env.testing @@ -0,0 +1 @@ +APP_ENV=development \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b3bffe --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +vendor +.env +composer.lock +/.phpunit.result.cache diff --git a/README.md b/README.md new file mode 100644 index 0000000..6eb8e87 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# Orange SmartSMS API Client + +A PHP client to interact with the Orange SmartSMS API. This package allows you to send SMS messages, check their delivery status, and monitor API usage limits. + +## Features + +- Send SMS messages to various networks. +- Check the delivery status of previously sent SMS messages. +- Retrieve the usage limit and available requests for the SmartSMS API. + +## Installation + +1. Install via Composer: + + ```bash + composer require kwarcek/orange-smartsms-api + ``` + +## Usage + +### 1. Send an SMS Message + +You can send an SMS message by using the `sendSMS` method. The message will be delivered to the recipient's mobile phone. + +#### Example: + +```php +use Kwarcek\OrangeSmartsmsApi\Requests\MessagingRequest; +use Kwarcek\OrangeSmartsmsApi\DTO\SMSMessage; +use GuzzleHttp\Client; + +$isDev = getenv('APP_ENV'); + +// Create a new Guzzle client and MessagingRequest instance +$client = new Client([ + 'base_uri' => $isDev ? 'https://apib2b-test.orange.pl/' : 'https://apib2b.orange.pl/', +]); +$apiKey = 'your-api-key-here'; + +$messagingRequest = new MessagingRequest($client, $apiKey); + +// Define the SMS message +$message = new SMSMessage([ + 'sender' => 'YourSenderID', + 'recipient' => '48510123456', // Recipient's phone number + 'content' => 'Hello from Orange SmartSMS!', +]); + +// Send the SMS +$response = $messagingRequest->sendSMS($message, true); + +print_r($response); +``` + +### 2. Check SMS Delivery Status + +You can check the delivery status of a sent SMS by passing the unique ID returned in the sendSMS response. +Example: + +```php +use Kwarcek\OrangeSmartsmsApi\Requests\MessagingRequest; +use GuzzleHttp\Client; + +$isDev = getenv('APP_ENV'); + +$client = new Client([ + 'base_uri' => $isDev ? 'https://apib2b-test.orange.pl/' : 'https://apib2b.orange.pl/', +]); +$apiKey = 'your-api-key-here'; + +$messagingRequest = new MessagingRequest($client, $apiKey); + +$id = '54510a5d0361'; // Example message ID +$response = $messagingRequest->checkDeliveryStatus($id); + +print_r($response); +``` + +### 3. Check API Usage Limit + +You can check the current API usage limit for SmartSMS, including used and available requests. +Example: + +```php +use Kwarcek\OrangeSmartsmsApi\Requests\MessagingRequest; +use GuzzleHttp\Client; + +$isDev = getenv('APP_ENV'); + +$client = new Client([ + 'base_uri' => $isDev ? 'https://apib2b-test.orange.pl/' : 'https://apib2b.orange.pl/', +]); +$apiKey = 'your-api-key-here'; + +$messagingRequest = new MessagingRequest($client, $apiKey); + +$response = $messagingRequest->checkLimit(); + +print_r($response); +``` \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..1429b70 --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "kwarcek/smart-sms-api", + "description": "A PHP API client for Orange SmartSMS service.", + "type": "library", + "version": "1.0.0", + "require": { + "php": "^8.2", + "guzzlehttp/guzzle": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "autoload": { + "psr-4": { + "Kwarcek\\OrangeSmartsmsApi\\":"src/" + } + }, + "autoload-dev": { + "psr-4": { + "Kwarcek\\OrangeSmartsmsApi\\Test\\": "tests" + } + }, + "scripts": { + "test": "phpunit" + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8303de5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +services: + php: + container_name: orange-smartsms-api + build: + context: . + dockerfile: docker/Dockerfile + env_file: + - .env + tty: true + volumes: + - ./:/app \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..1c14a6b --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,20 @@ +FROM php:8.1 + +WORKDIR /app + +COPY . . + +RUN apt-get update -y && \ + apt-get install git -y + +RUN apt-get update && \ + apt-get install -y libpq-dev \ + unzip \ + zlib1g-dev \ + zlib1g-dev \ + zip \ + --no-install-recommends + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +CMD /bin/bash \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..ab58e17 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,15 @@ + + + + + + ./tests + + + + + + + + \ No newline at end of file diff --git a/src/DTO/SMSMessage.php b/src/DTO/SMSMessage.php new file mode 100644 index 0000000..7100e22 --- /dev/null +++ b/src/DTO/SMSMessage.php @@ -0,0 +1,14 @@ +client->request('GET', 'Messaging/v1/SmartSMS', [ + 'query' => [ + 'from' => $message->sender, + 'to' => $message->recipient, + 'msg' => $message->content, + 'deliverystatus' => $deliveryStatus ? 'true' : 'false', + 'apikey' => $this->apiKey, + ] + ]); + + $data = json_decode($response->getBody()->getContents(), true); + + return [ + 'result' => $data['result'], + 'id' => $data['id'], + 'deliveryStatus' => $data['deliveryStatus'] ?? null + ]; + } catch (RequestException $e) { + return $this->handleError($e); + } + } + + /** + * @param string $id + * @return array{ result: string, address: string, deliveryStatus: string } + * @throws BadRequestException + * @throws Exception + * @throws ForbiddenException + * @throws InternalServerException + * @throws NotFoundException + * @throws UnathorizedException + * @throws GuzzleException + */ + public function checkDeliveryStatus(string $id): array + { + try { + $response = $this->client->request('GET', 'Messaging/v1/SMSDeliveryStatus', [ + 'query' => [ + 'id' => $id, + 'apikey' => $this->apiKey, + ] + ]); + + $data = json_decode($response->getBody()->getContents(), true); + + return [ + 'result' => $data['result'], + 'address' => $data['address'], + 'deliveryStatus' => $data['deliveryStatus'] + ]; + } catch (RequestException $e) { + return $this->handleError($e); + } + } + + /** + * @return array{ used: string, available: string, date: string} + * @throws BadRequestException + * @throws Exception + * @throws ForbiddenException + * @throws InternalServerException + * @throws NotFoundException + * @throws UnathorizedException + * @throws GuzzleException + */ + public function checkLimit(): array + { + try { + $response = $this->client->request('GET', 'Messaging/v1/SmartSMS/limit', [ + 'query' => [ + 'apikey' => $this->apiKey, + ] + ]); + + $data = json_decode($response->getBody()->getContents(), true); + + return [ + 'used' => $data['SmartSMS -global counter']['used'], + 'available' => $data['SmartSMS -global counter']['available'], + 'date' => $data['SmartSMS -global counter']['date'] + ]; + } catch (RequestException $e) { + return $this->handleError($e); + } + } + + /** + * Handle errors in API requests by throwing custom exceptions based on status code. + * + * @param RequestException $exception + * @return array + * @throws BadRequestException + * @throws Exception + * @throws ForbiddenException + * @throws InternalServerException + * @throws NotFoundException + * @throws UnathorizedException + */ + private function handleError(RequestException $exception): array + { + $errorMessage = 'Network or server error'; + + if ($exception->hasResponse()) { + $statusCode = $exception->getResponse()->getStatusCode(); + $errorBody = json_decode($exception->getResponse()->getBody(), true); + $errorMessage = $errorBody['description'] ?? 'Unknown error'; + + switch ($statusCode) { + case 400: + throw new BadRequestException($errorMessage); + case 401: + throw new UnathorizedException($errorMessage); + case 403: + throw new ForbiddenException($errorMessage); + case 404: + throw new NotFoundException($errorMessage); + case 500: + throw new InternalServerException($errorMessage); + default: + throw new Exception($errorMessage); + } + } + + throw new Exception($errorMessage); + } +} diff --git a/tests/MessagingMockRequestTest.php b/tests/MessagingMockRequestTest.php new file mode 100644 index 0000000..dee67f3 --- /dev/null +++ b/tests/MessagingMockRequestTest.php @@ -0,0 +1,92 @@ +clientMock = $this->createMock(ClientInterface::class); + + $this->messagingRequest = new MessagingRequest($this->clientMock, 'tTGPMspDeGpdGQ8PLCyfdSD1jz5zQdZb'); + } + + public function testSendSMSSuccessful(): void + { + $responseBody = json_encode([ + 'result' => 'OK', + 'id' => '123456789', + 'deliveryStatus' => 'DeliveredToNetwork' + ]); + + $response = new Response(200, [], $responseBody); + + $this->clientMock->expects($this->once()) + ->method('request') + ->with('GET', 'Messaging/v1/SmartSMS', $this->arrayHasKey('query')) + ->willReturn($response); + + $message = new SMSMessage('test', '48510123456', 'Wiadomość testowa'); + + $result = $this->messagingRequest->sendSMS($message, true); + + $this->assertEquals('OK', $result['result']); + $this->assertEquals('123456789', $result['id']); + $this->assertEquals('DeliveredToNetwork', $result['deliveryStatus']); + } + + public function testCheckDeliveryStatusSuccessful(): void + { + $responseBody = json_encode([ + 'result' => 'OK', + 'address' => '123456789', + 'deliveryStatus' => 'DeliveredToTerminal' + ]); + + $response = new Response(200, [], $responseBody); + + $this->clientMock->expects($this->once()) + ->method('request') + ->with('GET', 'Messaging/v1/SMSDeliveryStatus', $this->arrayHasKey('query')) + ->willReturn($response); + + $result = $this->messagingRequest->checkDeliveryStatus('123456789'); + + $this->assertEquals('OK', $result['result']); + $this->assertEquals('123456789', $result['address']); + $this->assertEquals('DeliveredToTerminal', $result['deliveryStatus']); + } + + public function testCheckLimitSuccessful() + { + $responseBody = json_encode([ + 'SmartSMS -global counter' => [ + 'used' => '10', + 'available' => '990', + 'date' => '2024-10-05' + ] + ]); + + $response = new Response(200, [], $responseBody); + + $this->clientMock->expects($this->once()) + ->method('request') + ->with('GET', 'Messaging/v1/SmartSMS/limit', $this->arrayHasKey('query')) + ->willReturn($response); + + $result = $this->messagingRequest->checkLimit(); + + $this->assertEquals('10', $result['used']); + $this->assertEquals('990', $result['available']); + $this->assertEquals('2024-10-05', $result['date']); + } +} \ No newline at end of file