diff --git a/src/files/custom/Espo/Modules/SmsProviders/Resources/i18n/en_US/Integration.json b/src/files/custom/Espo/Modules/SmsProviders/Resources/i18n/en_US/Integration.json index 21264e3..b21ca8b 100644 --- a/src/files/custom/Espo/Modules/SmsProviders/Resources/i18n/en_US/Integration.json +++ b/src/files/custom/Espo/Modules/SmsProviders/Resources/i18n/en_US/Integration.json @@ -20,6 +20,10 @@ "serwerSmsPassword": "Password", "serwerSmsBaseUrl": "Base URL", "serwerSmsSender": "Sender Name", - "serwerSmsTest": "Test" + "serwerSmsTest": "Test", + "playSmsBaseUrl": "Base URL", + "playSmsUsername": "Username", + "playSmsWebservicesToken": "Webservices Token", + "playSmsNumberPrefix": "Prefix to add in front of the phonenumber" } } diff --git a/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/app/smsProviders.json b/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/app/smsProviders.json index 8e87868..69a1bb6 100644 --- a/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/app/smsProviders.json +++ b/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/app/smsProviders.json @@ -13,5 +13,8 @@ }, "SerwerSms": { "senderClassName": "Espo\\Modules\\SmsProviders\\SerwerSms\\SerwerSmsSender" + }, + "playSMS": { + "senderClassName": "Espo\\Modules\\SmsProviders\\playSMS\\PlaySmsSender" } } diff --git a/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/integrations/playSMS.json b/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/integrations/playSMS.json new file mode 100644 index 0000000..346c603 --- /dev/null +++ b/src/files/custom/Espo/Modules/SmsProviders/Resources/metadata/integrations/playSMS.json @@ -0,0 +1,25 @@ +{ + "view": "views/admin/integrations/edit", + "fields": { + "playSmsBaseUrl": { + "type": "varchar", + "maxLength": 100, + "required": true + }, + "playSmsUsername": { + "type": "varchar", + "maxLength": 100, + "required": true + }, + "playSmsWebservicesToken": { + "type": "password", + "maxLength": 100, + "required": true + }, + "playSmsNumberPrefix": { + "type": "varchar", + "maxLength": 20, + "required": false + } + } +} diff --git a/src/files/custom/Espo/Modules/SmsProviders/playSMS/PlaySmsSender.php b/src/files/custom/Espo/Modules/SmsProviders/playSMS/PlaySmsSender.php new file mode 100644 index 0000000..6ef5bd8 --- /dev/null +++ b/src/files/custom/Espo/Modules/SmsProviders/playSMS/PlaySmsSender.php @@ -0,0 +1,186 @@ +config = $config; + $this->entityManager = $entityManager; + $this->log = $log; + } + + public function send(Sms $sms): void + { + $toNumberList = $sms->getToNumberList(); + + if (!count($toNumberList)) { + throw new Error("No recipient phone number."); + } + + foreach ($toNumberList as $number) { + $this->sendToNumber($sms, $number); + } + } + + private function sendToNumber(Sms $sms, string $toNumber): void + { + $integration = $this->getIntegrationEntity(); + + $username = $integration->get('playSmsUsername'); + $webservicesToken = $integration->get('playSmsWebservicesToken'); + $baseUrl = rtrim($integration->get('playSmsBaseUrl')); + $timeout = $this->config->get('playSmsSendTimeout') ?? self::TIMEOUT; + $fromNumber = $sms->getFromNumber(); + + if (!$username) { + throw new Error("No playSMS username."); + } + if (!$webservicesToken) { + throw new Error("No playSMS Webservices Token."); + } + + if (!$fromNumber) { + throw new Error("No sender phone number."); + } + + if (!$toNumber) { + throw new Error("No recipient phone number."); + } + + $numberPrefix = $integration->get('playSmsNumberPrefix'); + if ($numberPrefix) { + $toNumber = $numberPrefix . self::formatNumber($toNumber); + } + + $url = $baseUrl . '/index.php?app=ws&u=' . $username . '&h=' . $webservicesToken . '&op=pv&to=' . urlencode($toNumber) . '&from=' . urlencode(self::formatNumber($fromNumber)) . '&msg=' . urlencode($sms->getBody()); + + $ch = curl_init(); + if ($ch) { + + curl_setopt($ch, \CURLOPT_URL, $url); + curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, \CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, \CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'GET'); + + $response = curl_exec($ch); + + $code = curl_getinfo($ch, \CURLINFO_HTTP_CODE); + $error = curl_errno($ch); + + $headerSize = curl_getinfo($ch, \CURLINFO_HEADER_SIZE); + + $body = mb_substr($response, $headerSize); + + if ($code && !($code >= 200 && $code < 300)) { + $this->processError($code, $body); + + } + + if ($error) { + if (in_array($error, [\CURLE_OPERATION_TIMEDOUT, \CURLE_OPERATION_TIMEOUTED])) { + throw new Error("playSMS SMS sending timeout."); + } + } + + curl_close($ch); + } + } + + private function buildQuery(array $data): string + { + $itemList = []; + + foreach ($data as $key => $value) { + $itemList[] = urlencode($key) . '=' . urlencode($value); + } + + return implode('&', $itemList); + } + + private static function formatNumber(string $number): string + { + return preg_replace('/[^0-9]/', '', $number); + } + + private function processError(int $code, string $body): void + { + try { + $data = Json::decode($body); + + $message = $data->message ?? null; + } + catch (Throwable $e) { + $message = null; + } + + if ($message) { + $this->log->error("playSMS SMS sending error. Message: " . $message); + } + + throw new Error("playSMS SMS sending error. Code: {$code}."); + } + + private function getIntegrationEntity(): Integration + { + $entity = $this->entityManager + ->getEntity(Integration::ENTITY_TYPE, 'playSMS'); + + if (!$entity || !$entity->get('enabled')) { + throw new Error("playSMS integration is not enabled"); + } + + return $entity; + } +}