From c97cd4ea229050e52820022e00724bfe419e20c6 Mon Sep 17 00:00:00 2001 From: Raymond Jelierse Date: Wed, 8 May 2019 15:59:18 +0200 Subject: [PATCH 1/2] Revert "Revert "Merge pull request #72 from messagebird/add-conversations"" This reverts commit d8addaf06afb3f746330358d23d34650701f3b53. --- examples/conversations/create.php | 26 ++ examples/conversations/list.php | 22 ++ .../messages-create-location.php | 30 +++ .../conversations/messages-create-media.php | 31 +++ .../conversations/messages-create-text.php | 29 +++ examples/conversations/messages-list.php | 16 ++ examples/conversations/read.php | 24 ++ examples/conversations/update.php | 18 ++ examples/conversations/webhooks-create.php | 28 +++ examples/conversations/webhooks-delete.php | 15 ++ examples/conversations/webhooks-list.php | 16 ++ examples/conversations/webhooks-read.php | 17 ++ src/MessageBird/Client.php | 70 ++++-- .../Objects/Conversation/Channel.php | 67 +++++ .../Objects/Conversation/Contact.php | 82 ++++++ .../Objects/Conversation/Content.php | 116 +++++++++ .../Objects/Conversation/Conversation.php | 136 ++++++++++ .../Objects/Conversation/Message.php | 129 ++++++++++ .../Objects/Conversation/MessageReference.php | 26 ++ .../Objects/Conversation/Webhook.php | 90 +++++++ .../Resources/Conversation/Contacts.php | 17 ++ .../Resources/Conversation/Content.php | 17 ++ .../Resources/Conversation/Conversations.php | 107 ++++++++ .../Resources/Conversation/Messages.php | 167 +++++++++++++ .../Resources/Conversation/Webhooks.php | 20 ++ .../conversation/ConversationContentTest.php | 112 +++++++++ .../conversation/ConversationMessageTest.php | 157 ++++++++++++ .../conversation/ConversationTest.php | 236 ++++++++++++++++++ .../conversation/ConversationWebhookTest.php | 134 ++++++++++ 29 files changed, 1935 insertions(+), 20 deletions(-) create mode 100644 examples/conversations/create.php create mode 100644 examples/conversations/list.php create mode 100644 examples/conversations/messages-create-location.php create mode 100644 examples/conversations/messages-create-media.php create mode 100644 examples/conversations/messages-create-text.php create mode 100644 examples/conversations/messages-list.php create mode 100644 examples/conversations/read.php create mode 100644 examples/conversations/update.php create mode 100644 examples/conversations/webhooks-create.php create mode 100644 examples/conversations/webhooks-delete.php create mode 100644 examples/conversations/webhooks-list.php create mode 100644 examples/conversations/webhooks-read.php create mode 100644 src/MessageBird/Objects/Conversation/Channel.php create mode 100644 src/MessageBird/Objects/Conversation/Contact.php create mode 100644 src/MessageBird/Objects/Conversation/Content.php create mode 100644 src/MessageBird/Objects/Conversation/Conversation.php create mode 100644 src/MessageBird/Objects/Conversation/Message.php create mode 100644 src/MessageBird/Objects/Conversation/MessageReference.php create mode 100644 src/MessageBird/Objects/Conversation/Webhook.php create mode 100644 src/MessageBird/Resources/Conversation/Contacts.php create mode 100644 src/MessageBird/Resources/Conversation/Content.php create mode 100644 src/MessageBird/Resources/Conversation/Conversations.php create mode 100644 src/MessageBird/Resources/Conversation/Messages.php create mode 100644 src/MessageBird/Resources/Conversation/Webhooks.php create mode 100644 tests/integration/conversation/ConversationContentTest.php create mode 100644 tests/integration/conversation/ConversationMessageTest.php create mode 100644 tests/integration/conversation/ConversationTest.php create mode 100644 tests/integration/conversation/ConversationWebhookTest.php diff --git a/examples/conversations/create.php b/examples/conversations/create.php new file mode 100644 index 00000000..7675a1b9 --- /dev/null +++ b/examples/conversations/create.php @@ -0,0 +1,26 @@ +text = 'Hello world'; + +$message = new \MessageBird\Objects\Conversation\Message(); +$message->channelId = 'CHANNEL_ID'; +$message->content = $content; +$message->to = 'RECIPIENT'; // Channel-specific, e.g. MSISDN for SMS. +$message->type = 'text'; + +try { + $conversation = $messageBird->conversations->create($message); + + var_dump($conversation); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/list.php b/examples/conversations/list.php new file mode 100644 index 00000000..5c37408c --- /dev/null +++ b/examples/conversations/list.php @@ -0,0 +1,22 @@ + '10', + 'offset' => '5', +); + +try { + $conversations = $messageBird->conversations->getList($optionalParameters); + + var_dump($conversations); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/messages-create-location.php b/examples/conversations/messages-create-location.php new file mode 100644 index 00000000..769adc73 --- /dev/null +++ b/examples/conversations/messages-create-location.php @@ -0,0 +1,30 @@ +location = array( + 'latitude' => 52.379112, + 'longitude' => 4.900384, +); + +$message = new \MessageBird\Objects\Conversation\Message(); +$message->channelId = 'CHANNEL_ID'; +$message->content = $content; +$message->to = 'RECIPIENT'; +$message->type = \MessageBird\Objects\Conversation\Content::TYPE_LOCATION; // 'location' + +try { + $conversation = $messageBird->conversationMessages->create( + 'CONVERSATION_ID', + $message + ); + + var_dump($conversation); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/messages-create-media.php b/examples/conversations/messages-create-media.php new file mode 100644 index 00000000..fff236b3 --- /dev/null +++ b/examples/conversations/messages-create-media.php @@ -0,0 +1,31 @@ +image = array( + 'url' => 'https://cdn-gc.messagebird.com/assets/images/logo.png' +); + +$message = new \MessageBird\Objects\Conversation\Message(); +$message->channelId = 'CHANNEL_ID'; +$message->content = $content; +$message->to = 'RECIPIENT_MSISDN'; +$message->type = \MessageBird\Objects\Conversation\Content::TYPE_IMAGE; // 'image' + +try { + // Using a contactId instead of a conversationId is also supported. + $conversation = $messageBird->conversationMessages->create( + 'CONVERSATION_ID', + $message + ); + + var_dump($conversation); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/messages-create-text.php b/examples/conversations/messages-create-text.php new file mode 100644 index 00000000..a7d11863 --- /dev/null +++ b/examples/conversations/messages-create-text.php @@ -0,0 +1,29 @@ +text = 'Hello world'; + +$message = new \MessageBird\Objects\Conversation\Message(); +$message->channelId = 'CHANNEL_ID'; +$message->content = $content; +$message->to = 'RECIPIENT'; +$message->type = \MessageBird\Objects\Conversation\Content::TYPE_TEXT; + +try { + $conversation = $messageBird->conversationMessages->create( + 'CONVERSATION_ID', + $message + ); + + var_dump($conversation); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/messages-list.php b/examples/conversations/messages-list.php new file mode 100644 index 00000000..3789c2dc --- /dev/null +++ b/examples/conversations/messages-list.php @@ -0,0 +1,16 @@ +conversationMessages->getList('CONVERSATION_ID'); + + var_dump($messages); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/read.php b/examples/conversations/read.php new file mode 100644 index 00000000..d2a375df --- /dev/null +++ b/examples/conversations/read.php @@ -0,0 +1,24 @@ + 'content', +); + +try { + $conversation = $messageBird->conversations->read( + 'CONVERSATION_ID', + $optionalParameters + ); + + var_dump($conversation); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/update.php b/examples/conversations/update.php new file mode 100644 index 00000000..49159870 --- /dev/null +++ b/examples/conversations/update.php @@ -0,0 +1,18 @@ +conversations->read($conversationId); + + $conversation->status = \MessageBird\Objects\Conversation\Conversation::STATUS_ACTIVE; + $messageBird->conversations->update($conversation, $conversationId); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/webhooks-create.php b/examples/conversations/webhooks-create.php new file mode 100644 index 00000000..08c2e298 --- /dev/null +++ b/examples/conversations/webhooks-create.php @@ -0,0 +1,28 @@ +channelId = 'CHANNEL_ID'; + $webhook->url = 'https://example.com/webhook'; + $webhook->events = array( + \MessageBird\Objects\Conversation\Webhook::EVENT_CONVERSATION_CREATED, + \MessageBird\Objects\Conversation\Webhook::EVENT_MESSAGE_CREATED, + + // Other options: + // \MessageBird\Objects\Conversation\Webhook::EVENT_CONVERSATION_UPDATED, + // \MessageBird\Objects\Conversation\Webhook::EVENT_MESSAGE_UPDATED, + ); + + $messageBird->conversationWebhooks->create($webhook); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/webhooks-delete.php b/examples/conversations/webhooks-delete.php new file mode 100644 index 00000000..70b1d3e5 --- /dev/null +++ b/examples/conversations/webhooks-delete.php @@ -0,0 +1,15 @@ +conversationWebhooks->delete('WEBHOOK_ID'); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/webhooks-list.php b/examples/conversations/webhooks-list.php new file mode 100644 index 00000000..14cc9728 --- /dev/null +++ b/examples/conversations/webhooks-list.php @@ -0,0 +1,16 @@ +conversationWebhooks->getList(); + + var_dump($webhooks); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/examples/conversations/webhooks-read.php b/examples/conversations/webhooks-read.php new file mode 100644 index 00000000..1f52019f --- /dev/null +++ b/examples/conversations/webhooks-read.php @@ -0,0 +1,17 @@ +conversationWebhooks->read('WEBHOOK_ID'); + + var_dump($webhook); +} catch (\Exception $e) { + echo sprintf("%s: %s", get_class($e), $e->getMessage()); +} diff --git a/src/MessageBird/Client.php b/src/MessageBird/Client.php index 9bd84de4..93690b8d 100644 --- a/src/MessageBird/Client.php +++ b/src/MessageBird/Client.php @@ -11,6 +11,7 @@ class Client { const ENDPOINT = 'https://rest.messagebird.com'; const CHATAPI_ENDPOINT = 'https://chat.messagebird.com/1'; + const CONVERSATIONSAPI_ENDPOINT = 'https://conversations.messagebird.com/v1'; const VOICEAPI_ENDPOINT = 'https://voice.messagebird.com'; const CLIENT_VERSION = '1.13.0'; @@ -120,6 +121,21 @@ class Client */ public $voiceWebhooks; + /** + * @var Resources\Conversation\Conversations; + */ + public $conversations; + + /** + * @var Resources\Conversation\Messages; + */ + public $conversationMessages; + + /** + * @var Resources\Conversation\Webhooks; + */ + public $conversationWebhooks; + /** * @var Common\HttpClient */ @@ -130,6 +146,11 @@ class Client */ protected $ChatAPIHttpClient; + /** + * @var Common\HttpClient + */ + protected $ConversationsAPIHttpClient; + /** * @var Common\HttpClient */ @@ -143,12 +164,14 @@ public function __construct($accessKey = null, Common\HttpClient $httpClient = n { if ($httpClient === null) { $this->ChatAPIHttpClient = new Common\HttpClient(self::CHATAPI_ENDPOINT); + $this->ConversationsAPIHttpClient = new Common\HttpClient(self::CONVERSATIONSAPI_ENDPOINT); $this->HttpClient = new Common\HttpClient(self::ENDPOINT); $this->VoiceAPIHttpClient = new Common\HttpClient(self::VOICEAPI_ENDPOINT, 10, 2, array( 'X-MessageBird-Version' => '20170314', )); } else { $this->ChatAPIHttpClient = $httpClient; + $this->ConversationsAPIHttpClient = $httpClient; $this->HttpClient = $httpClient; $this->VoiceAPIHttpClient = $httpClient; } @@ -159,6 +182,9 @@ public function __construct($accessKey = null, Common\HttpClient $httpClient = n $this->ChatAPIHttpClient->addUserAgentString('MessageBird/ApiClient/' . self::CLIENT_VERSION); $this->ChatAPIHttpClient->addUserAgentString($this->getPhpVersion()); + $this->ConversationsAPIHttpClient->addUserAgentString('MessageBird/ApiClient/' . self::CLIENT_VERSION); + $this->ConversationsAPIHttpClient->addUserAgentString($this->getPhpVersion()); + $this->VoiceAPIHttpClient->addUserAgentString('MessageBird/ApiClient/' . self::CLIENT_VERSION); $this->VoiceAPIHttpClient->addUserAgentString($this->getPhpVersion()); @@ -166,26 +192,29 @@ public function __construct($accessKey = null, Common\HttpClient $httpClient = n $this->setAccessKey($accessKey); } - $this->messages = new Resources\Messages($this->HttpClient); - $this->hlr = new Resources\Hlr($this->HttpClient); - $this->verify = new Resources\Verify($this->HttpClient); - $this->balance = new Resources\Balance($this->HttpClient); - $this->voicemessages = new Resources\VoiceMessage($this->HttpClient); - $this->lookup = new Resources\Lookup($this->HttpClient); - $this->lookupHlr = new Resources\LookupHlr($this->HttpClient); - $this->chatMessages = new Resources\Chat\Message($this->ChatAPIHttpClient); - $this->chatChannels = new Resources\Chat\Channel($this->ChatAPIHttpClient); - $this->chatPlatforms = new Resources\Chat\Platform($this->ChatAPIHttpClient); - $this->chatContacts = new Resources\Chat\Contact($this->ChatAPIHttpClient); - $this->voiceCallFlows = new Resources\Voice\CallFlows($this->VoiceAPIHttpClient); - $this->voiceCalls = new Resources\Voice\Calls($this->VoiceAPIHttpClient); - $this->voiceLegs = new Resources\Voice\Legs($this->VoiceAPIHttpClient); - $this->voiceRecordings = new Resources\Voice\Recordings($this->VoiceAPIHttpClient); - $this->voiceTranscriptions = new Resources\Voice\Transcriptions($this->VoiceAPIHttpClient); - $this->voiceWebhooks = new Resources\Voice\Webhooks($this->VoiceAPIHttpClient); - $this->mmsMessages = new Resources\MmsMessages($this->HttpClient); - $this->contacts = new Resources\Contacts($this->HttpClient); - $this->groups = new Resources\Groups($this->HttpClient); + $this->messages = new Resources\Messages($this->HttpClient); + $this->hlr = new Resources\Hlr($this->HttpClient); + $this->verify = new Resources\Verify($this->HttpClient); + $this->balance = new Resources\Balance($this->HttpClient); + $this->voicemessages = new Resources\VoiceMessage($this->HttpClient); + $this->lookup = new Resources\Lookup($this->HttpClient); + $this->lookupHlr = new Resources\LookupHlr($this->HttpClient); + $this->chatMessages = new Resources\Chat\Message($this->ChatAPIHttpClient); + $this->chatChannels = new Resources\Chat\Channel($this->ChatAPIHttpClient); + $this->chatPlatforms = new Resources\Chat\Platform($this->ChatAPIHttpClient); + $this->chatContacts = new Resources\Chat\Contact($this->ChatAPIHttpClient); + $this->voiceCallFlows = new Resources\Voice\CallFlows($this->VoiceAPIHttpClient); + $this->voiceCalls = new Resources\Voice\Calls($this->VoiceAPIHttpClient); + $this->voiceLegs = new Resources\Voice\Legs($this->VoiceAPIHttpClient); + $this->voiceRecordings = new Resources\Voice\Recordings($this->VoiceAPIHttpClient); + $this->voiceTranscriptions = new Resources\Voice\Transcriptions($this->VoiceAPIHttpClient); + $this->voiceWebhooks = new Resources\Voice\Webhooks($this->VoiceAPIHttpClient); + $this->mmsMessages = new Resources\MmsMessages($this->HttpClient); + $this->contacts = new Resources\Contacts($this->HttpClient); + $this->groups = new Resources\Groups($this->HttpClient); + $this->conversations = new Resources\Conversation\Conversations($this->ConversationsAPIHttpClient); + $this->conversationMessages = new Resources\Conversation\Messages($this->ConversationsAPIHttpClient); + $this->conversationWebhooks = new Resources\Conversation\Webhooks($this->ConversationsAPIHttpClient); } /** @@ -196,6 +225,7 @@ public function setAccessKey ($accessKey) $Authentication = new Common\Authentication($accessKey); $this->ChatAPIHttpClient->setAuthentication($Authentication); + $this->ConversationsAPIHttpClient->setAuthentication($Authentication); $this->HttpClient->setAuthentication($Authentication); $this->VoiceAPIHttpClient->setAuthentication($Authentication); } diff --git a/src/MessageBird/Objects/Conversation/Channel.php b/src/MessageBird/Objects/Conversation/Channel.php new file mode 100644 index 00000000..02f017b3 --- /dev/null +++ b/src/MessageBird/Objects/Conversation/Channel.php @@ -0,0 +1,67 @@ +customDetails)) { + $this->customDetails = (array) $this->customDetails; + } + + return $this; + } +} diff --git a/src/MessageBird/Objects/Conversation/Content.php b/src/MessageBird/Objects/Conversation/Content.php new file mode 100644 index 00000000..d229681f --- /dev/null +++ b/src/MessageBird/Objects/Conversation/Content.php @@ -0,0 +1,116 @@ +loadLocationIfNeeded(); + $this->loadMediaIfNeeded(); + + return $this; + } + + /** + * Sets the location on this object if available. + */ + private function loadLocationIfNeeded() + { + if (!empty($this->location->latitude) && !empty($this->location->longitude)) { + $this->location = array( + 'latitude' => $this->location->latitude, + 'longitude' => $this->location->longitude, + ); + } + } + + /** + * Sets the media on this object if available. + */ + private function loadMediaIfNeeded() + { + if (!empty($this->audio->url)) { + $this->audio = array('url' => $this->audio->url); + } + + if (!empty($this->file->url)) { + $this->file = array('url' => $this->file->url); + } + + if (!empty($this->image->url)) { + $this->image = array('url' => $this->image->url); + } + + if (!empty($this->video->url)) { + $this->video = array('url' => $this->video->url); + } + } + + /** + * Serialize only non empty fields. + */ + public function jsonSerialize() + { + $json = array(); + + foreach (get_object_vars($this) as $key => $value) { + if (!empty($value)) { + $json[$key] = $value; + } + } + + return $json; + } +} diff --git a/src/MessageBird/Objects/Conversation/Conversation.php b/src/MessageBird/Objects/Conversation/Conversation.php new file mode 100644 index 00000000..d01f3f6e --- /dev/null +++ b/src/MessageBird/Objects/Conversation/Conversation.php @@ -0,0 +1,136 @@ +contact)) { + $newContact = new Contact(); + $newContact->loadFromArray($this->contact); + + $this->contact = $newContact; + } + + if (!empty($this->channels)) { + $channels = array(); + + foreach ($this->channels as $channel) { + $newChannel = new Channel(); + $newChannel->loadFromArray($channel); + + $channels[] = $newChannel; + } + + $this->channels = $channels; + } + + if (!empty($this->messages)) { + $messages = new MessageReference(); + $messages->loadFromArray($this->messages); + + $this->messages = $messages; + } + + return $this; + } +} diff --git a/src/MessageBird/Objects/Conversation/Message.php b/src/MessageBird/Objects/Conversation/Message.php new file mode 100644 index 00000000..b687335e --- /dev/null +++ b/src/MessageBird/Objects/Conversation/Message.php @@ -0,0 +1,129 @@ +loadFromArray($this->content); + + $this->content = $content; + + return $this; + } + + /** + * Serialize only non empty fields. + */ + public function jsonSerialize() + { + $json = array(); + + foreach (get_object_vars($this) as $key => $value) { + if (!empty($value)) { + $json[$key] = $value; + } + } + + return $json; + } +} diff --git a/src/MessageBird/Objects/Conversation/MessageReference.php b/src/MessageBird/Objects/Conversation/MessageReference.php new file mode 100644 index 00000000..b362a6e7 --- /dev/null +++ b/src/MessageBird/Objects/Conversation/MessageReference.php @@ -0,0 +1,26 @@ + $value) { + if (!empty($value)) { + $json[$key] = $value; + } + } + + return $json; + } +} diff --git a/src/MessageBird/Resources/Conversation/Contacts.php b/src/MessageBird/Resources/Conversation/Contacts.php new file mode 100644 index 00000000..ea7f1434 --- /dev/null +++ b/src/MessageBird/Resources/Conversation/Contacts.php @@ -0,0 +1,17 @@ +setObject(new Contact()); + } +} diff --git a/src/MessageBird/Resources/Conversation/Content.php b/src/MessageBird/Resources/Conversation/Content.php new file mode 100644 index 00000000..dfa292dd --- /dev/null +++ b/src/MessageBird/Resources/Conversation/Content.php @@ -0,0 +1,17 @@ +setObject(new ContentObject()); + } +} diff --git a/src/MessageBird/Resources/Conversation/Conversations.php b/src/MessageBird/Resources/Conversation/Conversations.php new file mode 100644 index 00000000..3109629c --- /dev/null +++ b/src/MessageBird/Resources/Conversation/Conversations.php @@ -0,0 +1,107 @@ +setObject(new Conversation()); + $this->setResourceName(self::RESOURCE_NAME); + } + + /** + * Starts a conversation by sending an initial message. + * + * @param Message $object + * @param array|null $query + * + * @return Message + * + * @throws Exceptions\HttpException + * @throws Exceptions\RequestException + * @throws Exceptions\ServerException + */ + public function start($object, $query = null) + { + $body = json_encode($object); + + list(, , $body) = $this->HttpClient->performHttpRequest( + HttpClient::REQUEST_POST, + $this->getStartUrl(), + $query, + $body + ); + + return $this->processRequest($body); + } + + /** + * Conversations API uses a special URL scheme for starting a conversation. + */ + private function getStartUrl() + { + return $this->resourceName . '/start'; + } + + /** + * Starts a conversation without sending an initial message. + * + * @param int $contactId + * + * @return Message + * + * @throws Exceptions\HttpException + * @throws Exceptions\RequestException + * @throws Exceptions\ServerException + */ + public function create($contactId, $query = null) + { + $body = json_encode(array('contactId' => $contactId)); + + list(, , $body) = $this->HttpClient->performHttpRequest( + HttpClient::REQUEST_POST, + $this->resourceName, + $query, + $body + ); + + return $this->processRequest($body); + } + + /** + * @param $object + * @param $id + * + * @return $this ->Object + * + * @internal param array $parameters + */ + public function update($object, $id) + { + $objVars = get_object_vars($object); + $body = array(); + + foreach ($objVars as $key => $value) { + if (null !== $value) { + $body[$key] = $value; + } + } + + $resourceName = $this->resourceName . ($id ? '/' . $id : null); + $body = json_encode($body); + + list(, , $body) = $this->HttpClient->performHttpRequest(HttpClient::REQUEST_PATCH, $resourceName, false, $body); + + return $this->processRequest($body); + } +} diff --git a/src/MessageBird/Resources/Conversation/Messages.php b/src/MessageBird/Resources/Conversation/Messages.php new file mode 100644 index 00000000..89c625ea --- /dev/null +++ b/src/MessageBird/Resources/Conversation/Messages.php @@ -0,0 +1,167 @@ +httpClient = $httpClient; + + $this->setObject(new Message()); + } + + /** + * @return Message + */ + public function getObject() + { + return $this->object; + } + + /** + * @param Message $object + */ + public function setObject($object) + { + $this->object = $object; + } + + /** + * Send a message to a conversation. + * + * @param string $conversationId + * @param Message $object + * @param string[]|null $query + * + * @return Message + * + * @throws HttpException + * @throws RequestException + * @throws ServerException + */ + public function create($conversationId, $object, $query = null) + { + $body = json_encode($object); + + list(, , $body) = $this->httpClient->performHttpRequest( + HttpClient::REQUEST_POST, + $this->getResourceNameWithId($conversationId), + $query, + $body + ); + + return $this->processRequest($body); + } + + /** + * Retrieves all the messages form the conversation based on its + * conversationId. + * + * @param string $conversationId + * @param string[] $parameters + */ + public function getList($conversationId, $parameters = array()) + { + list($status, , $body) = $this->httpClient->performHttpRequest( + HttpClient::REQUEST_GET, + $this->getResourceNameWithId($conversationId), + $parameters + ); + + if ($status === self::HTTP_STATUS_OK) { + $body = json_decode($body); + + $items = $body->items; + unset($body->items); + + $baseList = new BaseList(); + $baseList->loadFromArray($body); + + $objectName = $this->object; + + foreach ($items as $item) { + $message = new $objectName($this->httpClient); + $message->loadFromArray($item); + + $baseList->items[] = $message; + } + + return $baseList; + } + + return $this->processRequest($body); + } + + /** + * Formats a URL for the Conversation API's messages endpoint based on the + * conversationId. + * + * @param string $id + * + * @return string + */ + private function getResourceNameWithId($id) + { + return sprintf(self::RESOURCE_NAME, $id); + } + + /** + * Throws an exception if the request if the request has any errors. + * + * @param string $body + * + * @return self + * + * @throws RequestException + * @throws ServerException + */ + public function processRequest($body) + { + $body = @json_decode($body); + + if ($body === null or $body === false) { + throw new ServerException('Got an invalid JSON response from the server.'); + } + + if (empty($body->errors)) { + return $this->object->loadFromArray($body); + } + + $responseError = new ResponseError($body); + + throw new RequestException( + $responseError->getErrorString() + ); + } +} diff --git a/src/MessageBird/Resources/Conversation/Webhooks.php b/src/MessageBird/Resources/Conversation/Webhooks.php new file mode 100644 index 00000000..6f8a6325 --- /dev/null +++ b/src/MessageBird/Resources/Conversation/Webhooks.php @@ -0,0 +1,20 @@ +setObject(new Webhook()); + $this->setResourceName(self::RESOURCE_NAME); + } +} diff --git a/tests/integration/conversation/ConversationContentTest.php b/tests/integration/conversation/ConversationContentTest.php new file mode 100644 index 00000000..bcde5197 --- /dev/null +++ b/tests/integration/conversation/ConversationContentTest.php @@ -0,0 +1,112 @@ +loadFromArray( + json_decode($json) + ); + + return $message; + } + + public function testAudioContent() + { + $content = new Content(); + $content->audio = array('url' => 'https://example.com/audio.mp3'); + + $message = new Message(); + $message->content = $content; + $message->type = 'audio'; + + $this->assertEquals($message, $this->messageFromJson( + '{"type":"audio","content":{"audio":{"url":"https://example.com/audio.mp3"}}}' + )); + } + + public function testFileContent() + { + $content = new Content(); + $content->file = array('url' => 'https://example.com/file.pdf'); + + $message = new Message(); + $message->content = $content; + $message->type = 'file'; + + $this->assertEquals($message, $this->messageFromJson( + '{"type":"file","content":{"file":{"url":"https://example.com/file.pdf"}}}' + )); + } + + public function testImageContent() + { + $content = new Content(); + $content->image = array('url' => 'https://example.com/image.png'); + + $message = new Message(); + $message->content = $content; + $message->type = 'image'; + + $this->assertEquals($message, $this->messageFromJson( + '{"type":"image","content":{"image":{"url":"https://example.com/image.png"}}}' + )); + } + + public function testLocationContent() + { + $content = new Content(); + $content->location = array( + 'latitude' => '37.778326', + 'longitude' => '-122.394648', + ); + + $message = new Message(); + $message->content = $content; + $message->type = 'location'; + + $this->assertEquals($message, $this->messageFromJson( + '{"type":"location","content":{"location":{"latitude":"37.778326","longitude":"-122.394648"}}}' + )); + } + + public function testTextContent() + { + $content = new Content(); + $content->text = 'Foo Bar'; + + $message = new Message(); + $message->content = $content; + $message->type = 'text'; + + $this->assertEquals($message, $this->messageFromJson( + '{"type":"text","content":{"text":"Foo Bar"}}' + )); + } + + public function testVideoContent() + { + $content = new Content(); + $content->video = array('url' => 'https://example.com/video.mp4'); + + $message = new Message(); + $message->content = $content; + $message->type = 'video'; + + $this->assertEquals($message, $this->messageFromJson( + '{"type":"video","content":{"video":{"url":"https://example.com/video.mp4"}}}' + )); + } +} diff --git a/tests/integration/conversation/ConversationMessageTest.php b/tests/integration/conversation/ConversationMessageTest.php new file mode 100644 index 00000000..967079d0 --- /dev/null +++ b/tests/integration/conversation/ConversationMessageTest.php @@ -0,0 +1,157 @@ +client = new Client('YOUR_ACCESS_KEY', $this->mockClient); + } + + public function testCreateImage() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'conversations/some-conversation-id/messages', null, '{"channelId":"abcd1234","type":"image","content":{"image":{"url":"https:\/\/developers.messagebird.com\/assets\/images\/glyph.svg"}}}') + ->willReturn(array(200, '', '{}')); + + $content = new Content(); + $content->image = array( + 'url' => 'https://developers.messagebird.com/assets/images/glyph.svg' + ); + + $message = new Message(); + $message->channelId = 'abcd1234'; + $message->content = $content; + $message->type = 'image'; + + $this->client->conversationMessages->create('some-conversation-id', $message); + } + + public function testCreateLocation() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'conversations/some-contact-id/messages', null, '{"channelId":"abcd1234","type":"location","content":{"location":{"latitude":"52.379112","longitude":"4.900384"}}}') + ->willReturn(array(200, '', '{}')); + + $content = new Content(); + $content->location = array( + 'latitude' => '52.379112', + 'longitude' => '4.900384' + ); + + $message = new Message(); + $message->channelId = 'abcd1234'; + $message->content = $content; + $message->type = 'location'; + + $this->client->conversationMessages->create('some-contact-id', $message); + } + + public function testCreateText() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'conversations/some-other-contact-id/messages', null, '{"channelId":"abcd1234","type":"text","content":{"text":"Hello world"}}') + ->willReturn(array(200, '', '{}')); + + $content = new Content(); + $content->text = 'Hello world'; + + $message = new Message(); + $message->content = $content; + $message->channelId = 'abcd1234'; + $message->type = 'text'; + + $this->client->conversationMessages->create('some-other-contact-id', $message); + } + + public function testCreateWithoutChannel() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'conversations/genid/messages', null, '{"type":"text","content":{"text":"Hello world"}}') + ->willReturn(array(200, '', '{}')); + + $content = new Content(); + $content->text = 'Hello world'; + + $message = new Message(); + $message->content = $content; + $message->type = 'text'; + + $this->client->conversationMessages->create('genid', $message); + } + + public function testListPagination() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'conversations/genid/messages', array(), null) + ->willReturn(array(200, '', self::LIST_RESPONSE)); + + $messages = $this->client->conversationMessages->getList('genid'); + + $this->assertEquals(1, $messages->count); + $this->assertEquals(1, $messages->totalCount); + $this->assertEquals(25, $messages->limit); + $this->assertEquals(0, $messages->offset); + } + + public function testListObject() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'conversations/genid/messages', array(), null) + ->willReturn(array(200, '', self::LIST_RESPONSE)); + + $message = $this->client->conversationMessages->getList('genid')->items[0]; + + $expectedContent = new Content(); + $expectedContent->video = array( + 'url' => 'https://developers.messagebird.com/assets/videos/foo.mp4' + ); + + $expectedMessage = new Message(); + $expectedMessage->id = 'genid'; + $expectedMessage->channelId = 'chid'; + $expectedMessage->conversationId = 'conid'; + $expectedMessage->content = $expectedContent; + $expectedMessage->type = 'video'; + $expectedMessage->direction = 'received'; + $expectedMessage->status = 'delivered'; + $expectedMessage->createdDatetime = '2002-10-02T16:00:00Z'; + + $this->assertEquals($expectedMessage, $message); + } +} diff --git a/tests/integration/conversation/ConversationTest.php b/tests/integration/conversation/ConversationTest.php new file mode 100644 index 00000000..9b9b539b --- /dev/null +++ b/tests/integration/conversation/ConversationTest.php @@ -0,0 +1,236 @@ +client = new Client('YOUR_ACCESS_KEY', $this->mockClient); + } + + public function testStart() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'conversations/start', null, self::START_REQUEST) + ->willReturn(array(200, '', '{}')); + + $content = new Content(); + $content->location = array( + 'latitude' => '37.778326', + 'longitude' => '-122.394648', + ); + + $message = new Message(); + $message->channelId = 'channel-id'; + $message->to = '31612345678'; + $message->type = 'location'; + $message->content = $content; + + $this->client->conversations->start($message); + } + + /** + * We can also start a conversation without a message. + */ + public function testCreate() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'conversations', null, self::CREATE_REQUEST) + ->willReturn(array(200, '', '{}')); + + $this->client->conversations->create('some-contact-id'); + } + + public function testList() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'conversations', array(), null) + ->willReturn(array(200, '', self::LIST_RESPONSE)); + + $list = new BaseList(); + $list->limit = 10; + $list->offset = 0; + $list->count = 1; + $list->totalCount = 1; + $list->items = array($this->getConversation()); + + $this->assertEquals( + $list, + $this->client->conversations->getList() + ); + } + + public function testRead() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'conversations/conversation-id', null, null) + ->willReturn(array(200, '', self::READ_RESPONSE)); + + $this->assertEquals( + $this->getConversation(), + $this->client->conversations->read('conversation-id') + ); + } + + public function testUpdate() + { + $this->mockClient + ->expects($this->exactly(2))->method('performHttpRequest') + ->withConsecutive( + array('PATCH', 'conversations/conversation-id', null, '{"status":"archived"}'), + array('PATCH', 'conversations/conversation-id', null, '{"status":"active"}') + ) + ->willReturn(array(200, '', '{}')); + + $conversation = new Conversation(); + + $conversation->status = Conversation::STATUS_ARCHIVED; + $this->client->conversations->update($conversation, 'conversation-id'); + + $conversation->status = Conversation::STATUS_ACTIVE; + $this->client->conversations->update($conversation, 'conversation-id'); + } + + /** + * Gets an arbitrary conversation that's used in tests. + * + * @return Conversation + */ + private function getConversation() + { + $contact = new Contact(); + $contact->id = 'contact-id'; + $contact->href = 'https://rest.messagebird.com/contacts/contact-id'; + $contact->msisdn = '31612345678'; + $contact->firstName = 'Foo'; + $contact->lastName = 'Bar'; + $contact->customDetails = array( + 'custom1' => 'Baz', + ); + $contact->createdDatetime = '2018-07-20T12:13:41+00:00'; + $contact->updatedDatetime = '2018-07-20T12:13:51+00:00'; + + $channel = new Channel(); + $channel->id = 'channel-id'; + $channel->name = 'channel-name'; + $channel->platformId = 'messenger'; + $channel->status = 'active'; + $channel->createdDatetime = '2018-07-20T12:13:31+00:00'; + $channel->updatedDatetime = '2018-07-20T12:13:41+00:00'; + + $messages = new MessageReference(); + $messages->href = 'https://conversations.messagebird.com/v1/conversations/conversation-id/messages'; + $messages->totalCount = 12; + + $conversation = new Conversation(); + $conversation->contact = $contact; + $conversation->channels = array($channel); + $conversation->id = 'conversation-id'; + $conversation->href = 'https://conversations.messagebird.com/v1/conversations/conversation-id'; + $conversation->messages = $messages; + $conversation->status = Conversation::STATUS_ACTIVE; + $conversation->createdDatetime = '2018-07-20T12:13:21+00:00'; + $conversation->updatedDatetime = '2018-07-20T12:13:31+00:00'; + $conversation->lastReceivedDatetime = '2018-07-20T12:13:41+00:00'; + $conversation->lastUsedChannelId = 'channel-id'; + + return $conversation; + } +} \ No newline at end of file diff --git a/tests/integration/conversation/ConversationWebhookTest.php b/tests/integration/conversation/ConversationWebhookTest.php new file mode 100644 index 00000000..44472c52 --- /dev/null +++ b/tests/integration/conversation/ConversationWebhookTest.php @@ -0,0 +1,134 @@ +client = new \MessageBird\Client('YOUR_ACCESS_KEY', $this->mockClient); + } + + public function testDelete() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('DELETE', 'webhooks/some-id', null, null) + ->willReturn(array(204, '', null)); + + $this->client->conversationWebhooks->delete('some-id'); + } + + public function testCreate() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('POST', 'webhooks', null, '{"channelId":"chid","events":["conversation.created","message.created"],"url":"https:\/\/messagebird.com\/webhook-receiver"}') + ->willReturn(array(200, '', '{}')); + + $webhook = new Webhook(); + $webhook->channelId = 'chid'; + $webhook->url = 'https://messagebird.com/webhook-receiver'; + $webhook->events = array( + Webhook::EVENT_CONVERSATION_CREATED, + Webhook::EVENT_MESSAGE_CREATED, + ); + + $this->client->conversationWebhooks->create($webhook); + } + + public function testListPagination() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'webhooks', array(), null) + ->willReturn(array(200, '', self::LIST_RESPONSE)); + + $webhooks = $this->client->conversationWebhooks->getList(); + + $this->assertEquals(1, $webhooks->count); + $this->assertEquals(1, $webhooks->totalCount); + $this->assertEquals(25, $webhooks->limit); + $this->assertEquals(0, $webhooks->offset); + } + + public function testListObject() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'webhooks', array(), null) + ->willReturn(array(200, '', self::LIST_RESPONSE)); + + $expectedWebhook = new Webhook(); + $expectedWebhook->id = 'some-id'; + $expectedWebhook->channelId = 'chid'; + $expectedWebhook->events = array('conversation.created', 'message.created'); + $expectedWebhook->url = 'https://example.com/webhook'; + $expectedWebhook->createdDatetime = '2018-07-31T12:12:43Z'; + + $this->assertEquals( + $expectedWebhook, + $this->client->conversationWebhooks->getList()->items[0] + ); + } + + public function testRead() + { + $this->mockClient + ->expects($this->once())->method('performHttpRequest') + ->with('GET', 'webhooks/some-id', null, null) + ->willReturn(array(200, '', self::READ_RESPONSE)); + + $webhook = new Webhook(); + $webhook->id = 'some-id'; + $webhook->href = 'https://conversations.messagebird.com/v1/webhooks/some-id'; + $webhook->channelId = 'chid'; + $webhook->url = 'https://messagebird.com/webhook-receiver'; + $webhook->events = array( + Webhook::EVENT_CONVERSATION_UPDATED, + Webhook::EVENT_MESSAGE_UPDATED, + ); + $webhook->createdDatetime = '2018-07-20T12:13:41+00:00'; + $webhook->updatedDatetime = '2018-07-20T12:13:51+00:00'; + + $this->assertEquals( + $webhook, + $this->client->conversationWebhooks->read('some-id') + ); + } +} From 33954b9049f4f6d5377b601746f83016f559ffba Mon Sep 17 00:00:00 2001 From: Raymond Jelierse Date: Wed, 8 May 2019 16:28:41 +0200 Subject: [PATCH 2/2] Drop support for PHP 5.3 Anyone still on 5.3 should upgrade anyway, so Conversation API might be a key motivator --- .travis.yml | 3 --- composer.json | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 72d130f9..0d1135dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,9 +15,6 @@ matrix: allow_failures: - php: hhvm - php: hhvm-nightly - include: - - php: 5.3 - dist: precise before_script: - if [[ "$TRAVIS_PHP_VERSION" == "hhvm"* ]]; then curl -sSfL -o ~/.phpenv/versions/hhvm/bin/phpunit https://phar.phpunit.de/phpunit-5.7.phar; fi diff --git a/composer.json b/composer.json index 8d279724..b32ed4e8 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": ">=5.3.0", + "php": ">=5.4.0", "ext-curl": "*", "symfony/polyfill-php56": "^1.10" },