18 public const ID =
'ednaruimhpx';
24 private const ENDPOINT_OPTION =
'connector_endpoint';
25 private const LOGIN_OPTION =
'login';
26 private const PASSWORD_OPTION =
'password';
27 private const SUBJECT_OPTION =
'subject_id';
31 return defined(
'MESSAGESERIVICE_ALLOW_IMHPX') && MESSAGESERIVICE_ALLOW_IMHPX ===
true;
41 return 'Edna.ru IMHPX';
46 return 'Edna.ru IMHPX';
51 return defined(
'MESSAGESERIVICE_ALLOW_IMHPX') && MESSAGESERIVICE_ALLOW_IMHPX ===
true;
61 $id = $this->
getOption(self::SUBJECT_OPTION);
71 public function register(array $fields):
Result
73 $this->
setOption(static::ENDPOINT_OPTION, $fields[
'connector_endpoint']);
74 $this->
setOption(static::LOGIN_OPTION, $fields[
'login']);
75 $this->
setOption(static::PASSWORD_OPTION, $fields[
'password']);
76 $this->
setOption(static::SUBJECT_OPTION, $fields[
'subject_id']);
84 self::ENDPOINT_OPTION => $this->
getOption(self::ENDPOINT_OPTION),
85 self::LOGIN_OPTION => $this->
getOption(self::LOGIN_OPTION),
86 self::PASSWORD_OPTION => $this->
getOption(self::PASSWORD_OPTION),
87 self::SUBJECT_OPTION => $this->
getOption(self::SUBJECT_OPTION),
93 return parent::getCallbackUrl();
106 return $result->addError(
new Error(
'Service is unavailable'));
112 if (!$requestResult->isSuccess())
114 $result->addErrors($requestResult->getErrors());
119 $response = $requestResult->getHttpResponse();
120 $this->processServiceResponse($response, $result);
132 switch ($serviceStatus)
148 case 'no-match-template':
157 $messageText = $messageFields[
'MESSAGE_BODY'];
158 $messageText = htmlspecialcharsbx($messageText);
161 <subject>Bitrix24</subject>
162 <priority>{$this->getPriority()}</priority>
163 <content>{$messageText}</content>
164 <sendTimeoutSeconds>60</sendTimeoutSeconds>
165 <validityPeriodMinutes>30</validityPeriodMinutes>
168 $address = static::normalizePhoneNumberForOutgoing($messageFields[
'MESSAGE_TO']);
171 $login = $ownerInfo[static::LOGIN_OPTION];
172 $password = $ownerInfo[static::PASSWORD_OPTION];
173 $mailbox = $ownerInfo[static::SUBJECT_OPTION];
176<?xml version=
"1.0" encoding=
"UTF-8" standalone=
"no"?>
177<consumeInstantMessageRequest>
180 <login>{$login}</login>
181 <password>{$password}</password>
186 <instantMessage clientId=
"{$messageFields['ID']}">
187 <address>{$address}</address>
188 <subject>{$mailbox}</subject>
190 <instantMessageType>{$this->
getMessageType()}</instantMessageType>
191 <contentType>text</contentType>
193 <text>{$messageText}</text>
197 </instantMessageList>
199</consumeInstantMessageRequest>
208 "socketTimeout" => $this->socketTimeout,
209 "streamTimeout" => $this->streamTimeout,
210 'waitResponse' =>
true,
212 $httpClient->setHeader(
'User-Agent',
'Bitrix24');
213 $httpClient->setHeader(
'Content-type',
'text/xml');
216 $result->setHttpRequest(
new DTO\
Request([
219 'headers' => method_exists($httpClient,
'getRequestHeaders') ? $httpClient->getRequestHeaders()->toArray() : [],
223 $body = Encoding::convertEncoding($body, SITE_CHARSET,
'utf-8');
226 $result->setHttpResponse(
new DTO\
Response([
229 $httpError = $httpClient->getError();
230 $errorCode = array_key_first($httpError);
231 $result->addError(
new Error($httpError[$errorCode], $errorCode));
236 'statusCode' => $httpClient->getStatus(),
237 'headers' => $httpClient->getHeaders()->toArray(),
238 'body' => $httpClient->getResult(),
240 $result->setHttpResponse($httpResponse);
271 if ($response->statusCode !== 200)
273 $result->addError(
new Error(
"Response status code is {$response->statusCode}",
'WRONG_SERVICE_RESPONSE_CODE'));
276 $parseResult = $this->parseXml($response->body);
277 if (!$parseResult->isSuccess())
281 'XML parse error: ' . implode(
'; ', $parseResult->getErrorMessages()),
289 $instantMessageResponse = $parseResult->getData()[
'root'];
292 $instantMessageResponse = Json::decode(Json::encode($instantMessageResponse));
296 !isset($instantMessageResponse[
'payload'])
297 || (!isset($instantMessageResponse[
'payload'][
'code'])
298 && !isset($instantMessageResponse[
'payload'][
'instantMessageList'])
302 $result->addError(
new Error(
'Wrong xml response structure',
'SERVICE_RESPONSE_PARSE_ERROR'));
306 if ($instantMessageResponse[
'payload'][
'code'] !==
'ok')
309 $result->addError(
new Error($instantMessageResponse[
'payload'][
'code'], $instantMessageResponse[
'payload'][
'code']));
313 foreach ($instantMessageResponse[
'payload'][
'instantMessageList'] as $instantMessage)
315 if ($instantMessage[
'code'] ===
'ok' && isset($instantMessage[
'@attributes'][
'providerId']))
317 $result->setExternalId($instantMessage[
'@attributes'][
'providerId']);
318 $result->setAccepted();
323 $result->addError(
new Error(
'', $instantMessage[
'code']));
329 $result->addError(
new Error(
'Could not find message status in response',
'SERVICE_RESPONSE_PARSE_ERROR'));
353 public function processIncomingRequest(
string $incomingRequestBody): DTO\Response
355 $response =
new DTO\Response([
358 $parseResult = $this->parseIncomingRequest($incomingRequestBody);
359 if (!$parseResult->isSuccess())
361 $response->statusCode = 400;
362 $response->body =
'Parse error';
368 $statusUpdateList = $parseResult->getData();
369 foreach ($statusUpdateList as $statusUpdate)
372 if ($message && $statusUpdate->providerStatus !=
'')
374 $message->updateStatusByExternalStatus($statusUpdate->providerStatus);
402 public function parseIncomingRequest(
string $incomingRequestBody): Result
404 $result =
new Result();
405 $parseResult = $this->parseXml($incomingRequestBody);
406 if (!$parseResult->isSuccess())
408 return $result->addErrors($parseResult->getErrors());
412 $incomingRequest = $parseResult->getData()[
'root'];
415 if ($incomingRequest->getName() !=
'provideInstantMessageDlvStatusResponse')
421 $incomingRequest = Json::decode(Json::encode($incomingRequest));
423 !isset($incomingRequest[
'payload'])
424 || (!isset($incomingRequest[
'payload'][
'code'])
425 && !isset($incomingRequest[
'payload'][
'instantMessageList'])
429 return $result->addError(
new Error(
'Wrong XML structure'));
432 $statusUpdateList = [];
436 $instantMessageList = $incomingRequest[
'payload'][
'instantMessageList'][
'instantMessage'];
437 if (!is_array($instantMessageList))
440 return $result->setData($statusUpdateList);
443 if (Collection::isAssociative($instantMessageList))
445 $instantMessageList = [$instantMessageList];
448 foreach ($instantMessageList as $instantMessage)
450 $statusUpdateList[] =
new DTO\StatusUpdate([
451 'externalId' => (
int)$instantMessage[
'@attributes'][
'providerId'],
452 'providerStatus' => $instantMessage[
'instantMessageDlvStatus'][
'dlvStatus'],
453 'deliveryStatus' => static::resolveStatus($instantMessage[
'instantMessageDlvStatus'][
'dlvStatus']),
454 'deliveryError' => $instantMessage[
'instantMessageDlvStatus'][
'dlvError']
458 return $result->setData($statusUpdateList);
466 protected function parseXml(
string $xmlString): Result
468 $result =
new Result();
470 if ($xmlString ===
'')
472 return $result->addError(
new Error(
'Empty XML'));
475 libxml_use_internal_errors(
true);
476 libxml_clear_errors();
477 $parsedBody = simplexml_load_string($xmlString);
478 $parseErrors = libxml_get_errors();
480 if (!empty($parseErrors))
483 foreach ($parseErrors as $parseError)
485 $result->addError(
new Error($parseError->message, $parseError->code));
491 'root' => $parsedBody
498 return $this::DEFAULT_PRIORITY;
503 return $this::MESSAGE_TYPE;
508 return $this->
getOption(static::ENDPOINT_OPTION);
514 if (mb_strpos($phoneNumber,
'+') === 0)
516 return mb_substr($phoneNumber, 1);