Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add domain whitelisting #45

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions spec/MessengerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Tgallice\FBMessenger\Model\MessageResponse;
use Tgallice\FBMessenger\Model\ThreadSetting;
use Tgallice\FBMessenger\Model\UserProfile;
use Tgallice\FBMessenger\Model\WhitelistedDomains;
use Tgallice\FBMessenger\NotificationType;
use Tgallice\FBMessenger\TypingIndicator;

Expand Down Expand Up @@ -297,4 +298,52 @@ function it_should_set_typing_status($client)

$this->setTypingStatus('USER_ID', TypingIndicator::TYPING_ON);
}

function it_should_define_domain_whitelisting($client)
{
$expectedBody = [
'setting_type' => 'domain_whitelisting',
'whitelisted_domains' => ['https://www.google.com'],
'domain_action_type' => 'add'
];

$client->post('/me/thread_settings', Argument::that(function ($body) use ($expectedBody) {
return json_encode($body) === json_encode($expectedBody);
}))->shouldBeCalled();

$this->setDomainWhitelisting(['https://www.google.com']);
}

function it_get_domain_whitelisting($client, ResponseInterface $response)
{
$response->getBody()->willReturn('
{
"data" : [{
"whitelisted_domains" : [
"domain_1",
"domain_2"
],
"id" : "123456"
}]
}
');

$query = [
'fields' => 'whitelisted_domains',
];

$client->get('/me/thread_settings', $query)->willReturn($response);

$whitelistedDomains = new WhitelistedDomains([
'data' => [[
'whitelisted_domains' => [
'domain_1',
'domain_2'
],
'id' => '123456'
]]
]);

$this->getDomainWhitelisting()->shouldBeLike($whitelistedDomains);
}
}
79 changes: 79 additions & 0 deletions spec/Model/ThreadSetting/DomainWhitelistingSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace spec\Tgallice\FBMessenger\Model\ThreadSetting;

use PhpSpec\ObjectBehavior;
use Tgallice\FBMessenger\Model\ThreadSetting;

class DomainWhitelistingSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(['https://google.com']);
}

function it_is_initializable()
{
$this->shouldHaveType('Tgallice\FBMessenger\Model\ThreadSetting\DomainWhitelisting');
}

function it_has_a_domains()
{
$this->getDomains()->shouldReturn(['https://google.com']);
}

function it_has_a_add_action()
{
$this->getAction()->shouldReturn('add');
}

function it_has_a_remove_action()
{
$this->beConstructedWith(['https://google.com'], 'remove');

$this->getAction()->shouldReturn('remove');
}

function it_throws_exception_when_is_not_add_or_remove_action()
{
$this->beConstructedWith(['https://google.com'], 'update');

$this
->shouldThrow(new \InvalidArgumentException('The action must be type: "add" or "remove".'))
->duringInstantiation();
}

function it_throws_exception_when_domains_is_not_a_array()
{
$this->beConstructedWith('not array');

$this
->shouldThrow(new \InvalidArgumentException('Domains must be a array.'))
->duringInstantiation();
}

function it_throws_exception_when_one_domains_has_not_a_https_protocol()
{
$this->beConstructedWith([
'https://petersfancyapparel.com',
'http://google.com',
'https://www.google.com'
], 'add');

$this
->shouldThrow(new \InvalidArgumentException('Each domain must be a "https" protocol.'))
->duringInstantiation();
}

function it_should_be_serializable()
{
$this->shouldImplement(\JsonSerializable::class);

$expected = [
'whitelisted_domains' => ['https://google.com'],
'domain_action_type' => 'add'
];

$this->jsonSerialize()->shouldBeLike($expected);
}
}
38 changes: 35 additions & 3 deletions src/Messenger.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
use Tgallice\FBMessenger\Model\ThreadSetting;
use Tgallice\FBMessenger\Model\ThreadSetting\GreetingText;
use Tgallice\FBMessenger\Model\ThreadSetting\StartedButton;
use Tgallice\FBMessenger\Model\ThreadSetting\DomainWhitelisting;
use Tgallice\FBMessenger\Model\UserProfile;
use Tgallice\FBMessenger\Model\WhitelistedDomains;

class Messenger
{
Expand Down Expand Up @@ -170,6 +172,33 @@ public function deleteGreetingText()
$this->deleteThreadSettings($setting);
}

/**
* @param array $domains
* @param string $action
*/
public function setDomainWhitelisting($domains, $action = DomainWhitelisting::TYPE_ADD)
{
$domainWhitelisting = new DomainWhitelisting($domains, $action);
$setting = $this->buildSetting(ThreadSetting::TYPE_DOMAIN_WHITELISTING, null, $domainWhitelisting, true);

$this->postThreadSettings($setting);
}

/**
* @return array
*/
public function getDomainWhitelisting()
{
$query = [
'fields' => DomainWhitelisting::WHITELISTED_DOMAINS
];

$response = $this->client->get('/me/thread_settings', $query);
$data = $this->decodeResponse($response);

return WhitelistedDomains::create($data);
}

/**
* Messenger Factory
*
Expand Down Expand Up @@ -205,10 +234,11 @@ private function deleteThreadSettings(array $setting)
* @param string $type
* @param null|string $threadState
* @param mixed $value
* @param bool $mergeValueWithSetting
*
* @return array
*/
private function buildSetting($type, $threadState = null, $value = null)
private function buildSetting($type, $threadState = null, $value = null, $mergeValueWithSetting = false)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation look like to be updated. No need to threadState and setting_type anymore. Maybe a rewrite of this function should be better.

{
$setting = [
'setting_type' => $type,
Expand All @@ -217,8 +247,10 @@ private function buildSetting($type, $threadState = null, $value = null)
if (!empty($threadState)) {
$setting['thread_state'] = $threadState;
}

if (!empty($value)) {

if($mergeValueWithSetting === true) {
$setting = array_merge($setting, $value->jsonSerialize());
} else if(!empty($value)) {
$setting[$type] = $value;
}

Expand Down
1 change: 1 addition & 0 deletions src/Model/ThreadSetting.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface ThreadSetting
// Setting type
const TYPE_GREETING = 'greeting';
const TYPE_CALL_TO_ACTIONS = 'call_to_actions';
const TYPE_DOMAIN_WHITELISTING = 'domain_whitelisting';

// Thread state
const NEW_THREAD = 'new_thread';
Expand Down
102 changes: 102 additions & 0 deletions src/Model/ThreadSetting/DomainWhitelisting.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace Tgallice\FBMessenger\Model\ThreadSetting;

use Tgallice\FBMessenger\Model\ThreadSetting;

class DomainWhitelisting implements ThreadSetting, \JsonSerializable
{
const TYPE_ADD = 'add';
const TYPE_REMOVE = 'remove';

const WHITELISTED_DOMAINS = 'whitelisted_domains';
const DOMAIN_ACTION_TYPE = 'domain_action_type';

/**
* @var string
*/
private $action;

/**
* @var array
*/
private $domains = [];

/**
*
* @param string $action
* @param array $domains
*
* @throws \InvalidArgumentException
*/
public function __construct($domains, $action = DomainWhitelisting::TYPE_ADD)
{
self::validateAction($action);
self::validateDomains($domains);

$this->action = $action;
$this->domains = $domains;
}

/**
*
* @return array
*/
public function getDomains()
{
return $this->domains;
}

/**
*
* @return string
*/
public function getAction()
{
return $this->action;
}

/**
*
* @param string $action
*
* @throws \InvalidArgumentException
*/
public static function validateAction($action)
{
if(!in_array($action, [DomainWhitelisting::TYPE_ADD, DomainWhitelisting::TYPE_REMOVE])) {
throw new \InvalidArgumentException('The action must be type: "add" or "remove".');
}
}

/**
*
* @param array $domains
*
* @throws \InvalidArgumentException
*/
public static function validateDomains($domains)
{
if(!is_array($domains)) {
throw new \InvalidArgumentException('Domains must be a array.');
}

//https://developers.facebook.com/docs/messenger-platform/thread-settings/domain-whitelisting
foreach($domains as $domain) {
if(!preg_match('#^https:\/\/#', $domain)) {
throw new \InvalidArgumentException('Each domain must be a "https" protocol.');
}
}
}

/**
* @inheritdoc
*/
public function jsonSerialize()
{
return [
DomainWhitelisting::WHITELISTED_DOMAINS => $this->domains,
DomainWhitelisting::DOMAIN_ACTION_TYPE => $this->action
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is needed ? No mention of that in the documentation.

];
}
}
41 changes: 41 additions & 0 deletions src/Model/WhitelistedDomains.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Tgallice\FBMessenger\Model;

use Tgallice\FBMessenger\Model\ThreadSetting\DomainWhitelisting;

class WhitelistedDomains
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the need of this class. Or It's should be more generic. Maybe rename DomainWhitelisting to DomainWhitelist and used it instead of WhitelistedDomains. The DomainWhitelist should contain only domain list.

{
/**
* @var array
*/
private $data;

/**
* @param array $data
*/
public function __construct(array $data)
{
$this->data = $data;
}

/**
* @return array|null
*/
public function getDomains()
{
return isset($this->data['data'][0][DomainWhitelisting::WHITELISTED_DOMAINS]) ?
$this->data['data'][0][DomainWhitelisting::WHITELISTED_DOMAINS] :
null;
}

/**
* @param array $data
*
* @return WhitelistedDomains
*/
public static function create(array $data)
{
return new self($data);
}
}