acf
This commit is contained in:
@ -0,0 +1,457 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class ActiveCampaign extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
* @param array $options The service's required options
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options);
|
||||
$this->setEndpoint($options['endpoint'] . '/api/3');
|
||||
$this->options->set('headers.Api-Token', $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to ActiveCampaign List
|
||||
*
|
||||
* https://developers.activecampaign.com/v3/reference#create-contact
|
||||
*
|
||||
* @param string $email The Email of the Contact
|
||||
* @param string $name The name of the Contact (Name can be also declared in Custom Fields)
|
||||
* @param string $list List ID
|
||||
* @param string $tags Tags for this contact (comma-separated). Example: "tag1, tag2, etc"
|
||||
* @param array $customfields Custom Fields
|
||||
* @param boolean $updateexisting Update Existing User
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $name, $lists, $tags = '', $customfields = [], $updateexisting = true)
|
||||
{
|
||||
// Detect name
|
||||
$name = (is_null($name) || empty($name)) ? $this->getNameFromCustomFields($customfields) : explode(' ', $name, 2);
|
||||
$apiAction = ($updateexisting) ? 'contact/sync' : 'contacts';
|
||||
|
||||
$data = [
|
||||
'contact' => [
|
||||
'email' => $email,
|
||||
'phone' => $this->getPhone($customfields),
|
||||
'ip4' => \NRFramework\User::getIP()
|
||||
],
|
||||
];
|
||||
|
||||
// Add first and last name only if they are not empty, as ActiveCampaign will empty the fields if they are empty.
|
||||
if (isset($name[0]) && $name[0])
|
||||
{
|
||||
$data['contact']['firstName'] = $name[0];
|
||||
}
|
||||
if (isset($name[1]) && $name[1])
|
||||
{
|
||||
$data['contact']['lastName'] = $name[1];
|
||||
}
|
||||
|
||||
$this->post($apiAction, $data);
|
||||
|
||||
if (!$this->request_successful)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrive the contact's ID
|
||||
$contact_id = $this->getContactIDFromResponse();
|
||||
|
||||
// Add Lists to Contact
|
||||
$this->addListsToContact($contact_id, $lists);
|
||||
|
||||
// Add Tags to Contact
|
||||
if (!empty($tags))
|
||||
{
|
||||
$tags = is_array($tags) ? $tags : explode(',', $tags);
|
||||
|
||||
$tag_ids = $this->convertTagNamesToIDs($tags);
|
||||
|
||||
if ($tag_ids && !empty($tag_ids))
|
||||
{
|
||||
$this->addTagsToContact($tag_ids, $contact_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Add Custom Fields to Contact
|
||||
$this->addCustomFieldsToContact($customfields, $contact_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phone number of the contact.
|
||||
*
|
||||
* @param array $customfields
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPhone($customfields)
|
||||
{
|
||||
$phone = $this->getCustomFieldValue('phone', $customfields);
|
||||
|
||||
if (is_string($phone))
|
||||
{
|
||||
return $phone;
|
||||
}
|
||||
|
||||
if (isset($phone['code']) && isset($phone['value']) && $phone['value'])
|
||||
{
|
||||
$calling_code = \NRFramework\Countries::getCallingCodeByCountryCode($phone['code']);
|
||||
$calling_code = $calling_code !== '' ? '+' . $calling_code : '';
|
||||
|
||||
$phone = $calling_code . $phone['value'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$phone = '';
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Custom Field Values for a Contact
|
||||
*
|
||||
* API Reference: https://developers.activecampaign.com/v3/reference#fieldvalues
|
||||
*
|
||||
* @param array $custom_fields Array of custom field values
|
||||
* @param integer $contact_id The contact's ID
|
||||
*
|
||||
* @return mixed Null on failure, void on success
|
||||
*/
|
||||
private function addCustomFieldsToContact($custom_fields, $contact_id)
|
||||
{
|
||||
if (empty($custom_fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$custom_fields = array_change_key_case($custom_fields);
|
||||
|
||||
if (!$all_custom_fields = $this->getAllCustomFields())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($custom_fields as $custom_field_key => $custom_field_value)
|
||||
{
|
||||
if (empty($custom_field_value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$custom_field = strtolower(trim($custom_field_key));
|
||||
|
||||
if (!array_key_exists($custom_field, $all_custom_fields))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Let's add Custom Field to our contact
|
||||
$custom_field_data = $all_custom_fields[$custom_field];
|
||||
|
||||
// Radio buttons expect a string. Not an array.
|
||||
if ($custom_field_data['type'] == 'checkbox' && is_array($custom_field_value))
|
||||
{
|
||||
$custom_field_value = implode('||', $custom_field_value);
|
||||
$custom_field_value = '||' . $custom_field_value . '||';
|
||||
}
|
||||
|
||||
$this->post('fieldValues', [
|
||||
'fieldValue' => [
|
||||
'contact' => $contact_id,
|
||||
'field' => $custom_field_data['id'],
|
||||
'value' => $custom_field_value
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tags to contact
|
||||
*
|
||||
* API Reference: https://developers.activecampaign.com/v3/reference#create-contact-tag
|
||||
*
|
||||
* @param array $tag_ids Array of tag IDs
|
||||
* @param integer $contact_id The contact's ID
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addTagsToContact($tag_ids, $contact_id)
|
||||
{
|
||||
foreach ($tag_ids as $tag_id)
|
||||
{
|
||||
$this->post('contactTags', [
|
||||
'contactTag' => [
|
||||
'contact' => $contact_id,
|
||||
'tag' => $tag_id,
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of tag names to tag IDs
|
||||
*
|
||||
* @param array $tags Array ot tag names
|
||||
*
|
||||
* @return mixed Null on failure, assosiative tag name-based array on success.
|
||||
*/
|
||||
private function convertTagNamesToIDs($tags)
|
||||
{
|
||||
if (!$account_tags = $this->getAllTags())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$account_tags = array_map('strtolower', $account_tags);
|
||||
|
||||
$tag_ids = [];
|
||||
|
||||
foreach ($tags as $tag)
|
||||
{
|
||||
if (empty($tag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$tag = strtolower(trim($tag));
|
||||
|
||||
if (!$tag_id = array_search($tag, $account_tags))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$tag_ids[] = $tag_id;
|
||||
}
|
||||
|
||||
return $tag_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all contact-based tags
|
||||
*
|
||||
* API Reference: https://developers.activecampaign.com/v3/reference#list-all-tasks
|
||||
*
|
||||
* @return mixed Null on failure, assosiative array on success
|
||||
*/
|
||||
private function getAllTags()
|
||||
{
|
||||
$tags = $this->get('tags');
|
||||
|
||||
if (!$tags || !is_array($tags) || !isset($tags['tags']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$tags_ = [];
|
||||
|
||||
foreach ($tags['tags'] as $tag)
|
||||
{
|
||||
if ($tag['tagType'] != 'contact')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$tags_[$tag['id']] = $tag['tag'];
|
||||
}
|
||||
|
||||
return $tags_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add lists to contact
|
||||
*
|
||||
* @param integer $contact_id The Active Campaign Contact ID
|
||||
* @param mixed $lists The list ID to add the contact to.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addListsToContact($contact_id, $lists)
|
||||
{
|
||||
$lists = is_array($lists) ? $lists : explode(',', $lists);
|
||||
|
||||
foreach ($lists as $list)
|
||||
{
|
||||
$this->post('contactLists', [
|
||||
'contactList' => [
|
||||
'list' => $list,
|
||||
'contact' => $contact_id,
|
||||
'status' => 1
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the newly created contact's ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getContactIDFromResponse()
|
||||
{
|
||||
$response = $this->last_response;
|
||||
|
||||
if (isset($response->body) && isset($response->body['contact']) && isset($response->body['contact']['id']))
|
||||
{
|
||||
return $response->body['contact']['id'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for First Name and Last Name in Custom Fields and return an array with both values.
|
||||
*
|
||||
* @param array $customfields The Custom Fields array passed by the user.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getNameFromCustomFields($customfields)
|
||||
{
|
||||
return [
|
||||
(string) $this->getCustomFieldValue(['first_name', 'First Name'], $customfields),
|
||||
(string) $this->getCustomFieldValue(['last_name', 'Last Name'], $customfields)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all account lists
|
||||
*
|
||||
* API Reference: https://developers.activecampaign.com/v3/reference#retrieve-all-lists
|
||||
*
|
||||
* @return mixed Null on failure, Array on success
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = $this->get('lists');
|
||||
|
||||
if (!$data || !isset($data['lists']) || count($data['lists']) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = [];
|
||||
|
||||
foreach ($data['lists'] as $list)
|
||||
{
|
||||
$lists[] = [
|
||||
'id' => $list['id'],
|
||||
'name' => $list['name']
|
||||
];
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* API Reference: https://developers.activecampaign.com/v3/reference#errors
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$error_code = $this->last_response->code;
|
||||
$error_message = 'Active Campaign Error';
|
||||
|
||||
switch ((int) $error_code)
|
||||
{
|
||||
case 403:
|
||||
$error_message = 'The request could not be authenticated or the authenticated user is not authorized to access the requested resource.';
|
||||
break;
|
||||
case 404:
|
||||
$error_message = 'The requested resource does not exist.';
|
||||
break;
|
||||
case 422:
|
||||
$error_message = 'The request could not be processed, usually due to a missing or invalid parameter.';
|
||||
|
||||
if (isset($this->last_response->body['errors']) && isset($this->last_response->body['errors'][0]))
|
||||
{
|
||||
$error_message = $this->last_response->body['errors'][0]['title'];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $error_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Active Campaign Account's Custom Fields
|
||||
*
|
||||
* API Reference: https://developers.activecampaign.com/v3/reference#retrieve-fields-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllCustomFields()
|
||||
{
|
||||
$fields = $this->get('fields');
|
||||
|
||||
if (!$fields || !isset($fields['fields']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Make our life easier by creating a title-based assosiative array
|
||||
$f = [];
|
||||
|
||||
foreach ($fields['fields'] as $key => $field)
|
||||
{
|
||||
if (!$field || !isset($field['title']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = strtolower(trim($field['title']));
|
||||
|
||||
$f[$key] = $field;
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP GET request for retrieving data.
|
||||
*
|
||||
* ActiveCampaign has a limit of max 100 results per page.
|
||||
* https://developers.activecampaign.com/reference#pagination
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
*
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function get($method, $args = array())
|
||||
{
|
||||
$args['limit'] = isset($args['limit']) ? $args['limit'] : 100;
|
||||
$args['offset'] = isset($args['offset']) ? $args['offset'] : 0;
|
||||
|
||||
$response = parent::get($method, $args);
|
||||
|
||||
if ($args['offset'] < (int) $response['meta']['total'])
|
||||
{
|
||||
$args['offset'] += $args['limit'];
|
||||
$response_next = $this->get($method, $args);
|
||||
$response[$method] = array_merge($response[$method], $response_next[$method]);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
118
plugins/system/nrframework/NRFramework/Integrations/Brevo.php
Normal file
118
plugins/system/nrframework/NRFramework/Integrations/Brevo.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class Brevo extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options);
|
||||
$this->setEndpoint('https://api.brevo.com/v3');
|
||||
$this->options->set('headers.api-key', $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes a user to a Brevo Account
|
||||
*
|
||||
* API Reference v3:
|
||||
* https://developers.brevo.com/reference/createcontact
|
||||
*
|
||||
* @param string $email The user's email
|
||||
* @param array $params All the form fields
|
||||
* @param string $listid The List ID
|
||||
* @param boolean $update_existing Whether to update the existing contact (Only in v3)
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function subscribe($email, $params, $listid = false, $update_existing = true)
|
||||
{
|
||||
$data = [
|
||||
'email' => $email,
|
||||
'attributes' => (object) $params,
|
||||
'updateEnabled' => $update_existing
|
||||
];
|
||||
|
||||
if ($listid)
|
||||
{
|
||||
$data['listIds'] = [(int) $listid];
|
||||
}
|
||||
|
||||
$this->post('contacts', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Campaign lists
|
||||
*
|
||||
* API Reference v3:
|
||||
* https://developers.brevo.com/reference/getlists-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = [
|
||||
'offset' => 0,
|
||||
'limit' => 50
|
||||
];
|
||||
|
||||
$lists = [];
|
||||
|
||||
$data = $this->get('contacts/lists', $data);
|
||||
|
||||
// sanity check
|
||||
if (!isset($data['lists']) || !is_array($data['lists']) || $data['count'] == 0)
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data['lists'] as $key => $list)
|
||||
{
|
||||
$lists[] = [
|
||||
'id' => $list['id'],
|
||||
'name' => $list['name']
|
||||
];
|
||||
}
|
||||
|
||||
return $lists;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* API Reference:
|
||||
* https://developers.brevo.com/docs/how-it-works#error-codes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
$message = '';
|
||||
|
||||
if (!isset($body['code']))
|
||||
{
|
||||
return $message;
|
||||
}
|
||||
|
||||
return $body['message'];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class CampaignMonitor extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options);
|
||||
$this->setEndpoint('https://api.createsend.com/api/v3.1');
|
||||
$this->options->set('userauth', $this->key);
|
||||
$this->options->set('passwordauth', 'nopass');
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to Campaign Monitor
|
||||
*
|
||||
* API References:
|
||||
* https://www.campaignmonitor.com/api/subscribers/#importing_many_subscribers
|
||||
* Reminder:
|
||||
* The classic add_subscriber method of Campaign Monitor's API is NOT instantaneous!
|
||||
* It is suggested to use their import method for instantaneous subscriptions!
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $name User's Name
|
||||
* @param string $list The Campaign Monitor list unique ID
|
||||
* @param array $custom_fields Custom Fields
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $name, $list, $customFields = array())
|
||||
{
|
||||
$data = array(
|
||||
'Subscribers' => array(
|
||||
array(
|
||||
'EmailAddress' => $email,
|
||||
'Name' => $name,
|
||||
'Resubscribe' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (is_array($customFields) && count($customFields))
|
||||
{
|
||||
$data['Subscribers'][0]['CustomFields'] = $this->validateCustomFields($customFields, $list);
|
||||
}
|
||||
|
||||
$this->post('subscribers/' . $list . '/import.json', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array with valid only custom fields
|
||||
*
|
||||
* @param array $formCustomFields Array of custom fields
|
||||
*
|
||||
* @return array Array of valid only custom fields
|
||||
*/
|
||||
public function validateCustomFields($formCustomFields, $list)
|
||||
{
|
||||
$fields = array();
|
||||
|
||||
if (!is_array($formCustomFields))
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$listCustomFields = $this->get('lists/' . $list . '/customfields.json');
|
||||
|
||||
if (!$this->request_successful)
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$formCustomFieldsKeys = array_keys($formCustomFields);
|
||||
|
||||
foreach ($listCustomFields as $listCustomField)
|
||||
{
|
||||
$field_name = $listCustomField['FieldName'];
|
||||
|
||||
if (!in_array($field_name, $formCustomFieldsKeys))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $formCustomFields[$field_name];
|
||||
|
||||
// Always convert custom field value to array, to support multiple values in a custom field.
|
||||
$value = is_array($value) ? $value : (array) $value;
|
||||
|
||||
foreach ($value as $val)
|
||||
{
|
||||
$fields[] = array(
|
||||
'Key' => $field_name,
|
||||
'Value' => $val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
$message = '';
|
||||
|
||||
if (isset($body['Message']))
|
||||
{
|
||||
$message = $body['Message'];
|
||||
}
|
||||
|
||||
if (isset($body['ResultData']['FailureDetails'][0]['Message']))
|
||||
{
|
||||
$message .= ' - ' . $body['ResultData']['FailureDetails'][0]['Message'];
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Client lists
|
||||
*
|
||||
* https://www.campaignmonitor.com/api/clients/#getting-subscriber-lists
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$clients = $this->getClients();
|
||||
|
||||
if (!is_array($clients))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = array();
|
||||
|
||||
foreach ($clients as $key => $client)
|
||||
{
|
||||
if (!isset($client['ClientID']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$clientLists = $this->get('/clients/' . $client['ClientID'] . '/lists.json');
|
||||
|
||||
if (!is_array($clientLists))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($clientLists as $key => $clientList)
|
||||
{
|
||||
$lists[] = array(
|
||||
'id' => $clientList['ListID'],
|
||||
'name' => $clientList['Name']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Clients
|
||||
*
|
||||
* https://www.campaignmonitor.com/api/account/
|
||||
*
|
||||
* @return mixed Array on success, Null on fail
|
||||
*/
|
||||
private function getClients()
|
||||
{
|
||||
$clients = $this->get('/clients.json');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return $clients;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
class ConvertKit extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param string $api_key Your ConvertKit API Key
|
||||
*/
|
||||
public function __construct($api_key)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->setKey($api_key);
|
||||
$this->setEndpoint('https://api.convertkit.com/v3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe a user to a ConvertKit Form
|
||||
*
|
||||
* API Reference:
|
||||
* http://help.convertkit.com/article/33-api-documentation-v3
|
||||
*
|
||||
* @param string $email The subscriber's email
|
||||
* @param string $formid The account owner's form id
|
||||
* @param array $params The form's parameters
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function subscribe($email, $formid, $params)
|
||||
{
|
||||
$first_name = (isset($params['first_name'])) ? $params['first_name'] : '';
|
||||
$tags = (isset($params['tags'])) ? $this->convertTagnamesToTagIDs($params['tags']) : '';
|
||||
$fields = $this->validateCustomFields($params);
|
||||
|
||||
$data = array(
|
||||
'api_key' => $this->key,
|
||||
'email' => $email,
|
||||
'first_name' => $first_name,
|
||||
'tags' => $tags,
|
||||
'fields' => $fields,
|
||||
);
|
||||
|
||||
$this->post('forms/' . $formid . '/subscribe', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts tag names to tag IDs for the subscribe method
|
||||
*
|
||||
* @param string $tagnames comma separated list of tagnames
|
||||
*
|
||||
* @return string comma separated list of tag IDs
|
||||
*/
|
||||
public function convertTagnamesToTagIDs($tagnames)
|
||||
{
|
||||
if (empty($tagnames))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$tagArray = !is_array($tagnames) ? explode(',', $tagnames) : $tagnames;
|
||||
$tagnames = array_map('trim', $tagArray);
|
||||
$accountTags = $this->get('tags', array('api_key' => $this->key));
|
||||
|
||||
if (empty($accountTags) || !$this->request_successful)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$tagIDs = array();
|
||||
|
||||
foreach ($accountTags['tags'] as $tag)
|
||||
{
|
||||
foreach ($tagnames as $tagname)
|
||||
{
|
||||
if (StringHelper::strcasecmp($tag['name'], $tagname) == 0)
|
||||
{
|
||||
$tagIDs[] = $tag['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode(',', $tagIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array with valid only custom fields
|
||||
*
|
||||
* @param array $formCustomFields Array of custom fields
|
||||
*
|
||||
* @return array Array of valid only custom fields
|
||||
*/
|
||||
public function validateCustomFields($formCustomFields)
|
||||
{
|
||||
if (!is_array($formCustomFields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$customFields = $this->get('custom_fields', array('api_key' => $this->key));
|
||||
|
||||
if (!$this->request_successful)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = array();
|
||||
|
||||
$formCustomFieldsKeys = array_keys($formCustomFields);
|
||||
|
||||
foreach ($customFields['custom_fields'] as $customField)
|
||||
{
|
||||
if (in_array($customField['key'], $formCustomFieldsKeys))
|
||||
{
|
||||
$fields[$customField['key']] = $formCustomFields[$customField['key']];
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
$message = '';
|
||||
|
||||
if (isset($body['error']) && !empty($body['error']))
|
||||
{
|
||||
$message = $body['error'];
|
||||
}
|
||||
|
||||
if (isset($body['message']) && !empty($body['message']))
|
||||
{
|
||||
$message .= ' - ' . $body['message'];
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
287
plugins/system/nrframework/NRFramework/Integrations/Drip.php
Normal file
287
plugins/system/nrframework/NRFramework/Integrations/Drip.php
Normal file
@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class Drip extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param string $key Your Drip API key
|
||||
* @param string $account_id Your Drip Account ID
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!(isset($options['api']) && isset($options['account_id']))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setKey($options['api']);
|
||||
$this->setEndpoint('https://api.getdrip.com/v2/' . $options['account_id']);
|
||||
$this->options->set('headers.Authorization', 'Basic ' . base64_encode($this->key . ':'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to Drip
|
||||
*
|
||||
* API References:
|
||||
* https://developer.drip.com/#create-or-update-a-subscriber
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $campaign_id The Campaign ID
|
||||
* @param string $name The name of the Contact (Name can be also declared in Custom Fields)
|
||||
* @param Object $custom_fields Custom Fields
|
||||
* @param mixed $tags Tags for this contact (comma-separated). Example: 'tag1, tag2, etc'
|
||||
* @param boolean $update_existing Update existing user
|
||||
* @param boolean $double_optin Send MailChimp confirmation email?
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $campaign_id, $name = null, $custom_fields = array(), $tags = '', $update_existing = true, $double_optin = false)
|
||||
{
|
||||
// Detect name
|
||||
$name = (is_null($name) || empty($name)) ? $this->getNameFromCustomFields($custom_fields) : explode(' ', $name, 2);
|
||||
|
||||
// We use this boolean to see if the user has subscribed the campaign
|
||||
// This is used for the `update_existing` parameter
|
||||
$subscriber_exists = $this->subscriberIsInCampaign($email, $campaign_id);
|
||||
|
||||
// Check if we need to update the user
|
||||
if ($update_existing == false && $subscriber_exists)
|
||||
{
|
||||
throw new \Exception(Text::_('NR_YOU_ARE_ALREADY_A_SUBSCRIBER'), 1);
|
||||
}
|
||||
|
||||
// Remove tags from custom fields
|
||||
$custom_fields_parse = $custom_fields;
|
||||
if (isset($custom_fields_parse['tags']))
|
||||
{
|
||||
unset($custom_fields_parse['tags']);
|
||||
}
|
||||
|
||||
// Create or Update a Subscriber
|
||||
$data = [
|
||||
'subscribers' => [
|
||||
[
|
||||
'email' => $email,
|
||||
'first_name' => isset($name[0]) ? $name[0] : '',
|
||||
'last_name' => isset($name[1]) ? $name[1] : '',
|
||||
'address1' => $this->getCustomFieldValue('address1', $custom_fields),
|
||||
'address2' => $this->getCustomFieldValue('address2', $custom_fields),
|
||||
'city' => $this->getCustomFieldValue('city', $custom_fields),
|
||||
'state' => $this->getCustomFieldValue('state', $custom_fields),
|
||||
'zip' => $this->getCustomFieldValue('zip', $custom_fields),
|
||||
'country' => $this->getCustomFieldValue('country', $custom_fields),
|
||||
'phone' => $this->getCustomFieldValue('phone', $custom_fields),
|
||||
'custom_fields' => $custom_fields_parse,
|
||||
'tags' => $this->getTags($tags)
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$this->post('subscribers', $data);
|
||||
|
||||
// If we are updating a user, dont try re-assigning him to a campaign
|
||||
// If we are updating a user but he just subscribed, then assign him to a campaign
|
||||
if ($update_existing == false || $subscriber_exists == false)
|
||||
{
|
||||
// Assign the newly created subscriber to the campaign
|
||||
$this->assignSubscriberToCampaign($email, $campaign_id, $double_optin);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a Subscriber to a Campaign
|
||||
*
|
||||
* https://developer.drip.com/?shell#subscribe-someone-to-a-campaign
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assignSubscriberToCampaign($email, $campaign_id, $double_optin)
|
||||
{
|
||||
|
||||
// Subscribe user to a campaign
|
||||
$campaignSubAPI = 'campaigns/' . $campaign_id . '/subscribers';
|
||||
|
||||
$data = [
|
||||
'subscribers' => [
|
||||
[
|
||||
'email' => $email,
|
||||
'double_optin' => (bool) $double_optin
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$this->post($campaignSubAPI, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tags or an empty string if no tags provided
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getTags($tags) {
|
||||
|
||||
if (empty($tags))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($tags))
|
||||
{
|
||||
$tags = array_map('trim', explode(',', $tags));
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the subscriber is in a campaign
|
||||
*
|
||||
* https://developer.drip.com/?shell#list-all-of-a-subscriber-39-s-campaign-subscriptions
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function subscriberIsInCampaign($email, $campaign_id)
|
||||
{
|
||||
$found_campaign = false;
|
||||
|
||||
$subscriber_id = $this->getSubscriberIdFromEmail($email);
|
||||
|
||||
// Use does not exist in Drip
|
||||
if (empty($subscriber_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$subscriber_campaigns = $this->getSubscriberCampaigns($subscriber_id);
|
||||
|
||||
foreach ($subscriber_campaigns as $c)
|
||||
{
|
||||
if ($c['campaign_id'] == $campaign_id)
|
||||
{
|
||||
$found_campaign = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $found_campaign;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the subscriber from email
|
||||
*
|
||||
* https://developer.drip.com/?shell#fetch-a-subscriber
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getSubscriberIdFromEmail($email)
|
||||
{
|
||||
$data = $this->get('subscribers/' . $email);
|
||||
|
||||
return isset($data['subscribers']) ? $data['subscribers'][0]['id'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all subscriber's campaigns
|
||||
*
|
||||
* https://developer.drip.com/?javascript#list-all-of-a-subscriber-39-s-campaign-subscriptions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getSubscriberCampaigns($subscriberId)
|
||||
{
|
||||
$data = $this->get('subscribers/' . $subscriberId . '/campaign_subscriptions');
|
||||
|
||||
return isset($data['campaign_subscriptions']) ? $data['campaign_subscriptions'] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available Drip campaigns
|
||||
*
|
||||
* https://developer.drip.com/?shell#list-all-campaigns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = $this->get('campaigns');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($data['campaigns']) || !is_array($data['campaigns']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$campaigns = [];
|
||||
|
||||
foreach ($data['campaigns'] as $key => $campaign)
|
||||
{
|
||||
$campaigns[] = array(
|
||||
'id' => $campaign['id'],
|
||||
'name' => $campaign['name']
|
||||
);
|
||||
}
|
||||
|
||||
return $campaigns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for First Name and Last Name in Custom Fields and return an array with both values.
|
||||
*
|
||||
* @param array $custom_fields The Custom Fields array passed by the user.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getNameFromCustomFields($custom_fields)
|
||||
{
|
||||
return [
|
||||
(string) $this->getCustomFieldValue(['first_name', 'First Name'], $custom_fields),
|
||||
(string) $this->getCustomFieldValue(['last_name', 'Last Name'], $custom_fields)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
$messages = '';
|
||||
|
||||
if (isset($body['errors']))
|
||||
{
|
||||
foreach ($body['errors'] as $error)
|
||||
{
|
||||
$messages .= ' - ' . $error['message'];
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class ElasticEmail extends Integration
|
||||
{
|
||||
protected $endpoint = 'https://api.elasticemail.com/v2';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to ElasticEmail
|
||||
*
|
||||
* API References:
|
||||
* http://api.elasticemail.com/public/help#Contact_Add
|
||||
* http://api.elasticemail.com/public/help#Contact_Update
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $list The ElasticEmail List unique ID
|
||||
* @param string $publicAccountID The ElasticEmail PublicAccountID
|
||||
* @param array $params The form's parameters
|
||||
* @param boolean $update_existing Update existing user
|
||||
* @param boolean $double_optin Send ElasticEmail confirmation email?
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $list, $publicAccountID, $params = array(), $update_existing = true, $double_optin = false)
|
||||
{
|
||||
$data = array(
|
||||
'apikey' => $this->key,
|
||||
'email' => $email,
|
||||
'publicAccountID' => $publicAccountID,
|
||||
'publicListID' => $list,
|
||||
'sendActivation' => $double_optin ? 'true' : 'false',
|
||||
'consentIP' => \NRFramework\User::getIP()
|
||||
);
|
||||
|
||||
if (is_array($params) && count($params))
|
||||
{
|
||||
foreach ($params as $param_key => $param_value)
|
||||
{
|
||||
$data[$param_key] = (is_array($param_value)) ? implode(',', $param_value) : $param_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$update_existing)
|
||||
{
|
||||
return $this->get('/contact/add', $data);
|
||||
}
|
||||
|
||||
if ($this->getContact($email))
|
||||
{
|
||||
$data['clearRestOfFields'] = 'false';
|
||||
$this->get('/contact/update', $data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->get('/contact/add', $data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available ElasticEmail lists
|
||||
*
|
||||
* http://api.elasticemail.com/public/help#List_list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = $this->get('/list/list', array('apikey' => $this->key));
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = array();
|
||||
|
||||
if (!isset($data['data']) || !is_array($data['data']))
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data['data'] as $key => $list)
|
||||
{
|
||||
$lists[] = array(
|
||||
'id' => $list['publiclistid'],
|
||||
'name' => $list['listname']
|
||||
);
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a contact exists
|
||||
*
|
||||
* @param string $email The contact's email
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getContact($email)
|
||||
{
|
||||
$contact = $this->get('/contact/loadcontact', array('apikey' => $this->key, 'email' => $email));
|
||||
|
||||
return (bool) $contact['success'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Elastic Email Public Account ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPublicAccountID()
|
||||
{
|
||||
$data = $this->get('/account/load', array('apikey' => $this->key));
|
||||
|
||||
if (isset($data['data']['publicaccountid']))
|
||||
{
|
||||
return $data['data']['publicaccountid'];
|
||||
}
|
||||
|
||||
throw new \Exception(Text::_('NR_ELASTICEMAIL_UNRETRIEVABLE_PUBLICACCOUNTID'), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (isset($body['error']))
|
||||
{
|
||||
return $body['error'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
protected function determineSuccess()
|
||||
{
|
||||
$code = $this->last_response->code;
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if ($code >= 200 && $code <= 299 && !isset($body['error']))
|
||||
{
|
||||
return ($this->request_successful = true);
|
||||
}
|
||||
|
||||
$this->last_error = 'Unknown error, call getLastResponse() to find out what happened.';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class GetResponse extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options);
|
||||
$this->endpoint = 'https://api.getresponse.com/v3';
|
||||
$this->options->set('headers.X-Auth-Token', 'api-key ' . $this->key);
|
||||
$this->options->set('headers.Accept-Encoding', 'gzip,deflate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to GetResponse Campaign
|
||||
*
|
||||
* https://apidocs.getresponse.com/v3/resources/contacts#contacts.create
|
||||
*
|
||||
* TODO: Update existing contact
|
||||
*
|
||||
* @param string $email Email of the Contact
|
||||
* @param string $name The name of the Contact
|
||||
* @param int $dayOfCycle Enter 0 to add to the start day of the cycle.
|
||||
* @param object $campaign Campaign ID
|
||||
* @param object $customFields Collection of custom fields
|
||||
* @param object $update_existing Update existing contact
|
||||
* @param array $tags Set user tags
|
||||
* @param string $tags_replace Determines what changes to make to the subscriber's tags. Values: add_only, replace_all
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $name, $campaign, $customFields, $update_existing, $dayOfCycle = 0, $tags = [], $tags_replace = 'add_only')
|
||||
{
|
||||
$data = [
|
||||
'email' => $email,
|
||||
'name' => $name,
|
||||
'dayOfCycle' => $dayOfCycle,
|
||||
'campaign' => ['campaignId' => $campaign],
|
||||
'customFieldValues' => $this->validateCustomFields($customFields),
|
||||
'ipAddress' => \NRFramework\User::getIP()
|
||||
];
|
||||
|
||||
if (empty($name) || is_null($name))
|
||||
{
|
||||
unset($data['name']);
|
||||
}
|
||||
|
||||
$contactId = null;
|
||||
$service_tags = [];
|
||||
|
||||
if ($tags)
|
||||
{
|
||||
$service_tags = $this->getServiceTags();
|
||||
}
|
||||
|
||||
// Replace all existing contact tags with new ones
|
||||
if ($tags && $tags_replace === 'replace_all')
|
||||
{
|
||||
$data['tags'] = $this->validateTags($tags, $service_tags, $tags_replace);
|
||||
}
|
||||
|
||||
if ($update_existing)
|
||||
{
|
||||
$contactId = $this->getContact($email);
|
||||
}
|
||||
|
||||
$endpoint = 'contacts';
|
||||
$endpoint = !empty($contactId) ? $endpoint . '/' . $contactId : $endpoint;
|
||||
|
||||
$this->post($endpoint, $data);
|
||||
|
||||
// Add new tags to the contact
|
||||
if ($tags && $tags_replace === 'add_only' && $contactId)
|
||||
{
|
||||
$data = ['tags' => $this->validateTags($tags, $service_tags, $tags_replace)];
|
||||
|
||||
$this->post('contacts/' . $contactId . '/tags', $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all service tags.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getServiceTags()
|
||||
{
|
||||
$tags = [];
|
||||
|
||||
foreach ($this->get('tags') as $tag)
|
||||
{
|
||||
$tags[$tag['tagId']] = $tag['name'];
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and returns the valid tags.
|
||||
*
|
||||
* @param array $tags
|
||||
* @param array $service_tags
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function validateTags($tags = [], $service_tags = [], $tags_replace = 'add_only')
|
||||
{
|
||||
$final_tags = [];
|
||||
|
||||
foreach ($tags as $index => $tag)
|
||||
{
|
||||
$valid = false;
|
||||
|
||||
// Find tag in service tags and add it to final tags list
|
||||
foreach ($service_tags as $tagId => $tagName)
|
||||
{
|
||||
if ($tagId === $tag || $tagName === $tag)
|
||||
{
|
||||
$valid = true;
|
||||
|
||||
// Add to final list
|
||||
$final_tags[] = [
|
||||
'tagId' => $tagId
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Add invalid tags
|
||||
if (!$valid && $tags_replace == 'add_only')
|
||||
{
|
||||
$new_tag = $this->createTag($tag);
|
||||
$final_tags[] = [
|
||||
'tagId' => $new_tag['tagId']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $final_tags;
|
||||
}
|
||||
|
||||
private function createTag($tag)
|
||||
{
|
||||
$data = [
|
||||
'name' => $tag
|
||||
];
|
||||
|
||||
return $this->post('tags', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array with valid only custom fields
|
||||
*
|
||||
* @param array $customFields Array of custom fields
|
||||
*
|
||||
* @return array Array of valid only custom fields
|
||||
*/
|
||||
public function validateCustomFields($customFields)
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
if (!is_array($customFields))
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$accountCustomFields = $this->get('custom-fields');
|
||||
|
||||
if (!$this->request_successful)
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
foreach ($accountCustomFields as $key => $customField)
|
||||
{
|
||||
if (!isset($customFields[$customField['name']]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields[] = [
|
||||
'customFieldId' => $customField['customFieldId'],
|
||||
'value' => [$customFields[$customField['name']]]
|
||||
];
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
* If something didn't work, this should contain the string describing the problem.
|
||||
*
|
||||
* @return string describing the error
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (!isset($body['context']) || !isset($body['context'][0]))
|
||||
{
|
||||
return $body['codeDescription'] . ' - ' . $body['message'];
|
||||
}
|
||||
|
||||
$error = $body['context'][0];
|
||||
|
||||
// GetResponse returns a JSON string as $error and we try to decode it so we can return a more human-friendly error message
|
||||
$error = is_string($error) && json_encode($error, true) ? json_decode($error, true) : $error;
|
||||
|
||||
if (is_array($error) && isset($error['fieldName']))
|
||||
{
|
||||
$errorFieldName = is_array($error['fieldName']) ? implode(' ', $error['fieldName']) : $error['fieldName'];
|
||||
return $errorFieldName . ': ' . $error['message'];
|
||||
}
|
||||
|
||||
return (is_array($error)) ? implode(' ', $error) : $error;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available GetResponse campaigns
|
||||
*
|
||||
* https://apidocs.getresponse.com/v3/resources/campaigns#campaigns.get.all
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = $this->get('campaigns');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($data) || !count($data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = [];
|
||||
|
||||
foreach ($data as $key => $list)
|
||||
{
|
||||
$lists[] = [
|
||||
'id' => $list['campaignId'],
|
||||
'name' => $list['name']
|
||||
];
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Contact resource
|
||||
*
|
||||
* @param string $email The email of the contact which we want to retrieve
|
||||
*
|
||||
* @return string The Contact ID
|
||||
*/
|
||||
public function getContact($email)
|
||||
{
|
||||
if (!isset($email))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->get('contacts', ['query[email]' => $email]);
|
||||
|
||||
if (empty($data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// the returned data is an array with only one contact
|
||||
$contactId = $data[0]['contactId'];
|
||||
|
||||
return ($contactId) ? $contactId : null;
|
||||
|
||||
}
|
||||
}
|
||||
109
plugins/system/nrframework/NRFramework/Integrations/HCaptcha.php
Normal file
109
plugins/system/nrframework/NRFramework/Integrations/HCaptcha.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* The HCaptcha Wrapper
|
||||
*/
|
||||
class HCaptcha extends Integration
|
||||
{
|
||||
/**
|
||||
* Service Endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint = 'https://hcaptcha.com/siteverify';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!array_key_exists('secret', $options))
|
||||
{
|
||||
$this->setError('NR_RECAPTCHA_INVALID_SECRET_KEY');
|
||||
throw new \Exception($this->getLastError());
|
||||
}
|
||||
|
||||
$this->setKey($options['secret']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the hCaptcha siteverify API to verify whether the user passes hCaptcha test.
|
||||
*
|
||||
* @param string $response Response string from hCaptcha verification.
|
||||
* @param string $remoteip IP address of end user
|
||||
*
|
||||
* @return bool Returns true if the user passes hCaptcha test
|
||||
*/
|
||||
public function validate($response, $remoteip = null)
|
||||
{
|
||||
if (empty($response) || is_null($response))
|
||||
{
|
||||
return $this->setError('NR_RECAPTCHA_PLEASE_VALIDATE');
|
||||
}
|
||||
|
||||
// remove these headers in order for hCaptcha to be abl to process the request
|
||||
$this->options->remove('headers.Accept');
|
||||
$this->options->remove('headers.Content-Type');
|
||||
|
||||
// do not encode request
|
||||
$this->setEncode(false);
|
||||
|
||||
$data = [
|
||||
'secret' => $this->key,
|
||||
'response' => $response,
|
||||
];
|
||||
|
||||
$this->post('', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
protected function determineSuccess()
|
||||
{
|
||||
$success = parent::determineSuccess();
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if ($body['success'] == false && array_key_exists('error-codes', $body) && count($body['error-codes']) > 0)
|
||||
{
|
||||
$success = $this->setError(implode(', ', $body['error-codes']));
|
||||
}
|
||||
|
||||
return ($this->request_successful = $success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set wrapper error text
|
||||
*
|
||||
* @param String $error The error message to display
|
||||
*/
|
||||
private function setError($error)
|
||||
{
|
||||
$this->last_error = Text::_('NR_HCAPTCHA') . ': ' . Text::_($error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
140
plugins/system/nrframework/NRFramework/Integrations/HubSpot.php
Normal file
140
plugins/system/nrframework/NRFramework/Integrations/HubSpot.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class HubSpot extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param string $key Your HubSpot API key
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->setKey(is_array($options) ? $options['api'] : $options);
|
||||
$this->setEndpoint('https://api.hubapi.com');
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to HubSpot
|
||||
*
|
||||
* API References:
|
||||
* http://developers.hubspot.com/docs/methods/contacts/update_contact-by-email
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $params The forms extra fields
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $params)
|
||||
{
|
||||
$fields = $this->validateCustomFields($params);
|
||||
|
||||
$fields[] = array('property' => 'email', 'value' => $email);
|
||||
|
||||
$data = array(
|
||||
'properties' => $fields
|
||||
);
|
||||
|
||||
$this->post('contacts/v1/contact/createOrUpdate/email/' . $email . '/?hapikey=' . $this->key, $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* API References:
|
||||
* http://developers.hubspot.com/docs/faq/api-error-responses
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
$message = '';
|
||||
|
||||
if ((isset($body['status'])) && ($body['status'] == 'error'))
|
||||
{
|
||||
$message = $body['message'];
|
||||
}
|
||||
|
||||
if (isset($body['validationResults']) && is_array($body['validationResults']) && count($body['validationResults']))
|
||||
{
|
||||
foreach ($body['validationResults'] as $key => $validation)
|
||||
{
|
||||
if ($validation['isValid'] === false)
|
||||
{
|
||||
$message .= ' - ' . $validation['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array with valid only custom fields
|
||||
*
|
||||
* API References:
|
||||
* http://developers.hubspot.com/docs/methods/contacts/v2/get_contacts_properties
|
||||
*
|
||||
* @param array $formCustomFields Array of custom fields
|
||||
*
|
||||
* @return array Array of valid only custom fields
|
||||
*/
|
||||
public function validateCustomFields($formCustomFields)
|
||||
{
|
||||
|
||||
$fields = array();
|
||||
|
||||
if (!is_array($formCustomFields))
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$accountFields = $this->get('properties/v1/contacts/properties?hapikey='.$this->key);
|
||||
|
||||
if (!$this->request_successful)
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$accountFieldsNames = array_map(
|
||||
function ($ar)
|
||||
{
|
||||
return $ar['name'];
|
||||
}, $accountFields
|
||||
);
|
||||
|
||||
$formCustomFieldsKeys = array_keys($formCustomFields);
|
||||
|
||||
foreach ($accountFieldsNames as $accountFieldsName)
|
||||
{
|
||||
if (!in_array($accountFieldsName, $formCustomFieldsKeys))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields[] = array(
|
||||
"property" => $accountFieldsName,
|
||||
"value" => $formCustomFields[$accountFieldsName],
|
||||
);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
220
plugins/system/nrframework/NRFramework/Integrations/HubSpot3.php
Normal file
220
plugins/system/nrframework/NRFramework/Integrations/HubSpot3.php
Normal file
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class HubSpot3 extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param string $key Your HubSpot API key
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->setKey($options);
|
||||
|
||||
$this->setEndpoint('https://api.hubapi.com/crm/v3');
|
||||
|
||||
$this->options->set('headers.Authorization', 'Bearer ' . $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/Update a HubSpot Contact
|
||||
*
|
||||
* API References:
|
||||
* https://developers.hubspot.com/docs/api/crm/contacts
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $params The forms extra fields
|
||||
* @param bool $update_existing Set whether to update an existing user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $params, $update_existing = true)
|
||||
{
|
||||
$contact_data = $this->contactExists($email);
|
||||
|
||||
if (!$update_existing)
|
||||
{
|
||||
if ($contact_data)
|
||||
{
|
||||
throw new \Exception('Contact already exists.');
|
||||
}
|
||||
}
|
||||
|
||||
$default_property = ['email' => $email];
|
||||
|
||||
$other_properties = $this->validateCustomFields($params);
|
||||
|
||||
$data = [
|
||||
'properties' => array_merge($default_property, $other_properties)
|
||||
];
|
||||
|
||||
$method = 'post';
|
||||
$endpoint = 'objects/contacts';
|
||||
|
||||
if ($update_existing && $contact_data)
|
||||
{
|
||||
$method = 'patch';
|
||||
$endpoint .= '/' . $contact_data['id'];
|
||||
};
|
||||
|
||||
$this->$method($endpoint, $data);
|
||||
|
||||
// If a list exists, add the contact to that list.
|
||||
if ($this->success() && isset($params['list']) && !empty($params['list']))
|
||||
{
|
||||
$this->addContactToStaticList($email, $params['list']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all lists.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$this->endpoint = $this->getV1Endpoint();
|
||||
|
||||
$data = $this->get('lists/static');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($data) || !count($data) || !isset($data['lists']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = [];
|
||||
|
||||
foreach ($data['lists'] as $key => $list)
|
||||
{
|
||||
$lists[] = [
|
||||
'id' => $list['listId'],
|
||||
'name' => $list['name']
|
||||
];
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add contact to a static list.
|
||||
*
|
||||
* @param string $email
|
||||
* @param int $list_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addContactToStaticList($email, $list_id)
|
||||
{
|
||||
$this->endpoint = $this->getV1Endpoint();
|
||||
|
||||
$data = (object) [ 'emails' => [ $email ] ];
|
||||
|
||||
$this->post('lists/' . $list_id . '/add', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the v1 endpoint.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getV1Endpoint()
|
||||
{
|
||||
return 'https://api.hubapi.com/contacts/v1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether contact already exists.
|
||||
*
|
||||
* @param string $email
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function contactExists($email)
|
||||
{
|
||||
$contact = $this->get('objects/contacts/' . $email . '?idProperty=email');
|
||||
|
||||
return $this->success() ? $contact : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array with valid only custom fields
|
||||
*
|
||||
* API References:
|
||||
* https://developers.hubspot.com/docs/api/crm/properties
|
||||
*
|
||||
* @param array $formCustomFields Array of custom fields
|
||||
*
|
||||
* @return array Array of valid only custom fields
|
||||
*/
|
||||
public function validateCustomFields($formCustomFields)
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
if (!is_array($formCustomFields))
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$contactCustomFields = $this->get('properties/Contact');
|
||||
|
||||
if (!$this->request_successful)
|
||||
{
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$customFieldNames = array_map(
|
||||
function ($ar)
|
||||
{
|
||||
return $ar['name'];
|
||||
}, $contactCustomFields['results']
|
||||
);
|
||||
|
||||
$formCustomFieldsKeys = array_keys($formCustomFields);
|
||||
|
||||
foreach ($customFieldNames as $accountFieldName)
|
||||
{
|
||||
if (!in_array($accountFieldName, $formCustomFieldsKeys))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields[$accountFieldName] = $formCustomFields[$accountFieldName];
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (isset($body['status']) && $body['status'] === 'error')
|
||||
{
|
||||
return $body['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
209
plugins/system/nrframework/NRFramework/Integrations/IContact.php
Normal file
209
plugins/system/nrframework/NRFramework/Integrations/IContact.php
Normal file
@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class IContact extends Integration
|
||||
{
|
||||
public $accountID;
|
||||
|
||||
public $clientFolderID;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
* @param array $options The service's required options
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->endpoint = 'https://app.icontact.com/icp/a';
|
||||
$this->options->set('headers.API-Version', '2.2');
|
||||
$this->options->set('headers.API-AppId', $options['appID']);
|
||||
$this->options->set('headers.API-Username', $options['username']);
|
||||
$this->options->set('headers.API-Password', $options['appPassword']);
|
||||
$this->setAccountID($options['accountID']);
|
||||
$this->setClientFolderID($options['clientFolderID']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and sets the iContact AccountID
|
||||
*
|
||||
* @param mixed $accountID
|
||||
*/
|
||||
public function setAccountID($accountID = false)
|
||||
{
|
||||
if ($accountID)
|
||||
{
|
||||
$this->accountID = $accountID;
|
||||
}
|
||||
|
||||
$accounts = $this->get('');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
throw new \Exception($this->getLastError());
|
||||
}
|
||||
|
||||
// Make sure the account is active
|
||||
if (intval($accounts['accounts'][0]['enabled']) === 1)
|
||||
{
|
||||
$this->accountID = (integer) $accounts['accounts'][0]['accountId'];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception(Text::_('NR_ICONTACT_ACCOUNTID_ERROR'), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and sets the iContact ClientFolderID
|
||||
*
|
||||
* @param mixed $clientFolderID
|
||||
*/
|
||||
public function setClientFolderID($clientFolderID = false)
|
||||
{
|
||||
if ($clientFolderID)
|
||||
{
|
||||
$this->clientFolderID = $clientFolderID;
|
||||
}
|
||||
|
||||
// We need an existant accountID
|
||||
if (empty($this->accountID))
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->setAccountID();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if ($clientFolder = $this->get($this->accountID . '/c/'))
|
||||
{
|
||||
$this->clientFolderID = $clientFolder['clientfolders'][0]['clientFolderId'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes a user to an iContact List
|
||||
*
|
||||
* API REFERENCE
|
||||
* https://www.icontact.com/developerportal/documentation/contacts
|
||||
*
|
||||
* @param string $email
|
||||
* @param object $params The extra form fields
|
||||
* @param mixed $list The iContact List ID
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function subscribe($email, $params, $list)
|
||||
{
|
||||
$data = array('contact' => array_merge(array('email' => $email, 'status' => 'normal'), (array) $params));
|
||||
|
||||
try
|
||||
{
|
||||
$contact = $this->post($this->accountID .'/c/' . $this->clientFolderID . '/contacts', $data);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ((isset($contact['contacts'])) && (is_array($contact['contacts'])) && (count($contact['contacts']) > 0))
|
||||
{
|
||||
$this->addToList($list, $contact['contacts'][0]['contactId']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a contact to an iContact List
|
||||
*
|
||||
* API REFERENCE
|
||||
* https://www.icontact.com/developerportal/documentation/subscriptions
|
||||
*
|
||||
* @param string $listID
|
||||
* @param string $contactID
|
||||
*/
|
||||
public function addToList($listID, $contactID)
|
||||
{
|
||||
$data = array(
|
||||
array(
|
||||
'contactId' => $contactID,
|
||||
'listId' => $listID,
|
||||
'status' => 'normal'
|
||||
)
|
||||
);
|
||||
$this->post($this->accountID .'/c/' . $this->clientFolderID . '/subscriptions',$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Client lists
|
||||
*
|
||||
* API REFERENCE
|
||||
* https://www.icontact.com/developerportal/documentation/lists
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = $this->get($this->accountID .'/c/' . $this->clientFolderID . '/lists');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = array();
|
||||
|
||||
if (!isset($data["lists"]) || !is_array($data["lists"]))
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data["lists"] as $key => $list)
|
||||
{
|
||||
$lists[] = array(
|
||||
'id' => $list['listId'],
|
||||
'name' => $list['name']
|
||||
);
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
* If something didn't work, this should contain the string describing the problem.
|
||||
*
|
||||
* @return string describing the error
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
$message = '';
|
||||
|
||||
if (isset($body['errors']))
|
||||
{
|
||||
foreach ($body['errors'] as $error) {
|
||||
$message .= $error . ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return trim($message);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\Registry\Registry;
|
||||
use Joomla\CMS\Http\HttpFactory;
|
||||
|
||||
class Integration
|
||||
{
|
||||
protected $key;
|
||||
protected $endpoint;
|
||||
protected $request_successful = false;
|
||||
protected $last_error = '';
|
||||
protected $last_response = [];
|
||||
protected $last_request = [];
|
||||
protected $timeout = 60;
|
||||
protected $options;
|
||||
protected $encode = true;
|
||||
protected $response_type = 'json';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->options = new Registry;
|
||||
$this->options->set('timeout', $this->timeout);
|
||||
$this->options->set('headers.Accept', 'application/json');
|
||||
$this->options->set('headers.Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter method for the API Key or Access Token
|
||||
*
|
||||
* @param string $apiKey
|
||||
*/
|
||||
public function setKey($apiKey)
|
||||
{
|
||||
$apiKey = is_array($apiKey) && isset($apiKey['api']) ? $apiKey['api'] : $apiKey;
|
||||
|
||||
if (!is_string($apiKey) || empty($apiKey) || is_null($apiKey))
|
||||
{
|
||||
throw new \Exception('Invalid API Key supplied.');
|
||||
}
|
||||
|
||||
$this->key = trim($apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter method for the endpoint
|
||||
* @param string $url The URL which is set in the account's developer settings
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setEndpoint($url)
|
||||
{
|
||||
if (!empty($url))
|
||||
{
|
||||
$this->endpoint = $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception("Invalid Endpoint URL `{$url}` supplied.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the last request successful?
|
||||
* @return bool True for success, false for failure
|
||||
*/
|
||||
public function success()
|
||||
{
|
||||
return $this->request_successful;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
* If something didn't work, this should contain the string describing the problem.
|
||||
* @return array|false describing the error
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
return $this->last_error ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing the HTTP headers and the body of the API response.
|
||||
* @return array Assoc array with keys 'headers' and 'body'
|
||||
*/
|
||||
public function getLastResponse()
|
||||
{
|
||||
return $this->last_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing the HTTP headers and the body of the API request.
|
||||
* @return array Assoc array
|
||||
*/
|
||||
public function getLastRequest()
|
||||
{
|
||||
return $this->last_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP DELETE request - for deleting data
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (if any)
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function delete($method, $args = [])
|
||||
{
|
||||
return $this->makeRequest('delete', $method, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP GET request - for retrieving data
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function get($method, $args = [])
|
||||
{
|
||||
return $this->makeRequest('get', $method, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP PATCH request - for performing partial updates
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function patch($method, $args = [])
|
||||
{
|
||||
return $this->makeRequest('patch', $method, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP POST request - for creating and updating items
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function post($method, $args = [])
|
||||
{
|
||||
return $this->makeRequest('post', $method, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP PUT request - for creating new items
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function put($method, $args = [])
|
||||
{
|
||||
return $this->makeRequest('put', $method, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the underlying HTTP request. Not very exciting.
|
||||
* @param string $http_verb The HTTP verb to use: get, post, put, patch, delete
|
||||
* @param string $method The API method to be called
|
||||
* @param array $args Assoc array of parameters to be passed
|
||||
* @return array|false Assoc array of decoded result
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function makeRequest($http_verb, $method, $args = [])
|
||||
{
|
||||
$url = $this->endpoint;
|
||||
|
||||
if (!empty($method) && !is_null($method) && strpos($url, '?') === false)
|
||||
{
|
||||
$url .= '/' . $method;
|
||||
}
|
||||
|
||||
$this->last_error = '';
|
||||
$this->request_successful = false;
|
||||
$this->last_response = [];
|
||||
$this->last_request = [
|
||||
'method' => $http_verb,
|
||||
'path' => $method,
|
||||
'url' => $url,
|
||||
'body' => '',
|
||||
'timeout' => $this->timeout,
|
||||
];
|
||||
|
||||
$http = HttpFactory::getHttp($this->options);
|
||||
|
||||
switch ($http_verb)
|
||||
{
|
||||
case 'post':
|
||||
$this->attachRequestPayload($args);
|
||||
$response = $http->post($url, $this->last_request['body']);
|
||||
break;
|
||||
|
||||
case 'get':
|
||||
$query = http_build_query($args, '', '&');
|
||||
$this->last_request['body'] = $query;
|
||||
$response = (strpos($url,'?') !== false) ? $http->get($url . '&' . $query) : $http->get($url . '?' . $query);
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
$response = $http->delete($url);
|
||||
break;
|
||||
|
||||
case 'patch':
|
||||
$this->attachRequestPayload($args);
|
||||
$response = $http->patch($url, $this->last_request['body']);
|
||||
break;
|
||||
|
||||
case 'put':
|
||||
$this->attachRequestPayload($args);
|
||||
$response = $http->put($url, $this->last_request['body']);
|
||||
break;
|
||||
}
|
||||
|
||||
// Do not touch directly the $response object to prevent the PHP 8.2 "Creation of dynamic property" deprecation notice.
|
||||
$this->last_response = (object) [
|
||||
'body' => $this->convertResponse($response->body),
|
||||
'headers' => $response->headers,
|
||||
'code' => $response->code
|
||||
];
|
||||
|
||||
$this->determineSuccess();
|
||||
|
||||
return $this->last_response->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the data and attach it to the request
|
||||
* @param array $data Assoc array of data to attach
|
||||
*/
|
||||
protected function attachRequestPayload($data)
|
||||
{
|
||||
if (!$this->encode)
|
||||
{
|
||||
$this->last_request['body'] = http_build_query($data);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->last_request['body'] = json_encode($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
protected function determineSuccess()
|
||||
{
|
||||
$status = $this->last_response->code;
|
||||
$success = ($status >= 200 && $status <= 299) ? true : false;
|
||||
|
||||
return ($this->request_successful = $success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the HTTP Call response to a traversable type
|
||||
*
|
||||
* @param json|xml $response
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
protected function convertResponse($response)
|
||||
{
|
||||
switch ($this->response_type)
|
||||
{
|
||||
case 'json':
|
||||
return json_decode($response, true);
|
||||
case 'xml':
|
||||
return new \SimpleXMLElement($response);
|
||||
case 'text':
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Custom Fields declared by the user for a specific custom field. If exists return its value.
|
||||
*
|
||||
* @param array $needles The custom field names
|
||||
* @param array $haystack The custom fields array
|
||||
*
|
||||
* @return string The value of the custom field or an empty string if not found
|
||||
*/
|
||||
protected function getCustomFieldValue($needles, $haystack)
|
||||
{
|
||||
$needles = is_array($needles) ? $needles : (array) $needles;
|
||||
$haystack = array_change_key_case($haystack);
|
||||
|
||||
$found = '';
|
||||
|
||||
foreach ($needles as $needle)
|
||||
{
|
||||
$needle = strtolower($needle);
|
||||
|
||||
if (array_key_exists($needle, $haystack))
|
||||
{
|
||||
$found = is_string($haystack[$needle]) ? trim($haystack[$needle]) : $haystack[$needle];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set encode
|
||||
*
|
||||
* @param boolean $encode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setEncode($encode)
|
||||
{
|
||||
$this->encode = $encode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,511 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
use NRFramework\Functions;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class MailChimp extends Integration
|
||||
{
|
||||
/**
|
||||
* MailChimp Endpoint URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint = 'https://<dc>.api.mailchimp.com/3.0';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->setKey($options);
|
||||
|
||||
if (strpos($this->key, '-') === false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
list(, $data_center) = explode('-', $this->key);
|
||||
$this->endpoint = str_replace('<dc>', $data_center, $this->endpoint);
|
||||
|
||||
$this->options->set('headers.Authorization', 'apikey ' . $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to MailChimp
|
||||
*
|
||||
* @param string $list_id The ID of the MailChimp list
|
||||
* @param string $email The email address of the subscriber
|
||||
* @param object $merge_fields The custom field that are associated with the subscriber where the keys are the merge tags.
|
||||
* @param boolean $double_optin If true, the subscriber will be added with status "pending" and a confirmation email will be sent to the user.
|
||||
* @param boolean $allow_update If true, the subscriber will be updated if it already exists. Otherwise, an error will be thrown.
|
||||
* @param array $tags The tags that are associated with the subscriber.
|
||||
* @param string $tags_replace Determines what changes to make to the subscriber's tags. Values: add_only, replace_all
|
||||
* @param array $interests The interests that are associated with the subscriber.
|
||||
* @param string $interests_replace Determines what changes to make to the subscriber's groups/interests. Values: add_only, replace_all
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribeV2($list_id, $email, $merge_fields = null, $double_optin = true, $allow_update = true, $tags = null, $tags_replace = 'add_only', $interests = [], $interests_replace = 'add_only')
|
||||
{
|
||||
$data = [
|
||||
'email_address' => $email,
|
||||
'status' => $double_optin ? 'pending' : 'subscribed',
|
||||
'merge_fields' => (object) $merge_fields,
|
||||
'tags' => Functions::cleanArray($tags)
|
||||
];
|
||||
|
||||
$member = $this->getMemberByEmail($list_id, $email);
|
||||
|
||||
// Prepare Interests
|
||||
$interests = Functions::cleanArray($interests);
|
||||
$interests = $interests ? array_fill_keys($interests, true) : [];
|
||||
|
||||
if ($member && isset($member['interests']) && $interests_replace == 'replace_all')
|
||||
{
|
||||
// Disable all existing groups
|
||||
$memberInterests = array_fill_keys(array_keys($member['interests']), false);
|
||||
|
||||
// Merge new interests with existing interests
|
||||
$interests = array_merge($memberInterests, $interests);
|
||||
}
|
||||
|
||||
$data['interests'] = (object) $interests;
|
||||
|
||||
if (!$member)
|
||||
{
|
||||
// API Doc: https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
|
||||
$this->post('lists/' . $list_id . '/members', $data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Member exists
|
||||
// Since member exists and we don't allow updating existing member, throw an error.
|
||||
if (!$allow_update)
|
||||
{
|
||||
throw new \Exception('Member already exists');
|
||||
}
|
||||
|
||||
// Skip double opt-in if the existing member is already confirmed
|
||||
if (isset($member['status']) && $member['status'] == 'subscribed')
|
||||
{
|
||||
$data['status'] = $member['status'];
|
||||
}
|
||||
|
||||
// Update existing member
|
||||
// API Doc: https://mailchimp.com/developer/marketing/api/list-members/add-or-update-list-member
|
||||
$this->put('lists/' . $list_id . '/members/' . $member['id'], $data);
|
||||
|
||||
// Remove existing member tags not included in the given Tags.
|
||||
if ($member['tags'] && $tags_replace == 'replace_all')
|
||||
{
|
||||
$currentTags = array_map(function($item) { return $item['name']; }, $member['tags']);
|
||||
|
||||
if ($removeTags = array_diff($currentTags, $data['tags']))
|
||||
{
|
||||
$rTags = [];
|
||||
|
||||
foreach ($removeTags as $removeTag)
|
||||
{
|
||||
$rTags[] = [
|
||||
'name' => $removeTag,
|
||||
'status' => 'inactive'
|
||||
];
|
||||
}
|
||||
|
||||
// API Doc: https://mailchimp.com/developer/marketing/api/list-member-tags/add-or-remove-member-tags/
|
||||
$this->post('lists/' . $list_id . '/members/' . $member['id'] . '/tags', ['tags' => $rTags]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to MailChimp
|
||||
*
|
||||
* API References:
|
||||
* https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-put_lists_list_id_members_subscriber_hash
|
||||
* https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $list The MailChimp list unique ID
|
||||
* @param Object $merge_fields Merge Fields
|
||||
* @param boolean $update_existing Update existing user
|
||||
* @param boolean $double_optin Send MailChimp confirmation email?
|
||||
*
|
||||
* @deprecated Use subscribeV2()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $list, $merge_fields = array(), $update_existing = true, $double_optin = false)
|
||||
{
|
||||
$data = array(
|
||||
'email_address' => $email,
|
||||
'status' => $double_optin ? 'pending' : 'subscribed'
|
||||
);
|
||||
|
||||
// add support for tags
|
||||
if ($tags = $this->getTags($merge_fields))
|
||||
{
|
||||
$data['tags'] = $tags;
|
||||
}
|
||||
|
||||
if (is_array($merge_fields) && count($merge_fields))
|
||||
{
|
||||
foreach ($merge_fields as $merge_field_key => $merge_field_value)
|
||||
{
|
||||
$value = is_array($merge_field_value) ? implode(',', $merge_field_value) : (string) $merge_field_value;
|
||||
$data['merge_fields'][$merge_field_key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$interests = $this->validateInterestCategories($list, $merge_fields);
|
||||
|
||||
if (!empty($interests))
|
||||
{
|
||||
$data = array_merge($data, array('interests' => $interests));
|
||||
}
|
||||
|
||||
if ($update_existing)
|
||||
{
|
||||
// Get subscriber information.
|
||||
$subscriberHash = md5(strtolower($email));
|
||||
$member = $this->get('lists/' . $list . '/members/' . $subscriberHash);
|
||||
|
||||
// Skip double opt-in if the subscriber exists and it's confirmed
|
||||
if (isset($member['status']) && $member['status'] == 'subscribed')
|
||||
{
|
||||
$data['status'] = $member['status'];
|
||||
}
|
||||
|
||||
$this->put('lists/' . $list . '/members/' . $subscriberHash, $data);
|
||||
|
||||
if ($tags)
|
||||
{
|
||||
$tags_ = [];
|
||||
|
||||
foreach ($tags as $tag)
|
||||
{
|
||||
$tags_[] = [
|
||||
'name' => $tag,
|
||||
'status' => 'active'
|
||||
];
|
||||
}
|
||||
|
||||
$currentTags = $this->getMemberTags($list, $subscriberHash);
|
||||
|
||||
if ($removeTags = array_diff($currentTags, $tags))
|
||||
{
|
||||
foreach ($removeTags as $removeTag)
|
||||
{
|
||||
$tags_[] = [
|
||||
'name' => $removeTag,
|
||||
'status' => 'inactive'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->post('lists/' . $list . '/members/' . $subscriberHash . '/tags', ['tags' => $tags_]);
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
$this->post('lists/' . $list . '/members', $data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use subscribeV2()
|
||||
*/
|
||||
private function getMemberTags($list, $subscriberHash)
|
||||
{
|
||||
$tags = $this->get('lists/' . $list . '/members/' . $subscriberHash . '/tags');
|
||||
|
||||
$return = [];
|
||||
|
||||
if (isset($tags['tags']))
|
||||
{
|
||||
foreach ($tags['tags'] as $tag)
|
||||
{
|
||||
$return[] = $tag['name'];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and return all unique tags
|
||||
*
|
||||
* @param array $merge_fields
|
||||
*
|
||||
* @deprecated use subscribeV2()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTags($merge_fields)
|
||||
{
|
||||
$tags = [];
|
||||
|
||||
// ensure tags are added in the form
|
||||
if (!isset($merge_fields['tags']))
|
||||
{
|
||||
return $tags;
|
||||
}
|
||||
|
||||
$mergeFieldsTags = $merge_fields['tags'];
|
||||
|
||||
// make string array
|
||||
if (is_string($mergeFieldsTags))
|
||||
{
|
||||
$tags = explode(',', $mergeFieldsTags);
|
||||
}
|
||||
|
||||
// ensure we have array to manipulate
|
||||
if (is_array($mergeFieldsTags) || is_object($mergeFieldsTags))
|
||||
{
|
||||
$tags = (array) $mergeFieldsTags;
|
||||
}
|
||||
|
||||
// remove empty values, keep uniques and reset keys
|
||||
$tags = array_filter($tags);
|
||||
$tags = array_unique($tags);
|
||||
$tags = array_values($tags);
|
||||
$tags = array_map('trim', $tags);
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available MailChimp lists
|
||||
*
|
||||
* https://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = $this->get('/lists');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($data['lists']) || !is_array($data['lists']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = [];
|
||||
|
||||
foreach ($data['lists'] as $key => $list)
|
||||
{
|
||||
$lists[] = array(
|
||||
'id' => $list['id'],
|
||||
'name' => $list['name']
|
||||
);
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Interest Categories from MailChimp
|
||||
*
|
||||
* @param string $listID The List ID
|
||||
*
|
||||
* @deprecated Use subscribeV2()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInterestCategories($listID)
|
||||
{
|
||||
if (!$listID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->get('/lists/' . $listID . '/interest-categories');
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($data['total_items']) && $data['total_items'] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return $data['categories'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the values accepted for the particular Interest Category
|
||||
*
|
||||
* @param string $listID The List ID
|
||||
* @param string $interestCategoryID The Interest Category ID
|
||||
*
|
||||
* @deprecated Use subscribeV2()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInterestCategoryValues($listID, $interestCategoryID)
|
||||
{
|
||||
if (!$interestCategoryID || !$listID)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = $this->get('/lists/' . $listID . '/interest-categories/' . $interestCategoryID . '/interests');
|
||||
|
||||
if (isset($data['total_items']) && $data['total_items'] == 0)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return $data['interests'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the interests categories through the form fields
|
||||
* and constructs the interests array for the subscribe method
|
||||
*
|
||||
* @param string $listID The List ID
|
||||
* @param array $params The Form fields
|
||||
*
|
||||
* @deprecated Use subscribeV2()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateInterestCategories($listID, $params)
|
||||
{
|
||||
if (!$params || !$listID)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$interestCategories = $this->getInterestCategories($listID);
|
||||
|
||||
if (!$interestCategories)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$categories = array();
|
||||
|
||||
foreach ($interestCategories as $category)
|
||||
{
|
||||
if (array_key_exists($category['title'], $params))
|
||||
{
|
||||
$categories[] = array('id' => $category['id'], 'title' => $category['title']);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($categories))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$interests = array();
|
||||
|
||||
foreach ($categories as $category)
|
||||
{
|
||||
$data = $this->getInterestCategoryValues($listID, $category['id']);
|
||||
|
||||
if (isset($data['total_items']) && $data['total_items'] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($data as $interest)
|
||||
{
|
||||
if (in_array($interest['name'], (array) $params[$category['title']]))
|
||||
{
|
||||
$interests[$interest['id']] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$interests[$interest['id']] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $interests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a subscriber in a list by email address
|
||||
*
|
||||
* @param string $list_id The MailChimp list ID
|
||||
* @param string $email The email address
|
||||
*
|
||||
* @return mixed Object on success, false on failure
|
||||
*/
|
||||
public function getMemberByEmail($list_id, $email)
|
||||
{
|
||||
$subscriberHash = md5(strtolower($email));
|
||||
$result = $this->get('lists/' . $list_id . '/members/' . $subscriberHash);
|
||||
|
||||
return $this->success() ? $result : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (isset($body['errors']))
|
||||
{
|
||||
$error = $body['errors'][0];
|
||||
return $error['field'] . ': ' . $error['message'];
|
||||
}
|
||||
|
||||
if (isset($body['detail']))
|
||||
{
|
||||
return $body['detail'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The get() method overridden so that it handles
|
||||
* the default item paging of MailChimp which is 10
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function get($method, $args = array())
|
||||
{
|
||||
$data = $this->makeRequest('get', $method, $args);
|
||||
|
||||
if ($data && isset($data['total_items']) && (int) $data['total_items'] > 10)
|
||||
{
|
||||
$args['count'] = $data['total_items'];
|
||||
return $this->makeRequest('get', $method, $args);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class MailerLite extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options);
|
||||
$this->setEndpoint('https://connect.mailerlite.com/api');
|
||||
$this->options->set('headers.Authorization', 'Bearer ' . $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes a user to a MailerLite Account
|
||||
*
|
||||
* API Reference v3:
|
||||
* https://developers.mailerlite.com/docs/subscribers.html#create-upsert-subscriber
|
||||
*
|
||||
* @param string $email The user's email
|
||||
* @param array $fields All the custom fields
|
||||
* @param string $groupIds The Group IDs
|
||||
* @param string $subscriber_status The subscriber status (active, unsubscribed, unconfirmed, bounced, junk)
|
||||
* @param boolean $update_existing Whether to update the existing contact (Only in v3)
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function subscribe($email, $fields, $groupIds = [], $subscriber_status = '', $update_existing = true)
|
||||
{
|
||||
// Abort if we don't want to update existing subscribers and the subscriber already exists
|
||||
if (!$update_existing && $this->subscriberExists($email))
|
||||
{
|
||||
throw new \Exception(Text::_('NR_YOU_ARE_ALREADY_A_SUBSCRIBER'), 1);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'email' => $email,
|
||||
'fields' => $fields
|
||||
];
|
||||
|
||||
if ($subscriber_status)
|
||||
{
|
||||
$data['status'] = $subscriber_status;
|
||||
}
|
||||
|
||||
if ($groupIds)
|
||||
{
|
||||
$data['groups'] = $groupIds;
|
||||
}
|
||||
|
||||
$this->post('subscribers', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a subscriber exists
|
||||
*
|
||||
* @param string $email The subscriber's email
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function subscriberExists($email = '')
|
||||
{
|
||||
if (!$email)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = $this->get('subscribers/' . $email);
|
||||
|
||||
return isset($response['data']['email']) && $response['data']['email'] == $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all groups
|
||||
*
|
||||
* API Reference v3:
|
||||
* https://developers.mailerlite.com/docs/groups.html#list-all-groups
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroups()
|
||||
{
|
||||
$data = [
|
||||
'offset' => 0,
|
||||
'limit' => 50
|
||||
];
|
||||
|
||||
$lists = [];
|
||||
|
||||
$data = $this->get('groups', $data);
|
||||
|
||||
// sanity check
|
||||
if (!isset($data['data']) || !is_array($data['data']))
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data['data'] as $key => $list)
|
||||
{
|
||||
$lists[] = [
|
||||
'id' => $list['id'],
|
||||
'name' => $list['name']
|
||||
];
|
||||
}
|
||||
|
||||
return $lists;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* API Reference:
|
||||
* https://developers.mailerlite.com/docs/#validation-errors
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
return isset($body['message']) ? $body['message'] : 'An error has occurred.';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class Notion extends Integration
|
||||
{
|
||||
protected $endpoint = 'https://api.notion.com/v1';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->setKey($options);
|
||||
|
||||
$this->options->set('headers.Authorization', 'Bearer ' . $this->key);
|
||||
$this->options->set('headers.Notion-Version', '2022-06-28');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* The reCAPTCHA Wrapper
|
||||
*/
|
||||
class ReCaptcha extends Integration
|
||||
{
|
||||
/**
|
||||
* Service Endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!array_key_exists('secret', $options))
|
||||
{
|
||||
$this->setError('NR_RECAPTCHA_INVALID_SECRET_KEY');
|
||||
throw new \Exception($this->getLastError());
|
||||
}
|
||||
|
||||
$this->setKey($options['secret']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the reCAPTCHA siteverify API to verify whether the user passes reCAPTCHA test.
|
||||
*
|
||||
* @param string $response Response string from recaptcha verification.
|
||||
* @param string $remoteip IP address of end user
|
||||
*
|
||||
* @return bool Returns true if the user passes reCAPTCHA test
|
||||
*/
|
||||
public function validate($response, $remoteip = null)
|
||||
{
|
||||
if (empty($response) || is_null($response))
|
||||
{
|
||||
return $this->setError('NR_RECAPTCHA_PLEASE_VALIDATE');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'secret' => $this->key,
|
||||
'response' => $response,
|
||||
'remoteip' => $remoteip ?: \NRFramework\User::getIP(),
|
||||
);
|
||||
|
||||
$this->get('', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
protected function determineSuccess()
|
||||
{
|
||||
$success = parent::determineSuccess();
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if ($body['success'] == false && array_key_exists('error-codes', $body) && count($body['error-codes']) > 0)
|
||||
{
|
||||
$success = $this->setError(implode(', ', $body['error-codes']));
|
||||
}
|
||||
|
||||
return ($this->request_successful = $success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set wrapper error text
|
||||
*
|
||||
* @param String $error The error message to display
|
||||
*/
|
||||
private function setError($error)
|
||||
{
|
||||
$this->last_error = Text::_('NR_RECAPTCHA') . ': ' . Text::_($error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class SalesForce extends Integration
|
||||
{
|
||||
/**
|
||||
* Service API Endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint = 'https://{{ENV}}.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8';
|
||||
|
||||
/**
|
||||
* Encode data before sending the request
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $encode = false;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->setKey($options);
|
||||
$this->prepareEndpoint($options);
|
||||
|
||||
$this->options->set('headers.Content-Type', 'application/x-www-form-urlencoded');
|
||||
}
|
||||
|
||||
private function prepareEndpoint($options = [])
|
||||
{
|
||||
if (isset($options['test_mode']) && $options['test_mode'])
|
||||
{
|
||||
$this->setEndpoint(str_replace('{{ENV}}', 'test', $this->endpoint));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->setEndpoint(str_replace('{{ENV}}', 'webto', $this->endpoint));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to SalesForce
|
||||
*
|
||||
* API References:
|
||||
* https://developer.salesforce.com/page/Wordpress-to-lead
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param array $params All the form fields
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $params)
|
||||
{
|
||||
$data = array(
|
||||
"email" => $email,
|
||||
"oid" => $this->key
|
||||
);
|
||||
|
||||
if (is_array($params) && count($params))
|
||||
{
|
||||
$data = array_merge($data, $params);
|
||||
}
|
||||
|
||||
$this->post('', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the Lead has been stored successfully in SalesForce
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function determineSuccess()
|
||||
{
|
||||
$status = $this->last_response->code;
|
||||
|
||||
if ($status < 200 && $status > 299)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$headers = $this->last_response->headers;
|
||||
|
||||
if (isset($headers['Is-Processed']) && (strpos($headers['Is-Processed'], 'Exception') !== false))
|
||||
{
|
||||
$this->last_error = Text::_('NR_SALESFORCE_ERROR');
|
||||
return false;
|
||||
}
|
||||
|
||||
return ($this->request_successful = true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class SendInBlue extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options['api']);
|
||||
$this->setEndpoint('https://api.sendinblue.com/v2.0');
|
||||
$this->options->set('headers.api-key', $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes a user to a SendinBlue Account
|
||||
*
|
||||
* API Reference:
|
||||
* https://apidocs.sendinblue.com/user/#1
|
||||
*
|
||||
* @param string $email The user's email
|
||||
* @param array $params All the form fields
|
||||
* @param string $listid The List ID
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function subscribe($email, $params, $listid = false)
|
||||
{
|
||||
$data = array(
|
||||
'email' => $email,
|
||||
'attributes' => $params,
|
||||
);
|
||||
|
||||
if ($listid)
|
||||
{
|
||||
$data['listid'] = array($listid);
|
||||
}
|
||||
|
||||
$this->post('user/createdituser', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Campaign lists
|
||||
*
|
||||
* https://apidocs.sendinblue.com/list/#1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = array(
|
||||
'page' => 1,
|
||||
'page_limit' => 50
|
||||
);
|
||||
|
||||
$lists = array();
|
||||
|
||||
$data = $this->get('/list', $data);
|
||||
|
||||
if (!isset($data['data']['lists']) || !is_array($data['data']['lists']) || $data['data']['total_list_records'] == 0)
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data['data']['lists'] as $key => $list)
|
||||
{
|
||||
$lists[] = array(
|
||||
'id' => $list['id'],
|
||||
'name' => $list['name']
|
||||
);
|
||||
}
|
||||
|
||||
return $lists;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* API Reference:
|
||||
* https://apidocs.sendinblue.com/response/
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
$message = '';
|
||||
|
||||
if (isset($body['code']) && ($body['code'] == 'failure'))
|
||||
{
|
||||
$message = $body['message'];
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class SendInBlue3 extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options['api']);
|
||||
$this->setEndpoint('https://api.sendinblue.com/v3');
|
||||
$this->options->set('headers.api-key', $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes a user to a SendinBlue Account
|
||||
*
|
||||
* API Reference v3:
|
||||
* https://developers.sendinblue.com/reference#createcontact
|
||||
*
|
||||
* @param string $email The user's email
|
||||
* @param array $params All the form fields
|
||||
* @param string $listid The List ID
|
||||
* @param boolean $update_existing Whether to update the existing contact (Only in v3)
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function subscribe($email, $params, $listid = false, $update_existing = true)
|
||||
{
|
||||
$data = [
|
||||
'email' => $email,
|
||||
'attributes' => (object) $params,
|
||||
'updateEnabled' => $update_existing
|
||||
];
|
||||
|
||||
if ($listid)
|
||||
{
|
||||
$data['listIds'] = [(int) $listid];
|
||||
}
|
||||
|
||||
$this->post('contacts', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Campaign lists
|
||||
*
|
||||
* API Reference v3:
|
||||
* https://developers.sendinblue.com/reference#getlists-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
$data = [
|
||||
'page' => 1,
|
||||
'page_limit' => 50
|
||||
];
|
||||
|
||||
$lists = [];
|
||||
|
||||
$data = $this->get('contacts/lists', $data);
|
||||
|
||||
// sanity check
|
||||
if (!isset($data['lists']) || !is_array($data['lists']) || $data['count'] == 0)
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data['lists'] as $key => $list)
|
||||
{
|
||||
$lists[] = [
|
||||
'id' => $list['id'],
|
||||
'name' => $list['name']
|
||||
];
|
||||
}
|
||||
|
||||
return $lists;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* API Reference:
|
||||
* https://developers.sendinblue.com/docs/how-it-works#error-codes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
$message = '';
|
||||
|
||||
if (!isset($body['code']))
|
||||
{
|
||||
return $message;
|
||||
}
|
||||
|
||||
return $body['message'];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class Turnstile extends Integration
|
||||
{
|
||||
/**
|
||||
* Service Endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!array_key_exists('secret', $options))
|
||||
{
|
||||
$this->setError('NR_RECAPTCHA_INVALID_SECRET_KEY');
|
||||
throw new \Exception($this->getLastError());
|
||||
}
|
||||
|
||||
$this->setKey($options['secret']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the Cloudflare Turnstile siteverify API to verify whether the user passes the test.
|
||||
*
|
||||
* @param string $response Response string from Cloudflare Turnstile verification.
|
||||
* @param string $remoteip IP address of end user
|
||||
*
|
||||
* @return bool Returns true if the user passes the test
|
||||
*/
|
||||
public function validate($response, $remoteip = null)
|
||||
{
|
||||
if (empty($response) || is_null($response))
|
||||
{
|
||||
return $this->setError('NR_RECAPTCHA_PLEASE_VALIDATE');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'secret' => $this->key,
|
||||
'response' => $response,
|
||||
];
|
||||
|
||||
$this->post('', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
protected function determineSuccess()
|
||||
{
|
||||
$success = parent::determineSuccess();
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if ($body['success'] == false && array_key_exists('error-codes', $body) && count($body['error-codes']) > 0)
|
||||
{
|
||||
$success = $this->setError(implode(', ', $body['error-codes']));
|
||||
}
|
||||
|
||||
return ($this->request_successful = $success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set wrapper error text
|
||||
*
|
||||
* @param String $error The error message to display
|
||||
*/
|
||||
private function setError($error)
|
||||
{
|
||||
$this->last_error = Text::_('NR_TURNSTILE') . ': ' . Text::_($error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
169
plugins/system/nrframework/NRFramework/Integrations/Zoho.php
Normal file
169
plugins/system/nrframework/NRFramework/Integrations/Zoho.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class Zoho extends Integration
|
||||
{
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options['api']);
|
||||
$this->endpoint = 'https://campaigns.zoho.com/api';
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to ZoHo
|
||||
*
|
||||
* https://www.zoho.com/campaigns/help/api/contact-subscribe.html
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param string $list The ZoHo list unique ID
|
||||
* @param Object $customFields Collection of custom fields
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $list, $customFields = array())
|
||||
{
|
||||
|
||||
$contactinfo = json_encode(array_merge(array("Contact Email" => $email), $customFields));
|
||||
|
||||
$data = array(
|
||||
"authtoken" => $this->key,
|
||||
"scope" => "CampaignsAPI",
|
||||
"version" => "1",
|
||||
"resfmt" => "JSON",
|
||||
"listkey" => $list,
|
||||
"contactinfo" => $contactinfo
|
||||
);
|
||||
|
||||
$this->get('json/listsubscribe', $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available ZoHo lists
|
||||
*
|
||||
* https://www.zoho.com/campaigns/help/api/get-mailing-lists.html
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
if (!$this->key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'authtoken' => $this->key,
|
||||
'scope' => 'CampaignsAPI',
|
||||
'sort' => 'asc',
|
||||
'resfmt' => 'JSON',
|
||||
'range' => '1000' //ambiguously large range of total results to overwrite the default range which is 20
|
||||
);
|
||||
|
||||
$data = $this->get("getmailinglists", $data);
|
||||
|
||||
if (!$this->success())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$lists = array();
|
||||
|
||||
if (!isset($data["list_of_details"]) || !is_array($data["list_of_details"]))
|
||||
{
|
||||
return $lists;
|
||||
}
|
||||
|
||||
foreach ($data["list_of_details"] as $key => $list)
|
||||
{
|
||||
$lists[] = array(
|
||||
"id" => $list["listkey"],
|
||||
"name" => $list["listname"]
|
||||
);
|
||||
}
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (isset($body['message']))
|
||||
{
|
||||
return $body['message'];
|
||||
}
|
||||
|
||||
return 'An unspecified error occured';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
protected function determineSuccess()
|
||||
{
|
||||
$status = $this->findHTTPStatus();
|
||||
|
||||
// check if the status is equal to the arbitrary success codes of ZoHo
|
||||
if (in_array($status, array(0, 200, 6101, 6201)))
|
||||
{
|
||||
return ($this->request_successful = true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the HTTP status code from the headers or API response body
|
||||
*
|
||||
* @return int HTTP status code
|
||||
*/
|
||||
protected function findHTTPStatus()
|
||||
{
|
||||
$status = $this->last_response->code;
|
||||
$success = ($status >= 200 && $status <= 299) ? true : false;
|
||||
|
||||
if (!$success)
|
||||
{
|
||||
return 418;
|
||||
}
|
||||
|
||||
// ZoHo sometimes uses "Code" instead of "code"
|
||||
// also they don't use HTTP status codes
|
||||
// instead they store their own status code inside the response body
|
||||
$data = array_change_key_case($this->last_response->body);
|
||||
|
||||
if (isset($data['code']))
|
||||
{
|
||||
return (int) $data['code'];
|
||||
}
|
||||
|
||||
return 418;
|
||||
}
|
||||
}
|
||||
156
plugins/system/nrframework/NRFramework/Integrations/ZohoCRM.php
Normal file
156
plugins/system/nrframework/NRFramework/Integrations/ZohoCRM.php
Normal file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Integrations;
|
||||
|
||||
// No direct access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class ZohoCRM extends Integration
|
||||
{
|
||||
/**
|
||||
* Response Type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $response_type = 'xml';
|
||||
|
||||
/**
|
||||
* Data Center API Endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $datacenter = 'crm.zoho.com';
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param array $options The service's required options
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setKey($options['authenticationToken']);
|
||||
|
||||
if (isset($options['datacenter']) && !is_null($options['datacenter']) && !empty($options['datacenter']))
|
||||
{
|
||||
$this->datacenter = $options['datacenter'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe user to ZohoCRM
|
||||
*
|
||||
* https://www.zoho.eu/crm/help/api/insertrecords.html#Insert_records_into_Zoho_CRM_from_third-party_applications
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param array $fields Available form fields
|
||||
* @param string $module Zoho module to be used
|
||||
* @param boolean $update_existing Update existing users
|
||||
* @param string $workflow Trigger the workflow rule while inserting record
|
||||
* @param string $approve Approve records (Supports: Leads, Contacts, and Cases modules)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subscribe($email, $fields, $module = 'leads', $update_existing = true, $workflow = false, $approve = false)
|
||||
{
|
||||
$data = array(
|
||||
'authtoken' => $this->key,
|
||||
'scope' => 'crmapi',
|
||||
'xmlData' => $this->buildModuleXML($email, $fields, $module),
|
||||
'duplicateCheck' => $update_existing ? '2' : '1',
|
||||
'wfTrigger' => $workflow ? 'true' : 'false',
|
||||
'isApproval' => $approve ? 'true' : 'false',
|
||||
'version' => '4'
|
||||
);
|
||||
|
||||
$this->endpoint = 'https://' . $this->datacenter . '/crm/private/xml/' . ucfirst($module) . '/insertRecords?' . http_build_query($data);
|
||||
|
||||
$this->post('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the XML for each module
|
||||
*
|
||||
* @param string $email User's email address
|
||||
* @param array $fields Form fields
|
||||
* @param string $module Module to be used
|
||||
*
|
||||
* @return string The XML
|
||||
*/
|
||||
private function buildModuleXML($email, $fields, $module)
|
||||
{
|
||||
$xml = new SimpleXMLElement('<' . ucfirst($module) . '/>');
|
||||
$row = $xml->addChild('row');
|
||||
$row->addAttribute('no', '1');
|
||||
|
||||
$xmlField = $row->addChild('FL', $email);
|
||||
$xmlField->addAttribute('val', 'Email');
|
||||
|
||||
if (is_array($fields) && count($fields))
|
||||
{
|
||||
foreach ($fields as $field_key => $field_value)
|
||||
{
|
||||
$field_value = is_array($field_value) ? implode(',', $field_value) : $field_value;
|
||||
|
||||
$xmlField = $row->addChild('FL', $field_value);
|
||||
$xmlField->addAttribute('val', $field_key);
|
||||
}
|
||||
}
|
||||
|
||||
return $xml->asXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (isset($body->error))
|
||||
{
|
||||
return $body->error->message;
|
||||
}
|
||||
|
||||
if (isset($body->result->row->error))
|
||||
{
|
||||
return $body->result->row->error->details;
|
||||
}
|
||||
|
||||
return 'Unknown error';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
public function determineSuccess()
|
||||
{
|
||||
$status = $this->last_response->code;
|
||||
$success = ($status >= 200 && $status <= 299) ? true : false;
|
||||
|
||||
if (!$success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = $this->last_response->body;
|
||||
|
||||
if (!isset($body->result->row->success))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ($this->request_successful = true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user