Skip to content

Instantly share code, notes, and snippets.

@echr
Last active May 29, 2023 13:37
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save echr/d5141b0a3210462d32ed1fc3a621c371 to your computer and use it in GitHub Desktop.
Save echr/d5141b0a3210462d32ed1fc3a621c371 to your computer and use it in GitHub Desktop.
Simple Botman Whatsapp Driver
<?php
namespace Drivers\Whatsapp;
use BotMan\BotMan\Exceptions\Base\DriverException;
class WhatsappConnectionException extends DriverException
{
}
<?php
return [
'url' => env('WHATSAPP_PARTNER', 'http://127.0.0.1:3001/v1'),
'throw_http_exceptions' => true
];
<?php
namespace Drivers\Whatsapp;
use BotMan\BotMan\Drivers\HttpDriver;
use BotMan\BotMan\Interfaces\UserInterface;
use BotMan\BotMan\Messages\Incoming\Answer;
use BotMan\BotMan\Messages\Incoming\IncomingMessage;
use BotMan\BotMan\Users\User;
use Illuminate\Support\Collection;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class WhatsappDriver extends HttpDriver
{
const DRIVER_NAME = 'Whatsapp';
protected $endpoint = 'messages';
/**
* @var array
*/
protected $messages = [];
/**
* @param Request $request
* @return void
*/
public function buildPayload(Request $request)
{
$this->payload = new ParameterBag((array) json_decode($request->getContent(), true));
$this->event = Collection::make((array) $this->payload->get('messages') ? (array) $this->payload->get('messages')[0] : '');
$this->content = $request->getContent();
$this->config = Collection::make($this->config->get('whatsapp', []));
}
/**
* Determine if the request is for this driver.
*
* @return bool
*/
public function matchesRequest()
{
return !is_null($this->payload->get('contacts')) || !is_null($this->event->get('from'));
}
/**
* Retrieve the chat message(s).
*
* @return array
*/
public function getMessages()
{
if (empty($this->messages)) {
$this->messages = [
new IncomingMessage(
$this->event->get('text')['body'],
$this->event->get('from'),
$this->event->get('from'),
$this->payload
)
];
}
return $this->messages;
}
/**
* Retrieve User information.
* @param IncomingMessage $matchingMessage
* @return UserInterface
*/
public function getUser(IncomingMessage $matchingMessage)
{
$contact = Collection::make($matchingMessage->getPayload()->get('contacts')[0]);
return new User(
$contact->get('wa_id'),
$contact->get('profile')['name'],
null,
$contact->get('wa_id'),
$contact
);
}
/**
* @param IncomingMessage $message
* @return \BotMan\BotMan\Messages\Incoming\Answer
*/
public function getConversationAnswer(IncomingMessage $message)
{
return Answer::create($message->getText())->setMessage($message);
}
/**
* @param string|\BotMan\BotMan\Messages\Outgoing\Question $message
* @param IncomingMessage $matchingMessage
* @param array $additionalParameters
* @return $this
*/
public function buildServicePayload($message, $matchingMessage, $additionalParameters = [])
{
return [
'preview_url' => true,
'recipient_type' => 'individual',
'to' => $matchingMessage->getSender(),
'type' => 'text',
'text' => [
'body' => $message->getText()
]
];
}
/**
* @param mixed $payload
* @return Response
*/
public function sendPayload($payload)
{
if ($this->config->get('throw_http_exceptions')) {
return $this->postWithExceptionHandling($this->buildApiUrl($this->endpoint), [], $payload, $this->buildAuthHeader(), true);
}
return $this->http->post($this->buildApiUrl($this->endpoint), [], $payload, $this->buildAuthHeader(), true);
}
/**
* @return bool
*/
public function isConfigured()
{
// TODO: Check token existence from DB?
return !empty($this->config->get('url'));
}
/**
* Low-level method to perform driver specific API requests.
*
* @param string $endpoint
* @param array $parameters
* @param \BotMan\BotMan\Messages\Incoming\IncomingMessage $matchingMessage
* @return void
*/
public function sendRequest($endpoint, array $parameters, IncomingMessage $matchingMessage)
{
$parameters = array_replace_recursive([
'to' => $matchingMessage->getRecipient(),
], $parameters);
if ($this->config->get('throw_http_exceptions')) {
return $this->postWithExceptionHandling($this->buildApiUrl($endpoint), [], $parameters, $this->buildAuthHeader());
}
return $this->http->post($this->buildApiUrl($endpoint), [], $parameters, $this->buildAuthHeader());
}
protected function buildApiUrl($endpoint)
{
return $this->config->get('url') . '/' . $endpoint;
}
protected function buildAuthHeader()
{
// TODO: Token should from DB & Re-Fetch before expired
// TODO: Should create Artisan command + Scheduler
$token = 'YOUR-BEARER-TOKEN-HERE';
return [
"Authorization: Bearer $token",
'Content-Type: application/json',
'Accept: application/json'
];
}
/**
* @param $url
* @param array $urlParameters
* @param array $postParameters
* @param array $headers
* @param bool $asJSON
* @param int $retryCount
* @return Response
* @throws \Modules\ChatBot\Drivers\Whatsapp\WhatsappConnectionException
*/
private function postWithExceptionHandling(
$url,
array $urlParameters = [],
array $postParameters = [],
array $headers = [],
$asJSON = false,
int $retryCount = 0
) {
$response = $this->http->post($url, $urlParameters, $postParameters, $headers, $asJSON);
$responseData = json_decode($response->getContent(), true);
if ($response->isSuccessful()) {
return $responseData;
}
$responseData['errors']['code'] = $responseData['errors']['code'] ?? 'No description from Vendor';
$responseData['errors']['title'] = $responseData['errors']['title'] ?? 'No error code from Vendor';
$message = "Status Code: {$response->getStatusCode()}\n".
"Description: ".print_r($responseData['errors']['title'], true)."\n".
"Error Code: ".print_r($responseData['errors']['code'], true)."\n".
"URL: $url\n".
"URL Parameters: ".print_r($urlParameters, true)."\n".
"Post Parameters: ".print_r($postParameters, true)."\n".
"Headers: ". print_r($headers, true)."\n";
throw new WhatsappConnectionException($message);
}
}
@jilenloa
Copy link

jilenloa commented Oct 7, 2020

which partner would this work with? Or is it a direct integration with Facebook?

@echr
Copy link
Author

echr commented Oct 8, 2020

which partner would this work with? Or is it a direct integration with Facebook?

I'm using facebook partner https://wappin.id/ , the API looks similar with the FB documentation have, just the endpoint is using the partner host.

@legreco
Copy link

legreco commented Feb 22, 2022

Did you manage to load this driver?
I am using botman studio

@echr
Copy link
Author

echr commented Feb 22, 2022

Yes.. @legreco we're using it for production purposes but only for plain text (non-media) bot response. You might need to adjust some code to match your requirement.

@mutualmw-apps
Copy link

@echr is there a possible way i use this with whatsapp cloud api?

@echr
Copy link
Author

echr commented Nov 22, 2022

@echr is there a possible way i use this with whatsapp cloud api?

Never connect directly with whatsapp cloud api, but I guess the API reference is same with the partner one.

@Wraptechologies
Copy link

@echr is there a possible way i use this with whatsapp cloud api?

Never connect directly with whatsapp cloud api, but I guess the API reference is same with the partner one.

Brother can you please help of direct whatsapp cloud api plugin

@echr
Copy link
Author

echr commented May 26, 2023

@echr is there a possible way i use this with whatsapp cloud api?

Never connect directly with whatsapp cloud api, but I guess the API reference is same with the partner one.

Brother can you please help of direct whatsapp cloud api plugin

Sorry, I'm afraid can't help right now. It's been a long time since the last time I handled this bot project, it might have different spec now.

This package might be helpful to get started... https://github.com/irwan-runtuwene/driver-whatsapp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment